<?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>Forem: Gary Kramlich</title>
    <description>The latest articles on Forem by Gary Kramlich (@grim).</description>
    <link>https://forem.com/grim</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%2F1062682%2F1a1cda6d-ce17-4cd4-93ec-fdd50e8f55a6.png</url>
      <title>Forem: Gary Kramlich</title>
      <link>https://forem.com/grim</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/grim"/>
    <language>en</language>
    <item>
      <title>Right to be Forgotten and Open Source</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Sat, 25 Jan 2025 01:05:17 +0000</pubDate>
      <link>https://forem.com/grim/right-to-be-forgotten-and-open-source-5873</link>
      <guid>https://forem.com/grim/right-to-be-forgotten-and-open-source-5873</guid>
      <description>&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Right_to_be_forgotten" rel="noopener noreferrer"&gt;Right to be Forgotten&lt;/a&gt; is giving people the right to have their information removed from the internet. On the surface this is a great thing and I'm a big supporter of it. However, when it comes to Open Source projects, things can get messy very quickly.&lt;/p&gt;

&lt;p&gt;Many people realize that interacting with an Open Source project means that basically everything is open to the world not just the source code. However, so people don't realize this and hopefully this post will help explain this a bit better.&lt;/p&gt;

&lt;p&gt;When it comes to Right to be Forgotten we only have few places were we have user data as part of us running &lt;a href="https://pidgin.im/" rel="noopener noreferrer"&gt;Pidgin&lt;/a&gt;. These are our mailing list archives which have been replaced by Discourse, our issue tracker, and our old developer &lt;a href="https://simple.wikipedia.org/wiki/Wiki" rel="noopener noreferrer"&gt;WIKI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Open Source mailing lists have historically been archived by the project and other mailing list archives out on the internet. This is done for a number of reasons, but at the core the idea is that there are a lot of discussion and answers to support questions and having them available is acceptable.&lt;/p&gt;

&lt;p&gt;However, people have requested use to forget them in our mailing list archives. There are a few options here to do this randomize their Personally Identifiable Information (PII) or just deleting any emails that mention them.&lt;/p&gt;

&lt;p&gt;The former is a ton of work and at the time of this writing I'm not aware of a tool that does this. The later of course is destructive and depending on how active the requestor was on the mailing list can have a huge impact of the value of the archives. But deleting everything from the user is generally the course that's taken because there's also a possibility they posted PII in the body of their messages which the former wouldn't detect unless it was the email address or whatever.&lt;/p&gt;

&lt;p&gt;But there's a bigger issue here. Remember those other archives out there on the internet, the requestor has to send a request to all of them. As far as I know there's no index of mailing list archives which means deleting one or two doesn't really matter in the grand scheme of things.&lt;/p&gt;

&lt;p&gt;That said, there's another sleeping dragon here. Many people just archive mailing lists in their email accounts. With a few scripts they can extract all the emails from their email account into a format where they can just mirror it on a website adding yet another site that the requestor has to find and request to be forgotten.&lt;/p&gt;

&lt;p&gt;So basically, if you think you might ever want to be forgotten, please stay off of the mailing lists :) I know this is unrealistic, but people need to be made aware of it.&lt;/p&gt;

&lt;p&gt;That said, we have replaced our mailing lists with a Discourse instance at &lt;a href="https://discourse.imfreedom.org/" rel="noopener noreferrer"&gt;discourse.imfreedom.org&lt;/a&gt;. Discourse has an option for users to anonymize themselves which effectively gives them all the power to be forgotten without actually getting the project involved.&lt;/p&gt;

&lt;p&gt;When they anonymize themselves all of their posts stick around but their username and stuff won't have any reference to them. But like email above, if the user put PII in a post it &lt;em&gt;will&lt;/em&gt; remain unless it is manually removed.&lt;/p&gt;

&lt;p&gt;So next up is the issue tracker. Previously we were using &lt;a href="https://trac.edgewall.org/" rel="noopener noreferrer"&gt;Edgewall Trac&lt;/a&gt; for issues and documentation via it's WIKI functionality. We made this read-only years ago because it is abandon-ware now and wasn't scaling to the needs of the project.&lt;/p&gt;

&lt;p&gt;When we did this, we redirected all of the URLs relating to tickets/issues to our new issue tracker. Our new issue tracker is &lt;a href="https://www.jetbrains.com/youtrack/" rel="noopener noreferrer"&gt;JetBrains YouTrack&lt;/a&gt; and similar to Discourse, users can anonymize themselves. Again, this is just account details and does nothing about the contents of posts.&lt;/p&gt;

&lt;p&gt;But more importantly to note, is that when we imported all of the issues into YouTrack we only copied a few developer accounts. We did not copy any user accounts so any a user would be mentioned we instead used a user named &lt;code&gt;Ghost&lt;/code&gt;. This was specifically done to respect people's privacy by not copying their data from one service to another.&lt;/p&gt;

&lt;p&gt;Semi-recently, we even went through and crawled our Trac instance and saved it all to static HTML. What you see today on &lt;a href="https://developer.pidgin.im" rel="noopener noreferrer"&gt;developer.pidgin.im&lt;/a&gt; is the result of that crawl. This means we were able to shut Trac down completely and since Trac and it's backing database are gone, users can't delete their accounts.&lt;/p&gt;

&lt;p&gt;However, there is still the WIKI to worry about and that's actually where the motivation for this whole post came from. But before we get to that, lets discuss what information is stored in the WIKI.&lt;/p&gt;

&lt;p&gt;We are still serving the read-only versions of the WIKI on developer.pidgin.im because we haven't yet migrated them to the new site. We haven't migrated them because we determined that &lt;a href="https://pidgin.im" rel="noopener noreferrer"&gt;pidgin.im&lt;/a&gt; isn't the right place for all this information and that we should create a new &lt;a href="https://developer.pidgin.im" rel="noopener noreferrer"&gt;developer.pidgin.im&lt;/a&gt; but we haven't gotten around to doing it yet.&lt;/p&gt;

&lt;p&gt;So the WIKI can still mention user accounts, their edit history, and all of the edits they made. Now generally speaking the list of contributors here is much smaller than the one creating issues, but it's not zero. Luckily for us so far, no one that has edited the WIKI has requested to be forgotten.&lt;/p&gt;

&lt;p&gt;So back to the impetus of this post.&lt;/p&gt;

&lt;p&gt;we received a right to be forgotten email request to security (at) pidgin.im. It turns out that email address was not configured as we intended, but our provider figured that out and forwarded the email on to me.&lt;/p&gt;

&lt;p&gt;The requestor was aware of our move to YouTrack but apparently did no investigation to whether or not any of their data was on there. I can't fault them too much here as I looked and apparently I never documented anything about the migration to YouTrack.&lt;/p&gt;

&lt;p&gt;So knowing that all of the issues had already been anonymized and that we're redirecting the links from developer.pidgin.im to YouTrack, I knew we were in the clear there. That just left the wiki.&lt;/p&gt;

&lt;p&gt;So I have a copy of the entire static dump we created of developer.pidgin.im. It is 30gb of uncompressed text and 1,142,949 files. It contains everything except the tickets that we redirect away from as I crawled the live site directly which had the redirects in place.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;grim@spectre:~/d/trac-static$ du -sh
30G .
grim@spectre:~/d/trac-static$ find -type f | wc -l
1142949
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So to check the WIKI, I have to &lt;code&gt;grep&lt;/code&gt; through all of it. Even on my beefy machine, this takes a fair amount of time as you can see from the output below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;grim@spectre:~/d/trac-static$ time grep -ri RequestorsUserName * | grep -v 'developer.pidgin.im/query' | grep -v "developer.pidgin.im/timeline" | cut -d: -f1 | sort | uniq -c

real    2m21.859s
user    0m38.984s
sys 0m29.105s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm ignoring the &lt;code&gt;query&lt;/code&gt; and &lt;code&gt;timeline&lt;/code&gt; paths because they're related to tickets and weren't redirected until after I created the dump.&lt;/p&gt;

&lt;p&gt;At any rate, you can see that we did not find any hits for the requestor.&lt;/p&gt;

&lt;p&gt;So while the requestor was able to help us find our misconfigured email address, everything else was left to us to determine if any of their data was even visible publicly.&lt;/p&gt;

&lt;p&gt;Now I completely understand the desire to be forgotten, but Pidgin like most Open Source projects is completely run by volunteers and when you're forcing them to do work when you haven't do any it takes them away from working on the project and that's not good for anyone.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>privacy</category>
      <category>pidgin</category>
    </item>
    <item>
      <title>Code signing HSMs for Pidgin2</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Wed, 22 Jan 2025 07:30:32 +0000</pubDate>
      <link>https://forem.com/grim/code-signing-hsms-for-pidgin2-3ikp</link>
      <guid>https://forem.com/grim/code-signing-hsms-for-pidgin2-3ikp</guid>
      <description>&lt;p&gt;We haven't done a Pidgin 2 release in awhile because aside from other things, I've been unable to sign the Windows binaries.&lt;/p&gt;

&lt;p&gt;I bought a new code signing certificate in March of 2024 and it came on a Hardware Security Module (HSM). This is a USB device you plugin into your machine and it contains a private key that allows you to use it without exposing it. The main issue with the HSM was the complete and utter lack of documentation that came with it. So I messed around with it for awhile, but couldn't figure it out.  We had no pressing reasons to release so it sat.&lt;/p&gt;

&lt;p&gt;In October, rekkanoryo was visiting and with his help we identified that when plugging it in to a Windows host it would show up in the certificate store. We spent a lot of time trying to figure out how to get it to work with &lt;a href="https://github.com/mtrojnar/osslsigncode" rel="noopener noreferrer"&gt;osslsigncode&lt;/a&gt; but apparently we needed to use &lt;code&gt;pkcs11&lt;/code&gt; and neither of us had any experience with that.&lt;/p&gt;

&lt;p&gt;So we ended up trying &lt;code&gt;signtool&lt;/code&gt; from the Windows SDK and were able to get it to sign a Pidgin executable, but only when calling it from &lt;code&gt;command prompt&lt;/code&gt;. We tried integrating it into our build system but we had zero luck.&lt;/p&gt;

&lt;p&gt;Before I go into more depth, lets describe our build system. Our build system on Windows is a collection static &lt;code&gt;Makefile&lt;/code&gt;'s that depends on a POSIX shell like Bash to work properly. As you might have guessed, these &lt;code&gt;Makefile&lt;/code&gt;'s can get pretty complicated. For the shell part, we used to recommend &lt;a href="https://cygwin.com/" rel="noopener noreferrer"&gt;cygwin&lt;/a&gt; but I've been using &lt;a href="https://www.msys2.org/" rel="noopener noreferrer"&gt;Msys2&lt;/a&gt; for awhile now.&lt;/p&gt;

&lt;p&gt;So to make this work, we needed to be able to run &lt;code&gt;signtool&lt;/code&gt; from a shell running under &lt;code&gt;msys2&lt;/code&gt;. However, whenever we'd run the command it would complain that we didn't provide the &lt;code&gt;/fd&lt;/code&gt; argument even though it was for sure there. We ended up trying multiple versions of &lt;code&gt;signtool&lt;/code&gt; as well and still no luck.&lt;/p&gt;

&lt;p&gt;At this point, we started trying to launch a &lt;code&gt;command prompt&lt;/code&gt; process with the command using the &lt;code&gt;/C&lt;/code&gt; flag to run it. But this wasn't running the command and just giving us a prompt. We gave up at this point as we were out of idea.&lt;/p&gt;

&lt;p&gt;So some more time went by and more and more issues started pressing for a Pidgin 2.14.14 release. The certificate prompts, the GCC14 and GCC15 compile errors, as well as the libxml compile errors were all pushing for a new release. So I started looking at this again today (January 21st).&lt;/p&gt;

&lt;p&gt;Everything was fuzzy as it had been 3 full months since we looked at this and rekkanoryo and I both forgot a lot of the finer details of what we attempted. Because of this I started trying to get this working with &lt;code&gt;PKCS11&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;After an hour or two of searching and trying random things I finally learned that the &lt;code&gt;module&lt;/code&gt; piece of &lt;code&gt;PKCS11&lt;/code&gt; is specific to your HSM. So I spent about 30 minutes looking to see if the vendor for my HSM provided one. I didn't find anything. So back to &lt;code&gt;signtool&lt;/code&gt; I went.&lt;/p&gt;

&lt;p&gt;Originally I was testing by modifying our &lt;code&gt;Makefile&lt;/code&gt;'s and waiting for them to get to the failure point and then tinkering from there but that obviously took a lot of time and got old quick.&lt;/p&gt;

&lt;p&gt;So I went back to trying to run the command manually from &lt;code&gt;msys2&lt;/code&gt;. But this was just failure after failure. I then realized I should just try running something like &lt;code&gt;cmd.exe /C /c/Program Files (x86)/.../signtool.exe /?&lt;/code&gt; and see if I could get the usage out of it. But to my surprise I just got a &lt;code&gt;command prompt&lt;/code&gt; in my &lt;code&gt;msys2&lt;/code&gt; Window. So it was clear at that point that that method wasn't going to work no matter how hard I tried.&lt;/p&gt;

&lt;p&gt;That's when I got the idea to just put the command in a batch file and to try running that from &lt;code&gt;msys2&lt;/code&gt;. So I threw the &lt;code&gt;/c/Program Files (x86)/.../signtool.exe /?&lt;/code&gt; into a file named &lt;code&gt;sign.bat&lt;/code&gt; and ran it from &lt;code&gt;msys2&lt;/code&gt; with &lt;code&gt;./sign.bat&lt;/code&gt;. To my great surprise, I got the usage.&lt;/p&gt;

&lt;p&gt;I then updated &lt;code&gt;sign.bat&lt;/code&gt; to include the full command and holy crap it works! We'll almost, I was connected to the machine via RDP and the HSM doesn't work when it detects an RDP session as a security feature. So I quickly ran over to the machine and ran the command again. This time the HSM software popped up asking me for the password to unlock the key. I entered it and SUCCESS!!&lt;/p&gt;

&lt;p&gt;I then went to verify the signature and noticed that it only included a signature with a &lt;code&gt;SHA-384&lt;/code&gt; digest.&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%2F5u3dtjn08zalui3ornzi.jpg" 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%2F5u3dtjn08zalui3ornzi.jpg" alt="A screen shot showing the digital signatures and cert information of the pidgin offline installer" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So this should work fine with with Windows 10 and 11, but we have people running Pidgin 2 on Windows as old as XP (I know..). We need to keep supporting that or they will complain, loudly.&lt;/p&gt;

&lt;p&gt;After some digging through the &lt;code&gt;signtool&lt;/code&gt; documentation, I determined that we can add multiple digests by running &lt;code&gt;signtool&lt;/code&gt; again and pass the &lt;code&gt;/as&lt;/code&gt; argument and a different value for the the &lt;code&gt;/fd&lt;/code&gt; argument.&lt;/p&gt;

&lt;p&gt;So with that done, the signatures look a lot better and we should be able to release now and not break anyone on very old Windows.&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%2Fpzxplow0rlxgwfiikbtz.jpg" 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%2Fpzxplow0rlxgwfiikbtz.jpg" alt="pidgin.exe showing signatures with digest of sha1, sha256, and sha384" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We still would like to have some people test on Windows XP, Vista, 7, and 8, so if you have any of those installed, please let me know so I can get you a file to try it out.&lt;/p&gt;

&lt;p&gt;This has been ton of work, but it's finally done. I wrote a quick &lt;a href="https://discourse.imfreedom.org/t/pidgin-2-signing-with-an-hsm/240/" rel="noopener noreferrer"&gt;post&lt;/a&gt; in our &lt;a href="https://discourse.imfreedom.org/" rel="noopener noreferrer"&gt;discourse&lt;/a&gt; with the actual final setup in the event that they're useful to someone else and so that I have a backup in case I need it.&lt;/p&gt;

&lt;p&gt;I hope you found this story interesting, but I hope to never go through it again :)&lt;/p&gt;

</description>
      <category>pidgin</category>
      <category>opensource</category>
      <category>codesigning</category>
      <category>development</category>
    </item>
    <item>
      <title>Tailscale Kubernetes Operator</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Wed, 14 Aug 2024 19:40:54 +0000</pubDate>
      <link>https://forem.com/grim/tailscale-kubernetes-operator-5c7o</link>
      <guid>https://forem.com/grim/tailscale-kubernetes-operator-5c7o</guid>
      <description>&lt;p&gt;Apologizes to anyone looking for more #Pidgin content. I know it's been awhile and I'll get something out soon I promise, but there are quite a few Pidgin related things in this post too...&lt;/p&gt;

&lt;p&gt;About a month ago I setup a Kubernetes cluster using &lt;a href="https://www.talos.dev/" rel="noopener noreferrer"&gt;Talos&lt;/a&gt; to handle my container load at home.&lt;/p&gt;

&lt;p&gt;I have containers for all sorts of things including the graphs you all may have seen on my &lt;a href="https://twitch.tv/rw_grim" rel="noopener noreferrer"&gt;stream&lt;/a&gt; as well as an &lt;a href="https://ergo.chat/" rel="noopener noreferrer"&gt;Ergo&lt;/a&gt; instance for developing our new &lt;a href="https://ircv3.net" rel="noopener noreferrer"&gt;IRCv3&lt;/a&gt; protocol plugin.&lt;/p&gt;

&lt;p&gt;I'll be adding to this cluster in the future too as we continue development on &lt;a href="https://keep.imfreedom.org/xeme/xeme" rel="noopener noreferrer"&gt;Xeme&lt;/a&gt; which is our new &lt;a href="https://xmpp.org/" rel="noopener noreferrer"&gt;XMPP&lt;/a&gt; library as well as &lt;a href="https://keep.imfreedom.org/myna/myna" rel="noopener noreferrer"&gt;Myna&lt;/a&gt; which is our new &lt;a href="https://matrix.org" rel="noopener noreferrer"&gt;Matrix&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;Having these servers running locally makes it easier to test interesting configurations, but more importantly, lets me use them on stream without leaking my IP address or any passwords.&lt;/p&gt;

&lt;p&gt;Anyways, I'm not always at home when I want to work on something and I wanted to find a way to access services remotely. Well tonight I realized I should be able to do this with &lt;a href="https://tailscale.com/" rel="noopener noreferrer"&gt;Tailscale&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm already using Tailscale to make sure we can access all of our build agents which are spread across a few sites, so being able to expose this to the other Pidgin developers who have access to that Tailscale network is just icing on the cake.&lt;/p&gt;

&lt;p&gt;So I decided to give the Tailscale Kubernetes Operator a go. They have full documentation it &lt;a href="https://tailscale.com/kb/1236/kubernetes-operator" rel="noopener noreferrer"&gt;here&lt;/a&gt;. As is pretty typical right now their installation instructions are based on using &lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I prefer to use &lt;a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/" rel="noopener noreferrer"&gt;Kustomize&lt;/a&gt; over Helm. There's plenty of reasons, but there's no reason to get into that now ;)&lt;/p&gt;

&lt;p&gt;Thankfully, Tailscale provides a static manifest for deploying the operator. This is very easy to import into our kustomize and get running directly quite quickly.&lt;/p&gt;

&lt;p&gt;But of course, it's not just that easy. Their instructions have you modifying that manifest and then applying that. This isn't a big deal, but it makes upgrading harder as you have to keep track of what you edited. Sure you could use version control (and you should have your manifest in version control) but kustomize makes this very easy.&lt;/p&gt;

&lt;p&gt;First we needed to download &lt;code&gt;operator.yaml&lt;/code&gt; which is the static manifest that Tailscale provides. We're going to use this file as is without modification which means we can just replace it if/when they update it.&lt;/p&gt;

&lt;p&gt;Next we need to create our &lt;code&gt;kustomization.yaml&lt;/code&gt; which is used to drive everything. My commented &lt;code&gt;kustomization.yaml&lt;/code&gt; is below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# Here we reference the unmodified operator.yaml we downloaded from&lt;/span&gt;
&lt;span class="c1"&gt;# Tailscale.&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;operator.yaml&lt;/span&gt;
&lt;span class="na"&gt;patches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Tailscale needs network admin and some other permissions, so&lt;/span&gt;
  &lt;span class="c1"&gt;# we use the following patch that will add the appropriate&lt;/span&gt;
  &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="s"&gt;annotations to the namespace.&lt;/span&gt;
  &lt;span class="s"&gt;- patch&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
      &lt;span class="s"&gt;apiVersion: v1&lt;/span&gt;
      &lt;span class="s"&gt;kind: Namespace&lt;/span&gt;
      &lt;span class="s"&gt;metadata:&lt;/span&gt;
        &lt;span class="s"&gt;name: tailscale&lt;/span&gt;
        &lt;span class="s"&gt;labels:&lt;/span&gt;
          &lt;span class="s"&gt;pod-security.kubernetes.io/enforce: privileged&lt;/span&gt;
          &lt;span class="s"&gt;pod-security.kubernetes.io/audit: privileged&lt;/span&gt;
          &lt;span class="s"&gt;pod-security.kubernetes.io/warn: privileged&lt;/span&gt;
&lt;span class="na"&gt;secretGenerator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# As I mentioned earlier, operator.yaml defines a secret for the&lt;/span&gt;
  &lt;span class="c1"&gt;# tailscale oauth secrets which the documentation wants you to&lt;/span&gt;
  &lt;span class="c1"&gt;# modify manually. We can instead use a secret generator to read&lt;/span&gt;
  &lt;span class="c1"&gt;# those values from an `env` file and merge them into the&lt;/span&gt;
  &lt;span class="c1"&gt;# existing secret.&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;operator-oauth&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tailscale&lt;/span&gt;
    &lt;span class="na"&gt;behavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;merge&lt;/span&gt;
    &lt;span class="na"&gt;envs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;secrets/env&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;With this all now setup, we can run &lt;code&gt;kubectl kustomize&lt;/code&gt; and verify our output. A condensed output with just the namespace and secret are below.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pod-security.kubernetes.io/audit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;privileged&lt;/span&gt;
    &lt;span class="na"&gt;pod-security.kubernetes.io/enforce&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;privileged&lt;/span&gt;
    &lt;span class="na"&gt;pod-security.kubernetes.io/warn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;privileged&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tailscale&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aGFjayB0aGUgcGxhbmV0&lt;/span&gt;
  &lt;span class="na"&gt;client_secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aGFja2VycyBvZiB0aGUgd29ybGQgdW5pdGU=&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;operator-oauth&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tailscale&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now that we've confirmed everything looks good, we can get ready to apply it to our cluster. Normally I'd recommend doing a dry run first, but since we're applying a namespace as well most of the tests will fail because that namespace doesn't exist.&lt;/p&gt;

&lt;p&gt;Anyways, we can apply this kustomization with the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

kubectl apply &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;If everything is successful you'll see something like the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

namespace/tailscale configured
customresourcedefinition.apiextensions.k8s.io/connectors.tailscale.com configured
customresourcedefinition.apiextensions.k8s.io/dnsconfigs.tailscale.com configured
customresourcedefinition.apiextensions.k8s.io/proxyclasses.tailscale.com configured
serviceaccount/operator configured
serviceaccount/proxies configured
role.rbac.authorization.k8s.io/operator configured
role.rbac.authorization.k8s.io/proxies configured
clusterrole.rbac.authorization.k8s.io/tailscale-operator configured
rolebinding.rbac.authorization.k8s.io/operator configured
rolebinding.rbac.authorization.k8s.io/proxies configured
clusterrolebinding.rbac.authorization.k8s.io/tailscale-operator configured
secret/operator-oauth configured
deployment.apps/operator configured
ingressclass.networking.k8s.io/tailscale configured


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

&lt;/div&gt;

&lt;p&gt;You can verify the operator is up and running the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; tailscale get deployments


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

&lt;/div&gt;

&lt;p&gt;You should see something like the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

NAME       READY   UP-TO-DATE   AVAILABLE   AGE
operator   1/1     1            1           72m


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

&lt;/div&gt;

&lt;p&gt;If that all looks good you can go ahead and verify that it shows up in the &lt;a href="https://login.tailscale.com/admin/machines" rel="noopener noreferrer"&gt;Machines&lt;/a&gt; section in Tailscale. You should see something like the following:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq1mhl1obm15j2lfpdi2s.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq1mhl1obm15j2lfpdi2s.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we're ready to expose a service via Tailscale!&lt;/p&gt;

&lt;p&gt;As I mentioned earlier, I'm running an Ergo instance for local IRC development. I have an &lt;code&gt;Service&lt;/code&gt; of type &lt;code&gt;LoadBalancer&lt;/code&gt; to expose it to my LAN via &lt;a href="https://metallb.universe.tf/" rel="noopener noreferrer"&gt;MetalLB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Tailscale operator has multiple ways to integrate with your Kubernetes cluster, but we're just going to expose existing services to the tailnet and doing that is extremely simple.&lt;/p&gt;

&lt;p&gt;To do so, you just need to add the &lt;code&gt;tailscale.com/expose: "true"&lt;/code&gt; annotation to the service. Below is my updated &lt;code&gt;Service&lt;/code&gt; for Ergo:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ergo&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tailscale.com/expose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ergo&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6667&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;irc&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6697&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ircs&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ergo&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now that that's done, I can apply the Kustomization for Ergo:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

kubectl apply -k .


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

&lt;/div&gt;

&lt;p&gt;The operator will automatically add it to the tailnet with a machine name of &lt;code&gt;&amp;lt;namespace&amp;gt;-&amp;lt;service-name&amp;gt;&lt;/code&gt;. This ergo instance is running in the &lt;code&gt;reaperworld&lt;/code&gt; namespace so it's machine name, and therefore DNS name is &lt;code&gt;reaperworld-ergo&lt;/code&gt; which we can now see in the Tailscale machines page.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faj3fyrs4fwghlvbye7e3.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faj3fyrs4fwghlvbye7e3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it, that service is now available on the tailnet accessible to anyone else on the tailnet!&lt;/p&gt;

&lt;p&gt;I hope you all found this interesting. I decided to write this as I had to learn about &lt;code&gt;behavior: merge&lt;/code&gt; property of the &lt;code&gt;secretGenerator&lt;/code&gt; and figured others might find this useful as well. Plus it gave me an excuse to show the power of Kustomize!&lt;/p&gt;

</description>
      <category>tailscale</category>
      <category>kubernetes</category>
      <category>kustomize</category>
    </item>
    <item>
      <title>Random Thoughts on Implementing Reactions</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Fri, 14 Jun 2024 20:48:09 +0000</pubDate>
      <link>https://forem.com/grim/random-thoughts-on-implementing-reactions-cg0</link>
      <guid>https://forem.com/grim/random-thoughts-on-implementing-reactions-cg0</guid>
      <description>&lt;p&gt;I was randomly thinking of how we'd integrate stuff like Mastodon, Twitter, Facebook posts, YouTube videos, and so on into Pidgin 3. Now I'm not saying &lt;strong&gt;I'm&lt;/strong&gt; planning on implementing these, but thinking about these helps determine how the interface should work to make them possible while still supporting traditional chat applications.&lt;/p&gt;

&lt;p&gt;Replies/comments will be easy as they'll be built into libpurple. The protocol would just treat each post or whatever has a channel or group direct message and then everything else is business as usual.&lt;/p&gt;

&lt;p&gt;However reactions might get weird because some of these only allow a few different reactions. For Mastodon and Twitter this is star/like, YouTube is thumbs up and thumbs down, and Facebook has it's normal 6 or whatever reactions.&lt;/p&gt;

&lt;p&gt;Reactions are something we &lt;em&gt;need&lt;/em&gt; to have and it's a topic I haven't actually spent much time thinking about it, but it's going to be coming up soon (tm), so I've been slowly working the problem.&lt;/p&gt;

&lt;p&gt;In traditional chat applications you can usually react with anything from the &lt;a href="https://www.unicode.org/emoji/charts/full-emoji-list.html"&gt;Unicode Emoji list&lt;/a&gt; which would have made this whole thing easy if that were the only thing you could react with.&lt;/p&gt;

&lt;p&gt;However, other chat networks have custom emoji that can be used as reactions too. Discord in particular makes this kind of funky because some servers won't allow custom emojis and other servers only let you use their custom emojis on their server.&lt;/p&gt;

&lt;p&gt;With that background now, it becomes obvious that the only real way to determine what reactions are available for a given message is to ask the protocol plugin itself on a per message basis.&lt;/p&gt;

&lt;p&gt;This means that we will have to add additional API to do this. This is anything major, and protocols that have a static list of elements, like Mastodon, Twitter, YouTube, etc will just have a simple function that can return the available reactions, where as something like Discord can go and ask the server what's available if need be.&lt;/p&gt;

&lt;p&gt;Now that the UI knows what reactions the user can use, it can then pass it on to the protocol which will actually pass it on to the server doing what it needs to do.&lt;/p&gt;

&lt;p&gt;We still need to figure out the exact representation reactions, which will &lt;em&gt;probably&lt;/em&gt; just be an &lt;code&gt;id,&lt;/code&gt;icon-name&lt;code&gt;, and&lt;/code&gt;description`, but since most reactions are repurposed emoji, we'll probably have to wait until those are sorted out before moving forward.&lt;/p&gt;

&lt;p&gt;At any rate we now have some ideas on how to move forward here which is always a good place to be :)&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>integration</category>
      <category>pidgin</category>
      <category>purple</category>
    </item>
    <item>
      <title>Why so rude?</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Thu, 21 Mar 2024 05:00:00 +0000</pubDate>
      <link>https://forem.com/grim/why-so-rude-bh0</link>
      <guid>https://forem.com/grim/why-so-rude-bh0</guid>
      <description>&lt;p&gt;Having worked in the open for over 20 years I've conversed with people from all over the world and all different walks of life.&lt;/p&gt;

&lt;p&gt;Recently I've noticed something troubling. Now this probably won't come as a surprise to many, but lately I've been running into people that just can't seem to understand that the experiences of others can be different than their own.&lt;/p&gt;

&lt;p&gt;I know respect for multiple perspectives is hard, but the issues seem to have even grown to include simple mundane things about life where people can't look outside of their immediate surroundings.&lt;/p&gt;

&lt;p&gt;The other night while watching a &lt;a href="https://twitch.tv"&gt;Twitch.tv&lt;/a&gt; stream, we (chat) got into a discussion about starting vegetable seedlings before planting them in a garden. One chatter said something along the lines of&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;lol you should have started that months ago.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I responded with&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We're clearly in different &lt;a href="https://planthardiness.ars.usda.gov/"&gt;hardiness zones&lt;/a&gt; as I'm still about 8 weeks out from the last freeze. Hell it even snowed yesterday...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The chatter then responded with something like&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Oh yeah, I'm in Florida, we don't get frost.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Based on their initial response I knew that something like this response was coming because this has become a typical interaction for me.&lt;/p&gt;

&lt;p&gt;I know I'm probably over analyzing this as I'm writing a blog post about it, but the original response comes off as disrespectful, elitist, and completely lacking in humility. &lt;/p&gt;

&lt;p&gt;I have interactions like this all the time and I honestly don't understand why. Someone will just blurt out something that's obviously subjective, with a high level of confidence, and in some cases will even try to mock the person they're responding to.&lt;/p&gt;

&lt;p&gt;I don't know if it's some statistical anomaly or what, but people do this to me constantly. In the official Pidgin channels, my own Twitch streams, random chats, forums, wherever. People refuse to acknowledge my reasoning, see it as an attack against them, and then start rambling nonsense at me. It's gotten totally out of control.&lt;/p&gt;

&lt;p&gt;Unfortunately When I've tried to confront this behavior, no matter how gentle I try to be, it's almost always seen as an attack against the other person. This is very ironic as typically they're the ones being rude and obtuse in the first place. &lt;/p&gt;

&lt;p&gt;A common example of this is that someone will mention that "Pidgin isn't a good IRC client". That is their opinion and I have no issue with that, but as the project maintainer, I would &lt;strong&gt;REALLY&lt;/strong&gt; like to know what we can do better. &lt;/p&gt;

&lt;p&gt;Unfortunately these discussions tend to devolve extremely quickly. People feel like I'm putting them on the spot and become defensive no matter how sensitive I try to be.&lt;/p&gt;

&lt;p&gt;I've seriously had people and observers think I was interrogating someone when I was using phrases like "I'd to hear your thoughts" or "could you be more specific?". &lt;/p&gt;

&lt;p&gt;I've spent a lot of time reflecting on these discussions and the only thing I've been able to come up with is that it appears that people just like to be rude. So much so, that they'll only remember that they didn't like something, and completely forget what they didn't like about it. &lt;/p&gt;

&lt;p&gt;Another example was in the exact same Twitch stream mentioned above. I mentioned that I was setting up a new build agent for Pidgin based on a &lt;a href="https://www.raspberrypi.com/"&gt;Raspberry Pi&lt;/a&gt; 5 using an m.2 SATA drive.&lt;/p&gt;

&lt;p&gt;Apparently that wasn't enough of a reason for people as the discussion immediately devolved into the typical "you can get a more powerful x86 machine for just as much" and so on.&lt;/p&gt;

&lt;p&gt;Whether or not that is true depends on your own personal situation. However, the point I'm trying to make is that my personal reasoning for my choices were completely ignored while the discussion pivoted into a meta discussion driven by elitism.&lt;/p&gt;

&lt;p&gt;On the plus side, I wasn't directly involved in the discussion anymore, but I still accidentally kicked it off, because surprise, people seem to have some very strong feelings about Raspberry Pis and feel the need to tell you all about them whether you want to hear them or not.&lt;/p&gt;

&lt;p&gt;The reasons someone may be using a Raspberry PI is quite frankly, none of your business, and their mention of it is not an invitation for someone to start preaching to them. Perhaps the Raspberry PI was was a gift or a hand me down from a mentor to a new enthusiast who couldn't afford one. In that case, and many others, the price difference is completely irrelevant and you're just making yourself look bad by being rude and pedantic.&lt;/p&gt;

&lt;p&gt;As I mentioned earlier, this scenario happens to me all the time. This is precisely why I refuse to discuss why we don't use &lt;a href="https://git-scm.com/"&gt;Git&lt;/a&gt; or &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt; for &lt;a href="https://pidgin.im"&gt;Pidgin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;No matter what reasoning or data I provide, it won't be enough for defenders of the &lt;a href="https://en.wikipedia.org/wiki/Monoculture_(computer_science)"&gt;monoculture&lt;/a&gt;. This group tends to think that there is one correct way to do things and everything else is empirically wrong and deserves immediate debate.&lt;/p&gt;

&lt;p&gt;There's a similar group that will try to bait you into these debates with prompts like "I'm curious why you use ". For some reason they believe they deserve an explanation and will get indignant if you don't give it to them immediately.&lt;/p&gt;

&lt;p&gt;Both of these groups are more interested in proving that their narrow focus is correct. They will ignore anything to the contrary and expect you to stop what you're doing and defend your stance immediately and attempt to sway their opinion, which can not be done. Many of them will also try to continue the discussion when you try to walk away. They're not interested in understanding, just their correctness and their ability to assert it.&lt;/p&gt;

&lt;p&gt;As you might imagine, this is not only extremely exhausting and unproductive, it's also extremely hostile. No one wants to have to defend their choices constantly. Many people will write a blog post explaining their stance and point people to it like I'm doing now, but that has its own set of problems.&lt;/p&gt;

&lt;p&gt;Many people have asked me to write a blog post on my preference of &lt;a href="https://mercurial-scm.org/"&gt;Mercurial&lt;/a&gt; over Git and so far I've refused and will continue doing so for the foreseeable future.&lt;/p&gt;

&lt;p&gt;I already know what the comments section will be like. I see it in trivial discussions like those mentioned above and I've seen it in this specific case too many times to count. I already know what the &lt;a href="https://hn.algolia.com/?q=mercurial"&gt;Hacker News&lt;/a&gt; and &lt;a href="https://lobste.rs/search?q=mercurial&amp;amp;what=comments&amp;amp;order=newest"&gt;lobste.rs&lt;/a&gt; comment sections will look like because this topic has been rehashed so many times.&lt;/p&gt;

&lt;p&gt;Nothing productive ever comes out of it and no one's "curiosity" is ever satisfied. Maybe a few people learn about some alternatives, but the only thing stopping them from even looking for them in the first place is the status quo of the monoculture.&lt;/p&gt;

&lt;p&gt;More importantly, there is nothing for me personally to gain here. My choices are made from my own opinions which are based on my own experiences. Even if someone were to gain some insight from my description, they can't necessarily act on it due to the incompatibility of Git and Mercurial and the monoculture around Git will continue to enforce that until a new contender appears. &lt;/p&gt;

&lt;p&gt;If you've ever had a discussion with me that sounds like what I've described here, there's a good chance I ended up avoiding responding to you, timed you out, or banned you. Hopefully this post helps to explain why that happens.&lt;/p&gt;

&lt;p&gt;Likewise, if you've ever seen me quietly disappear from a community it's most likely because I reached my limit of dealing with interactions like this.&lt;/p&gt;

&lt;p&gt;I try to do my best to be understanding of cultural differences and translation issues that occur when interacting with individuals where English is a second language, but eventually my patience will run out and the only thing left that I can do is to leave.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>community</category>
    </item>
    <item>
      <title>Why is there no mobile version of Pidgin?</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Thu, 01 Feb 2024 06:00:00 +0000</pubDate>
      <link>https://forem.com/grim/why-is-there-no-mobile-version-of-pidgin-44df</link>
      <guid>https://forem.com/grim/why-is-there-no-mobile-version-of-pidgin-44df</guid>
      <description>&lt;p&gt;We frequently get asked when a mobile version of Pidgin will be available or why it doesn't exist. There's actually quite a bit to it which makes for a decently sized blog post. So... Here we go!&lt;/p&gt;

&lt;p&gt;It is completely feasible to write a libpurple user interface for &lt;a href="https://en.wikipedia.org/wiki/Android_(operating_system)" rel="noopener noreferrer"&gt;Android&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/IOS" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;, or any other mobile operating systems. In fact &lt;a href="https://en.wikipedia.org/wiki/Palm,_Inc." rel="noopener noreferrer"&gt;Palm Inc.&lt;/a&gt; used libpurple as the backend for their messaging application in &lt;a href="https://en.wikipedia.org/wiki/WebOS" rel="noopener noreferrer"&gt;WebOS&lt;/a&gt; since version &lt;a href="https://web.archive.org/web/20131101122228/http://www.openwebosproject.org/opensource/1.0.1/index.html" rel="noopener noreferrer"&gt;1.0&lt;/a&gt; in 2009. But the problem for the Pidgin team is that we just don't have the resources and expertise to create and properly maintain these additional versions.&lt;/p&gt;

&lt;p&gt;There was an attempt at libpurple on Android via a 2012 &lt;a href="https://en.wikipedia.org/wiki/Google_Summer_of_Code" rel="noopener noreferrer"&gt;Google Summer of Code&lt;/a&gt; &lt;a href="https://pidgin.im/development/gsoc/#gsoc-2012" rel="noopener noreferrer"&gt;project&lt;/a&gt;. But that project had to manually write &lt;a href="https://en.wikipedia.org/wiki/Java_Native_Interface" rel="noopener noreferrer"&gt;JNI&lt;/a&gt; bindings so that libpurple could be accessed from &lt;a href="https://en.wikipedia.org/wiki/Java_(programming_language)" rel="noopener noreferrer"&gt;Java&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Modern innovations like &lt;a href="https://gi.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;GObject Introspection&lt;/a&gt; with &lt;a href="https://wiki.gnome.org/Projects/JGIR" rel="noopener noreferrer"&gt;JGIR&lt;/a&gt; have basically solved this issue and made Android development with native libraries nearly as easy as doing so with &lt;a href="https://en.wikipedia.org/wiki/Objective-C" rel="noopener noreferrer"&gt;Objective-C&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Swift_(programming_language)" rel="noopener noreferrer"&gt;Swift&lt;/a&gt; on iOS.&lt;/p&gt;

&lt;p&gt;So while this is technically possible, we come back to the issue of resources. Currently there are 2 people, including myself, actively working on Pidgin in their free time. However, neither of us know Android or iOS development at all.&lt;/p&gt;

&lt;p&gt;For us to create additional user interfaces is to increase our workload immensely and take a lot of time away from Pidgin. We're currently struggling to keep &lt;a href="https://finch.im" rel="noopener noreferrer"&gt;Finch&lt;/a&gt;, our &lt;a href="https://en.wikipedia.org/wiki/Ncurses" rel="noopener noreferrer"&gt;Ncurses&lt;/a&gt; user interface to libpurple, up to date as well. So much so that I will soon be calling for someone to step up and take over the Finch project in the near future.&lt;/p&gt;

&lt;p&gt;The next hurdle to deal with is the terms of services for both the Android Play Store and the iOS App Store. libpurple connects directly to chat networks. What this means is that for multiple networks like Discord, Slack, Google Chat, Microsoft Teams, etc is that we are generally breaking their Terms of Service because they do not allow third party clients.&lt;/p&gt;

&lt;p&gt;While this can be debated, this essentially counts as "unauthorized access" to these networks which is forbidden in the Android &lt;a href="https://play.google.com/about/developer-distribution-agreement.html#4.-use-of-google-play-by-you" rel="noopener noreferrer"&gt;Developer Distribution Agreement § 4.9&lt;/a&gt;. However, the iOS &lt;a href="https://developer.apple.com/app-store/review/guidelines/#5.2.2" rel="noopener noreferrer"&gt;App Store Review Guidelines § 5.2.2&lt;/a&gt; states that you need explicit permission to connect to these networks which we won't get.&lt;/p&gt;

&lt;p&gt;There's also the FOSS clause in the &lt;a href="https://developer.apple.com/support/terms/apple-developer-program-license-agreement/#a334" rel="noopener noreferrer"&gt;Apple Developer Program License § 3.3.4 A v&lt;/a&gt; which normally requires an exception to be granted by the copyright holders of the FOSS application. For Pidgin, that includes everyone in our &lt;a href="https://keep.imfreedom.org/pidgin/pidgin/file/default/COPYRIGHT" rel="noopener noreferrer"&gt;COPYRIGHT&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;As you may have noticed, we don't have contact information for any of those people. Even if we did, it is probably safe to say that at least one of them is no longer with us, which makes this all impossible. But even if that wasn't the case, you might also have noticed that &lt;a href="https://en.wikipedia.org/wiki/Sun_Microsystems" rel="noopener noreferrer"&gt;Sun Microsystems&lt;/a&gt; is credited in there as well.&lt;/p&gt;

&lt;p&gt;Sun Microsystems was &lt;a href="https://en.wikipedia.org/wiki/Acquisition_of_Sun_Microsystems_by_Oracle_Corporation" rel="noopener noreferrer"&gt;acquired&lt;/a&gt; by &lt;a href="https://en.wikipedia.org/wiki/Oracle_Corporation" rel="noopener noreferrer"&gt;Oracle&lt;/a&gt; in 2010 and I have no idea whether or not their copyrights on their contributions to Open Source projects were included in that acquisition. This would probably require getting lawyers involved and just isn't important to us right now and I'm not sure it ever will be.&lt;/p&gt;

&lt;p&gt;So essentially the app stores are not an option. We could do the work and take the chance of being taken down, but that doesn't sound like a good use of our extremely limited time.&lt;/p&gt;

&lt;p&gt;After that, people generally ask about side loading. While it certainly is an option on Android, it isn't nearly as easy on iOS. This could possibly change depending on the results of &lt;a href="https://en.wikipedia.org/wiki/Epic_Games_v._Apple" rel="noopener noreferrer"&gt;Epic Games v. Apple&lt;/a&gt; but that's just speculation.&lt;/p&gt;

&lt;p&gt;Regardless, building an application that can only be side loaded means your potential audience is very small and that you'll have more support requests for installation and updates than you would on any other platform. For those reasons, this is not an avenue we intend to go down.&lt;/p&gt;

&lt;p&gt;So let's pretend for a moment none of these issues existed and that the only barrier to Pidgin on mobile was resources. Even then there's a huge problem lurking in the shadows, notifications.&lt;/p&gt;

&lt;p&gt;On mobile platforms when the device goes to sleep network connections are typically terminated to save battery and network data. This works because the mobile platforms support &lt;a href="https://en.wikipedia.org/wiki/Mobile_marketing#Push_notifications" rel="noopener noreferrer"&gt;push notifications&lt;/a&gt; which are basically a way to tell the mobile device that your application needs attention. For this to work, you need to know when to send a push notification. &lt;/p&gt;

&lt;p&gt;For Pidgin to do this, we would need a server that knows when your messages come in and then send the push notification. To know when your messages come in, we'd need your credentials and have to be logged in on the server side to receive those messages. This is not what we're trying to accomplish. We are not trying to create a cloud service nor deal with all of the complexity, privacy, and security concerns that come that.&lt;/p&gt;

&lt;p&gt;So, without push notifications, Pidgin on mobile can't tell you when messages come in without keeping something running which will use more battery and network data than most people would like, which of course means additional support requests for a problem that we can't possibly solve.&lt;/p&gt;

&lt;p&gt;All of these reasons are why we won't be releasing Pidgin on mobile any time soon, if ever. If you have any questions or comments, or if I got something wrong, please don't hesitate to comment!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>mobile</category>
      <category>licensing</category>
      <category>distribution</category>
    </item>
    <item>
      <title>Scary Code Base</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Thu, 26 Oct 2023 05:00:00 +0000</pubDate>
      <link>https://forem.com/grim/scary-code-base-30n7</link>
      <guid>https://forem.com/grim/scary-code-base-30n7</guid>
      <description>&lt;p&gt;Often I refer to the Pidgin code base as &lt;strong&gt;&lt;em&gt;scary&lt;/em&gt;&lt;/strong&gt;. This is because it is very old, has implementations for things that there are libraries for now, is full of tech debt. Most of it was originally written by teenagers and people in their early 20's. In other words, not "professional" developers.&lt;/p&gt;

&lt;p&gt;But that's okay. As you all know &lt;strong&gt;&lt;em&gt;I&lt;/em&gt;&lt;/strong&gt; was one of those people in their early 20's writing some of that scary code. And now I'm pushing to make that code more friendly. It's way more approachable from all points of view today, but of course there's still work to do.&lt;/p&gt;

&lt;p&gt;However, that's not what I want to talk about today. Today we're going to talk about my philosophy when it comes to the attitude or approach I like to take with that code and how it can affect both our peers and ourselves.&lt;/p&gt;

&lt;p&gt;I've explained this quite a few times on stream but found myself explaining it again in person and decided that I should really just write this down so that others can see it and hopefully add to it. So without further ado..&lt;/p&gt;

&lt;p&gt;We've all been there before, getting frustrated trouble shooting some code and finally go "Who the hell wrote this!?" and immediately reach for our &lt;strong&gt;&lt;em&gt;blame&lt;/em&gt;&lt;/strong&gt; tool. We're frustrated and annoyed and we want to be angry at someone for it dammit!&lt;/p&gt;

&lt;p&gt;We all know the meme about this, that 9 times out of 10 it ends up being yourself, or something to that nature. But the real question here is, "Why are we so angry about some code?" Sure this code is weird, hard to read/follow, and probably buggy, but why are we so mad at it?&lt;/p&gt;

&lt;p&gt;Do we feel like that person that wrote that code was really trying to make things inconvenient for us? Do they have it out for us? Are they lazy? The answer to all of these questions is "who cares?"&lt;/p&gt;

&lt;p&gt;In my experience, most developers are trying to do the best they can every day every line of code. Maybe they didn't know of a technique that you're aware of and would be excited for you to teach it to them, maybe they were or are going through some personal things and aren't able to do their best, maybe they're just having an off day and don't want to put up with your shit, or maybe they don't even work or contribute to that project anymore.&lt;/p&gt;

&lt;p&gt;Getting angry about this is just nonsensical. It doesn't fix the problem and in most cases it's going to slow you down as you have to calm down. Sure it sucks, but programming is hard and no one writes bug free code that's completely optimal. If someone makes that claim, they're full of shit. &lt;/p&gt;

&lt;p&gt;And sure, watching an experienced programmer work can look like magic as they dance their way around writing bugs and memory leaks, all while avoiding the documentation as they have most of it memorized, but this all comes down to practice, so much practice.&lt;/p&gt;

&lt;p&gt;So what do I suggest instead? It's easy, just fix the code. Most of the time it doesn't matter who wrote the code, the real issue is the bug and the effects it's having on the people that use your software. They don't care who broke it, they care that it &lt;strong&gt;&lt;em&gt;is&lt;/em&gt;&lt;/strong&gt; broken.&lt;/p&gt;

&lt;p&gt;But in the case that it does matter, it's more important &lt;strong&gt;&lt;em&gt;when&lt;/em&gt;&lt;/strong&gt; they wrote that code. If someone has been working on this code for long time and they're making mistakes, you should be helping them to do better, constructively by mentoring them not humiliating them.&lt;/p&gt;

&lt;p&gt;Don't approach them like "Hey this code is shit..." that's going to immediately put them on the defensive and make the situation worse because now they're rightfully going to think you're an asshole.&lt;/p&gt;

&lt;p&gt;Instead try something like, "Hey I was reviewing some code in this section and noticed there's better/simpler/easier way to do this. If you're interested just let me know and I can walk you through it when you have some time."&lt;/p&gt;

&lt;p&gt;I know a lot of you are probably cringing at this, but even if someone is 100% completely objectively doing something wrong, they're way more open to discussion about it if you're courteous of their effort and their time. Also if you can't be polite to each other, you're probably not going to be working together much longer as well.&lt;/p&gt;

&lt;p&gt;This all applies to code review too of course. Many people get anxiety about code review because they identify with their code. This gets reinforced by the &lt;strong&gt;&lt;em&gt;blame&lt;/em&gt;&lt;/strong&gt; wars and messes with the motivators to write good code.&lt;/p&gt;

&lt;p&gt;Instead of writing good code to write good code which is rewarding, they start writing good code to avoid getting blamed/flamed/put on blast/whatever which is negative reinforcement and just creates contention between peers.&lt;/p&gt;

&lt;p&gt;What I'm really trying to say here is, be nice to each other, including your past self. We're all constantly getting better and we are not our old, new, or future code.&lt;/p&gt;

&lt;p&gt;And in the very rare case you need to find out who wrote some code and when, use &lt;strong&gt;&lt;em&gt;annotate&lt;/em&gt;&lt;/strong&gt;. In most version control systems &lt;strong&gt;&lt;em&gt;blame&lt;/em&gt;&lt;/strong&gt; is an alias of &lt;strong&gt;&lt;em&gt;annotate&lt;/em&gt;&lt;/strong&gt; and it has none of the negative connotations with it which helps check those micro biases.&lt;/p&gt;

&lt;p&gt;I hope you're enjoying these posts! Remember they go live for patrons at 9AM CST on Mondays and go public at 12AM CST on Thursdays! If there's something specific you'd like to see me cover here, please comment below!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>management</category>
      <category>techdebt</category>
    </item>
    <item>
      <title>In Tree Protocols</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Thu, 19 Oct 2023 05:00:00 +0000</pubDate>
      <link>https://forem.com/grim/in-tree-protocols-15ne</link>
      <guid>https://forem.com/grim/in-tree-protocols-15ne</guid>
      <description>&lt;p&gt;Determining what protocols to carry in our source code tree never really had a standard or process until recently. In this post I'm going to describe the process we're currently adopting and the events that led to it.&lt;/p&gt;

&lt;p&gt;Way back when we used to accept protocols into the tree without much hesitation. For example, we added a protocol Plugin for GroupWise that was &lt;a href="https://keep.imfreedom.org/pidgin/pidgin/rev/93d317c9976d"&gt;gifted to us by Novell&lt;/a&gt; even though we couldn't actually test it because we didn't have a GroupWise server.&lt;/p&gt;

&lt;p&gt;We had similar situations with &lt;a href="https://en.wikipedia.org/wiki/HCL_Sametime"&gt;SameTime&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Zephyr_(protocol)"&gt;Zephyr&lt;/a&gt; where we also had no access to a server which meant we couldn't test anything. It should come as no surprise that these protocols started to bit rot immediately only seeing updates when a technical user with enough patience would work with us to fix issues.&lt;/p&gt;

&lt;p&gt;Other times new protocols would get added by existing Pidgin developers because of their interest in it. This was generally okay because if someone reached Developer status, they had gained enough trust from the other developers and were expected to be around for quite a while. See &lt;a href="https://dev.to/grim/pidgin-developer-tiers-3g6j"&gt;Pidgin Developer Tiers&lt;/a&gt; for a more in-depth description.&lt;/p&gt;

&lt;p&gt;As you may have guessed, over time developers would lose interest in the protocols they brought in which would then of course start bit rotting as well. This happened with the popular protocols too, but sometimes that was just due to their complexity like the OSCAR protocol that AIM and ICQ used.&lt;/p&gt;

&lt;p&gt;While bit rot is a huge issue, the bigger issue with proprietary protocols especially, is keeping up with changes. With proprietary protocols changes are never expected and must be reversed engineered. This of course is all expected as these are proprietary protocols and there aren't supposed to be third party implementations by design but it's a huge burden to stay on top of.&lt;/p&gt;

&lt;p&gt;But the unexpected changes in proprietary protocols still aren't nearly as bad as dubious legality of the reverse engineering processes. While I believe we have always followed the law here, that doesn't mean our contributors have.&lt;/p&gt;

&lt;p&gt;I recall one contributor, a very long time ago, that was boasting about de-compiling an official client and using that to write patches for us. We of course had to reject those patches as they would have put the rest of the project as risk as that method of reverse engineering is to the best of my knowledge, illegal.&lt;/p&gt;

&lt;p&gt;This dubious legality even led to us losing a contributor a few years ago. This contributor had immigrated to the United States on a work visa, and the legal department at the company they were working for decided that this legal dubiousness wasn't an acceptable risk and stated they could no longer work on Pidgin while employed there.&lt;/p&gt;

&lt;p&gt;We were of course understanding of the situation, and as you expect, the contributor found something else to do with their free time and hasn't returned to the project. There's no ill will here, but we did learn an important lesson here about how others see some of the code that we carry.&lt;/p&gt;

&lt;p&gt;So with all that history out in the open, lets move on to how we're moving forward.&lt;/p&gt;

&lt;p&gt;To put it succinctly, Pidgin 3 will only have Open Source/Open Specification protocols in its source code tree that we can actually test. In doing so we will remove all legally questionable source code from our tree and thus avoid the previous situation where we lost a contributor.&lt;/p&gt;

&lt;p&gt;This means that the core protocols we'll be aiming to have are Bonjour, IRCv3, and XMPP. We're not aiming to have these all done by 3.0, but these are acceptable for us to have in tree.&lt;/p&gt;

&lt;p&gt;You might have noticed that Zephyr is not on this list even though it's an open protocol. We actually already removed the Zephyr implementation because we could not test it and because some of the code still use &lt;a href="https://stackoverflow.com/a/3092074"&gt;K&amp;amp;R functions&lt;/a&gt; as well as other pre-ansi C stuff.&lt;/p&gt;

&lt;p&gt;Similarly, &lt;a href="https://en.wikipedia.org/wiki/SILC_(protocol)"&gt;SILC&lt;/a&gt; has been removed because we can't connect due to a crash. We're not sure if it's the client library or the server that is the cause and looking deeper into it didn't seem like a good use of time.&lt;/p&gt;

&lt;p&gt;When it comes to proprietary protocols they are going to have to live as separate repositories. I know this has been problematic for users especially when it comes to stuff like Facebook, Discord, and others, but this is just the way it has to be.&lt;/p&gt;

&lt;p&gt;For starters, when something changes in these protocols, updates need to come as soon as they're ready. Releasing Pidgin is, complicated to say the least, and is not quick at all. So if these protocols were in the main tree, we'd have to force them into micro releases to get them out as fast as possible because the protocol would be broken but that importance is hidden expectations of a minor version number. They'd also be subject to string freezes and other quirks about our release process.&lt;/p&gt;

&lt;p&gt;But the real problem that users have with protocols not being in the main distribution is one of discovery. Sure we have the &lt;a href="https://pidgin.im/plugins/"&gt;plugins list&lt;/a&gt; to help people find them, but most users don't go to our website.&lt;/p&gt;

&lt;p&gt;The plan to solve this is to add an "addon store" inside of Pidgin, similar to the &lt;a href="https://chrome.google.com/webstore/category/extensions"&gt;Chrome Web Store&lt;/a&gt; and &lt;a href="https://addons.mozilla.org/en-US/firefox/extensions/"&gt;FireFox Add-ons&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This has been a concept we've been designing for a while but haven't actually built yet. A few interested parties have put together a few proof of concepts, but we haven't quite gotten to an minimum viable product yet. If this is something you might be interested in, please reach out!!&lt;/p&gt;

&lt;p&gt;So there you have it. Our new policy of including protocol plugins into the main source tree is that it must be Open Source/Open Specification. That means stuff like SIP, Mastodon, and Matrix could one day land in tree, but due to resources constraints, aren't on our road map.&lt;/p&gt;

&lt;p&gt;Proprietary protocol plugins will all be moved out of tree (only Gadu Gadu remains at the moment) but we plan to help users discover them via an add-on store that will also keep them up to date.&lt;/p&gt;

&lt;p&gt;I hope you're enjoying these posts! Remember they go live for patrons at 9AM CST on Mondays and go public at 12AM CST on Thursdays! If there's something specific you'd like to see me cover here, please comment below!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>legal</category>
      <category>management</category>
    </item>
    <item>
      <title>Our History with VCS's</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Thu, 12 Oct 2023 05:00:00 +0000</pubDate>
      <link>https://forem.com/grim/our-history-with-vcss-53ai</link>
      <guid>https://forem.com/grim/our-history-with-vcss-53ai</guid>
      <description>&lt;p&gt;I often get asked why Pidgin doesn't use Git. This post isn't going to talk about that directly, but instead talk about our history of using multiple different version control system and why we chose to make those moves at that time.&lt;/p&gt;

&lt;p&gt;When Pidgin was originally created by &lt;a href="https://en.wikipedia.org/wiki/Mark_Spencer_(computer_engineer)"&gt;Mark Spencer&lt;/a&gt; back in 1998 under the name Gaim, the main version control system to use was &lt;a href="https://en.wikipedia.org/wiki/Concurrent_Versions_System"&gt;CVS&lt;/a&gt;. So that's what Mark decided to use.&lt;/p&gt;

&lt;p&gt;However, this was before even &lt;a href="https://en.wikipedia.org/wiki/SourceForge"&gt;SourceForge&lt;/a&gt; existed so Mark had to set up his own CVS server that he ran on his own domain as Open Source code hosting just wasn't really a thing yet.&lt;/p&gt;

&lt;p&gt;The project remained on that CVS server for the next few years even as the the project declined as enthusiasm for EveryBuddy, later renamed &lt;a href="https://en.wikipedia.org/wiki/Ayttm"&gt;Ayttm&lt;/a&gt;, took off.&lt;/p&gt;

&lt;p&gt;Then in March of 2003, Rob Flynn picked up development of Gaim by creating a project in SourceForge. Unfortunately he created a new repository and copied the code in instead of importing the existing repository, but that's okay. However, this is the only version control history of the project that is not in our current repository.&lt;/p&gt;

&lt;p&gt;Then in March of 2006 we moved to &lt;a href="https://en.wikipedia.org/wiki/Apache_Subversion"&gt;Subversion&lt;/a&gt; as SourceForge had recently added support for it as well as automatic conversions from CVS. At the time Subversion was seen as "CVS done right" which admittedly was a pretty low bar. But regardless, it was tantalizing enough for us to make the move.&lt;/p&gt;

&lt;p&gt;Before we pulled the trigger to convert to Subversion we were discussing moving to one of the new distributed version control systems. This list included &lt;a href="https://en.wikipedia.org/wiki/Git"&gt;Git&lt;/a&gt; with &lt;a href="https://en.wikipedia.org/wiki/Cogito_(software)"&gt;Cogito&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Darcs"&gt;DARCS&lt;/a&gt;, and &lt;a href="https://en.wikipedia.org/wiki/GNU_Bazaar"&gt;Bazaar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We eventually ended up choosing &lt;a href="https://en.wikipedia.org/wiki/Monotone_(software)"&gt;Monotone&lt;/a&gt; in &lt;a href="https://sourceforge.net/p/pidgin/mailman/message/16333120/"&gt;April of 2007&lt;/a&gt;. Like many at the time, we were very interested in better branching, merging, and offline commits. In the near future I'll do a post covering how we used to handle contributions and why these features simplified the entire process.&lt;/p&gt;

&lt;p&gt;Then in &lt;a href="https://lists.pidgin.im/pipermail/devel/2011-January/021578.html"&gt;January of 2011&lt;/a&gt; discussion started on moving from Monotone to &lt;a href="https://en.wikipedia.org/wiki/Mercurial"&gt;Mercurial&lt;/a&gt;. There are plenty of reasons why we chose Mercurial in that mailing list thread so I won't discuss them here, but the prevailing issues were lack of tooling and complex user interactions.&lt;/p&gt;

&lt;p&gt;We're still using Mercurial today (as of October 2023) and have no desire or need to move to another version control system. The main reasoning for this is that we don't really have any issues with our current setup and any change to it would essentially be busy work.&lt;/p&gt;

&lt;p&gt;Also it appears that all of the innovation in version control seems to only be happening in Mercurial. See &lt;a href="https://www.mercurial-scm.org/doc/evolution/"&gt;Changeset Evolution&lt;/a&gt; and &lt;a href="https://wiki.mercurial-scm.org/ClonebundlesExtension"&gt;Clone Bundles&lt;/a&gt; for some examples of those innovations.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this trek down memory lane. As I mentioned earlier this is just historical information and not intended to sway someone's opinion. Also, we're not looking for opinions on switching VCS's any time soon either, so please keep those comments to yourself ;)&lt;/p&gt;

&lt;p&gt;I hope you're enjoying these posts! Remember they go live for patrons at 9AM CST on Mondays and go public at 12AM CST on Thursdays! If there's something specific you'd like to see me cover here, please comment below!&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>Talkatu's Future</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Thu, 14 Sep 2023 05:00:00 +0000</pubDate>
      <link>https://forem.com/grim/talkatus-future-5cf8</link>
      <guid>https://forem.com/grim/talkatus-future-5cf8</guid>
      <description>&lt;p&gt;Previously I introduced you all to &lt;a href="https://dev.to/grim/talkatu-hco"&gt;Talkatu&lt;/a&gt;. In that post I also talked about the uncertainty of Talkatu's future, well we've reached certainty now.&lt;/p&gt;

&lt;p&gt;In the previous post I mentioned how emoji and how contacts are represented were causing issues. Well it's been quite a few months since then and I've yet to come up with a decent solution to any of those problems.&lt;/p&gt;

&lt;p&gt;On top of that, the way we designed &lt;code&gt;TalkatuHistory&lt;/code&gt; was modeled after what we had in libpurple at the time, which was to "write" each message to the conversation and therefore the history widget.&lt;/p&gt;

&lt;p&gt;This doesn't work with what we were planning to do in Pidgin 3 by having a &lt;code&gt;GListModel&lt;/code&gt; as a property of the conversation which is how we were planning on integrating the History API into everything.&lt;/p&gt;

&lt;p&gt;While we could easily move &lt;code&gt;TalkatuHistory&lt;/code&gt; to using a &lt;code&gt;GListModel&lt;/code&gt; it just doesn't make sense to do so with all of the other issues.&lt;/p&gt;

&lt;p&gt;That means that yes we've finally decided to stop developing Talkatu itself. We're going to keep the project around as it has been great at helping us prototyping ideas and we may want to use it for that again in the future.&lt;/p&gt;

&lt;p&gt;This means that we will be integrating the Talkatu widgets into Pidgin 3. We're starting with &lt;code&gt;TalkatuHistory&lt;/code&gt; but this won't be a direct copy or anything as &lt;code&gt;TalkatuHistory&lt;/code&gt; is a &lt;a href="https://docs.gtk.org/gtk4/class.ListBox.html"&gt;GtkListBox&lt;/a&gt; and &lt;code&gt;PidginHistory&lt;/code&gt; will be a &lt;a href="https://docs.gtk.org/gtk4/class.ListView.html"&gt;GtkListView&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I still really like the idea of the &lt;code&gt;TalkatuMessage&lt;/code&gt; interface that allowed the input field for conversations to be a &lt;code&gt;TalkatuMessage&lt;/code&gt; as well as it could then be passed on to whatever was sending the actual message.&lt;/p&gt;

&lt;p&gt;We might still go that route with &lt;code&gt;PurpleMessage&lt;/code&gt;, but it'd require a bit of renaming and stuff, but it would also allow us to create more complicated messages later. Something that could potentially handle widgets and actions which seems to be all the rage in proprietary chat clients nowadays.&lt;/p&gt;

&lt;p&gt;At any rate, Talkatu was a great middle ground that helped us find a path forward. I have no regrets about developing it as we will be using basically all of its features directly. Also it's still a really great name and we'll need to find a way to honor it in Pidgin 3.&lt;/p&gt;

&lt;p&gt;I hope you're enjoying these posts! Remember they go live for patrons at 9AM CST on Mondays and go public at 12AM CST on Thursdays! If there's something specific you'd like to see me cover here, please comment below!&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>A narrowing of focus...</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Thu, 07 Sep 2023 05:00:00 +0000</pubDate>
      <link>https://forem.com/grim/a-narrowing-of-focus-2d3i</link>
      <guid>https://forem.com/grim/a-narrowing-of-focus-2d3i</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/grim/what-were-targeting-with-pidgin-300-alpha1-2fci"&gt;Awhile ago&lt;/a&gt; I wrote about what we were targeting for Pidgin 3.0.0 Alpha 1.&lt;/p&gt;

&lt;p&gt;At the time this felt like a good step forward as we didn't really have a road map or anything and this was precisely that. Except it wasn't, it turned out to be more of a nebulous list with little to no direction. Unfortunately it took awhile for me to realize this, but a solution was pretty easy to find.&lt;/p&gt;

&lt;p&gt;So, instead of just going through that list, we're going to focus on getting the new from scratch IRCv3 protocol plugin to the point where I can start using it with Pidgin 3 as a daily driver.&lt;/p&gt;

&lt;p&gt;Not only does this give us some much needed direction it will also finally get me using Pidgin 3 as a daily driver. On top of that, it'll create a good cycle as I will be able to find and fix bugs much faster as they'll be directly affecting me.&lt;/p&gt;

&lt;p&gt;So realistically not much is going to change from what we were doing before, but the &lt;a href="https://issues.imfreedom.org/issues?u=1&amp;amp;q=(Scheduled%20versions:%203.0.0-alpha1%20)%20and%20(%23unresolved)"&gt;3.0.0 Alpha 1&lt;/a&gt; issues will be prioritized to get IRCv3 working using all of the new APIs that we've been developing.&lt;/p&gt;

&lt;p&gt;I hope you're enjoying these posts! Remember they go live for patrons at 9AM CST on Mondays and go public at 12AM CST on Thursdays! If there's something specific you'd like to see me cover here, please comment below!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>planning</category>
    </item>
    <item>
      <title>Busy Busy</title>
      <dc:creator>Gary Kramlich</dc:creator>
      <pubDate>Mon, 04 Sep 2023 19:39:27 +0000</pubDate>
      <link>https://forem.com/grim/busy-busy-3g8j</link>
      <guid>https://forem.com/grim/busy-busy-3g8j</guid>
      <description>&lt;p&gt;Hey everyone, sorry I haven't been posting lately. I keep intending to, but then all of a sudden it's Thursday or something and I've never posted.&lt;/p&gt;

&lt;p&gt;That said, I have the next 2 post scheduled and I'm hoping to stay a post a head which will help keep these posts consistent.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
  </channel>
</rss>
