URI:
       add kokada.dev (RSS and Atom) - sfeed_tests - sfeed tests and RSS and Atom files
  HTML git clone git://git.codemadness.org/sfeed_tests
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 627538879a243435de10999fae80626ea58eea86
   DIR parent 0952a65777ea4fa93533cc27ff2c348a61f7c929
  HTML Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Fri,  6 Dec 2024 13:04:24 +0100
       
       add kokada.dev (RSS and Atom)
       
       uses https://capivaras.dev/ (blogging platform)
       
       Diffstat:
         A input/sfeed/realworld/kokada.dev.a… |    3703 +++++++++++++++++++++++++++++++
         A input/sfeed/realworld/kokada.dev.r… |    3707 +++++++++++++++++++++++++++++++
       
       2 files changed, 7410 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/input/sfeed/realworld/kokada.dev.atom.xml b/input/sfeed/realworld/kokada.dev.atom.xml
       @@ -0,0 +1,3702 @@
       +<?xml version="1.0" encoding="utf-8"?>
       +<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>kokada</title><link href="https://kokada.dev" rel="alternate"/><link href="https://kokada.dev/atom/" rel="self"/><id>https://kokada.dev</id><updated>2024-12-04T00:00:00+00:00</updated><subtitle/><entry><title>Praise to scdoc to generate man pages</title><link href="https://kokada.dev/blog/praise-to-scdoc-to-generate-man-pages/" rel="alternate"/><published>2024-12-04T00:00:00+00:00</published><id>https://kokada.dev/blog/praise-to-scdoc-to-generate-man-pages/</id><summary type="html">&lt;p&gt;Hey, its been a long time since my &lt;a href="posts/2024-10-07/01-enabling-le-audio-lc3-in-wf-1000xm5.md"&gt;last blog
       +post&lt;/a&gt;. It is mostly
       +because I ran out of things to write, but I expected this. This is probably
       +more likely how I am actually going to post from now. At least, it shows that
       +my plan to have a &lt;a href="https://kokada.dev/blog/making-a-blog-for-the-next-10-years"&gt;blog for a long
       +time&lt;/a&gt;, that is
       +easy to go back when I wanted is working fine, but I digress.&lt;/p&gt;
       +&lt;p&gt;Going back to the theme of the today blog post, I needed to write a &lt;a href="https://en.wikipedia.org/wiki/Man_page"&gt;man
       +page&lt;/a&gt; for the first time in years. I
       +hate &lt;a href="https://en.wikipedia.org/wiki/Troff"&gt;troff&lt;/a&gt;, the typesetting system used
       +for man pages (similar to &lt;a href="https://en.wikipedia.org/wiki/LaTeX"&gt;LaTeX&lt;/a&gt; for
       +documents). It is one of the weirdest languages that I ever saw, and even the
       +example in Wikipedia shows that:&lt;/p&gt;
       +&lt;pre&gt;&lt;code class="language-troff"&gt;.ND &amp;quot;January 10, 1993&amp;quot;
       +.AU &amp;quot;Ms. Jane Smith&amp;quot;
       +.AT &amp;quot;Upcoming appointment&amp;quot;
       +.MT 5
       +.DS
       +Reference #A12345
       +.sp 4
       +Mr. Samuel Jones
       +Field director, Bureau of Inspections
       +1010 Government Plaza
       +Capitoltown, ST
       +.sp 3
       +Dear Mr. Jones,
       +.sp 2
       +.P
       +Making reference to the noted obligation to submit for state inspection our newly created production process, we request that you consider the possible inappropriateness of subjecting the  innovative technologies of tomorrow to the largely antiquated requirements of yesterday.  If our great state is to prosper in the twenty-first century, we must take steps
       +.B now ,
       +in
       +.I this
       +year of
       +.I this
       +decade, to prepare our industrial base for the interstate and international competition that is sure to appear.  Our new process does precisely that.  Please do not let it be undone by a regulatory environment that is no longer apt.
       +.P
       +Thank you for your consideration of our position.
       +.FC Sincerely
       +.SG
       +&lt;/code&gt;&lt;/pre&gt;
       +&lt;p&gt;Keep in mind that the break lines are necessary every time you introduce a
       +macro, like &lt;code&gt;.I this&lt;/code&gt; (that I &lt;em&gt;think&lt;/em&gt; it is for italics). Yes, this format is
       +as illegible as hell, and it is worse that the format lacks good tooling (or at
       +least I didn't find any good ones).&lt;/p&gt;
       +&lt;p&gt;Most people when they need to write a man page nowadays ends up using some
       +other format that generates a man page. For example, in the past I used
       +&lt;a href="https://pandoc.org/"&gt;Pandoc&lt;/a&gt; to convert Markdown to a man page, but even if
       +Pandoc is a great project the result is sub-optimal at best: Markdowns are, at
       +the end, designed for generating HTML (and a subset of it), and not man pages,
       +so you basically ends up fighting the format for it to do what you want.
       +Also, Pandoc is a big project, with a ~200MB binary (at least it is the default
       +Pandoc binary in Nix).&lt;/p&gt;
       +&lt;p&gt;For this specific project I needed something small. I am trying to replace one
       +of the most essential pieces inside NixOS, &lt;code&gt;nixos-rebuild&lt;/code&gt;, written in Bash,
       +with a &lt;a href="https://discourse.nixos.org/t/nixos-rebuild-ng-a-nixos-rebuild-rewrite/55606/"&gt;full rewritten in
       +Python&lt;/a&gt;
       +(sorry Rust zealots!), called &lt;code&gt;nixos-rebuild-ng&lt;/code&gt;.&lt;/p&gt;
       +&lt;p&gt;Since this project will eventually (if successful) be in the critical path for
       +NixOS, I want to reduce the number of dependencies as much as possible, so
       +something as big as Pandoc is out. I could use
       +&lt;a href="https://asciidoc.org/"&gt;AsciiDoc&lt;/a&gt;, but it is a big complicated Python project
       +(this may seem ironic, but &lt;code&gt;nixos-rebuild-ng&lt;/code&gt; has only one runtime dependency,
       +that is optional). And I also hated the last time I tried to use it to generate
       +man pages: it more flexible than Markdown, but still far from optimal.&lt;/p&gt;
       +&lt;p&gt;Thanks to Drew DeVault (creator of &lt;a href="https://swaywm.org/"&gt;SwayWM&lt;/a&gt;) that seems it
       +had the same issues in the past and created
       +&lt;a href="https://drewdevault.com/2018/05/13/scdoc.html"&gt;&lt;code&gt;scdoc&lt;/code&gt;&lt;/a&gt;, a very simple man
       +page generator using a DSL inspired in Markdown, but specific to generate man
       +pages. The binary is written in C (and advantage in this case since it means it
       +is easier to bootstrap), is small (~1 Kloc) and has no dependencies, so it
       +fits the requirement.&lt;/p&gt;
       +&lt;p&gt;While the language suffers from being a niche project for a niche segment, the
       +&lt;a href="https://man.archlinux.org/man/scdoc.5.en"&gt;man page&lt;/a&gt; for it is actually really
       +nice. It is terse though and lacks examples, and this is what this blog post
       +will try to accomplish.&lt;/p&gt;
       +&lt;p&gt;To start, let's have a quick summary of the syntax, written in &lt;code&gt;scdoc&lt;/code&gt; as
       +comments:&lt;/p&gt;
       +&lt;pre&gt;&lt;code class="language-scdoc"&gt;; quick summary:
       +; # new section
       +; comments starts with ;
       +; - this is a list
       +;         - sub-list
       +; - *bold*: _underline_, force a line break++
       +; - [tables], \[ can be used to force an actual [
       +; . numbered list
       +; please configure your editor to use hard tabs
       +; see `man 5 scdoc` for more information about syntax
       +; or https://man.archlinux.org/man/scdoc.5.en
       +&lt;/code&gt;&lt;/pre&gt;
       +&lt;p&gt;I actually added this summary in the &lt;code&gt;.scd&lt;/code&gt; (the &lt;code&gt;scdoc&lt;/code&gt; extension) files that
       +I wrote, so it is easy for someone that never saw the format to start
       +collaborating.&lt;/p&gt;
       +&lt;p&gt;And here an example of a (summarised) man page in &lt;code&gt;.scd&lt;/code&gt; format:&lt;/p&gt;
       +&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nixos-rebuild-ng(8)
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# NAME
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nixos-rebuild - reconfigure a NixOS machine
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# SYNOPSIS
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ge"&gt;_nixos-rebuild_&lt;/span&gt; \[--upgrade] [--upgrade-all]++
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                \[{switch,boot}]
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# DESCRIPTION
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;This command has one required argument, which specifies the desired operation.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;It must be one of the following:
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ge"&gt;*switch*&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        Build and activate the new configuration, and make it the boot default.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        That is, the configuration is added to the GRUB boot menu as the
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        default menu entry, so that subsequent reboots will boot the system
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        into the new configuration. Previous configurations activated with
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        nixos-rebuild switch or nixos-rebuild boot remain available in the GRUB
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        menu.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ge"&gt;*boot*&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        Build the new configuration and make it the boot default (as with
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="ge"&gt;*nixos-rebuild switch*&lt;/span&gt;), but do not activate it. That is, the system
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        continues to run the previous configuration until the next reboot.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# OPTIONS
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="ge"&gt;*--upgrade, --upgrade-all*&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        Update the root user&amp;#39;s channel named &amp;#39;nixos&amp;#39; before rebuilding the
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        system.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        In addition to the &amp;#39;nixos&amp;#39; channel, the root user&amp;#39;s channels which have
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        a file named &amp;#39;.update-on-nixos-rebuild&amp;#39; in their base directory will
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        also be updated.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        Passing &lt;span class="ge"&gt;*--upgrade-all*&lt;/span&gt; updates all of the root user&amp;#39;s channels.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;See the Nix manual, &lt;span class="ge"&gt;*nix flake lock --help*&lt;/span&gt; or &lt;span class="ge"&gt;*nix-build --help*&lt;/span&gt; for details.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# ENVIRONMENT
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NIXOS_CONFIG
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        Path to the main NixOS configuration module. Defaults to
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="ge"&gt;_/etc/nixos/configuration.nix_&lt;/span&gt;.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# FILES
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/etc/nixos/flake.nix
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        If this file exists, then &lt;span class="ge"&gt;*nixos-rebuild*&lt;/span&gt; will use it as if the
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="ge"&gt;*--flake*&lt;/span&gt; option was given. This file may be a symlink to a
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        flake.nix in an actual flake; thus &lt;span class="ge"&gt;_/etc/nixos_&lt;/span&gt; need not be a
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        flake.
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# AUTHORS
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Nixpkgs/NixOS contributors
       +&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And here is a screenshot of the result:&lt;/p&gt;
       +&lt;p&gt;&lt;a href="https://github.com/thiagokokada/blog/raw/main/posts/2024-12-04/2024-12-04-230955_hyprshot.png"&gt;&lt;img src="https://github.com/thiagokokada/blog/raw/main/posts/2024-12-04/2024-12-04-230955_hyprshot.png" alt="Man page rendered from scd
       +file"&gt;&lt;/a&gt;&lt;/p&gt;
       +&lt;p&gt;One of nice things that I found is how looking at the plain text looks kind
       +like the man page result already. And if you know Markdown, you can basically
       +understand most things that is happening. There are a few differences, like
       +&lt;code&gt;*bold*&lt;/code&gt; instead of &lt;code&gt;**bold**&lt;/code&gt;, and while they're unfortunate they're not the
       +end of the world.&lt;/p&gt;
       +&lt;p&gt;Now, the format has its quirks. The first line being the name of the program
       +and section in parenthesis is required, but this makes sense, since you need
       +this information for the corners. But for one, it requires the usage of hard
       +tabs to create indentation, and the error messages are awful, in a situation
       +that kind remembers me of &lt;code&gt;Makefile&lt;/code&gt;. Also the choice of &lt;code&gt;[&lt;/code&gt; to start a table
       +means that the traditional &lt;code&gt;app [command]&lt;/code&gt; needs in many cases to be escaped as
       +&lt;code&gt;app \[command]&lt;/code&gt;. I found this a strange choice since this is supposed to be a
       +format that is only used for man pages, and using &lt;code&gt;[command]&lt;/code&gt; to indicate an
       +optional is common, but at least it is easy to escape.&lt;/p&gt;
       +&lt;p&gt;In the end, I think all that matters is the result. And for the first time for
       +all those years trying to write a man page, I am satisfied with the result. The
       +man page looks exactly as I wanted once rendered, and the &lt;code&gt;.scd&lt;/code&gt; file looks
       +reasonable good that it can work as a documentation for someone that for one
       +reason or another can't use the man page (can't say the same for the troff
       +version). Also, it is really easy for someone to just go there and update the
       +man page, even without experience in the format (except for maybe the
       +requirement of tabs). So all in all, I really liked the format, and will use it
       +again if I need to write another man page in the future.&lt;/p&gt;</summary></entry><entry><title>Enabling LE Audio/LC3 in WF-1000XM5</title><link href="https://kokada.dev/blog/enabling-le-audio-lc3-in-wf-1000xm5/" rel="alternate"/><published>2024-10-07T00:00:00+00:00</published><id>https://kokada.dev/blog/enabling-le-audio-lc3-in-wf-1000xm5/</id><summary type="html">&lt;p&gt;One of things that I hate the most about the fact that we are all using
       +wireless earbuds instead of wired earphones is the latency: it is bad, getting
       +up to seconds(!) depending on your particular combination of OS/earbuds/device.&lt;/p&gt;
       +&lt;p&gt;There is a solution though: Bluetooth LE Audio, that is supposed to fix
       +multiple issues with the original design for Bluetooth Classic Audio, including
       +a much lower latency, improved efficiency (e.g.: less battery power) and even
       +multiple streams of audio. LE Audio also includes a new default codec for
       +improved audio quality, &lt;a href="https://en.wikipedia.org/wiki/LC3_(codec)"&gt;LC3&lt;/a&gt;, that
       +replaces the venerable &lt;a href="https://en.wikipedia.org/wiki/SBC_(codec)"&gt;SBC&lt;/a&gt; codec
       +for audio.&lt;/p&gt;
       +&lt;p&gt;However, the standard is a mess right now: a few wireless headphones already
       +support it, but they're generally disabled by default and it is pretty messy to
       +enable. And even after enabling it, getting it to work can be a pain.&lt;/p&gt;
       +&lt;p&gt;I have pretty much the best setup to use LE Audio right now: a recently
       +released Pixel 9 Pro with Sony's
       +&lt;a href="https://www.sony.ie/headphones/products/wf-1000xm5"&gt;WF-1000XM5&lt;/a&gt; earbuds, and
       +after lots of tries I got it to work. You can see below the versions of
       +everything I am using:&lt;/p&gt;
       +&lt;ul&gt;
       +&lt;li&gt;Android: 14&lt;/li&gt;
       +&lt;li&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.sony.songpal.mdr"&gt;Sound
       +Connect&lt;/a&gt;:
       +11.0.1&lt;/li&gt;
       +&lt;li&gt;WM-1000XM5: 4.0.2&lt;/li&gt;
       +&lt;/ul&gt;
       +&lt;p&gt;The first thing you need to do is enable in &amp;quot;Sound Connect&amp;quot; app &amp;quot;LE Audio
       +Priority&amp;quot; in &amp;quot;Device Settings -&amp;gt; System&amp;quot;:&lt;/p&gt;
       +&lt;p&gt;&lt;a href="https://github.com/thiagokokada/blog/raw/main/posts/2024-10-07/photo_4909454744305642922_y.jpg"&gt;&lt;img src="https://github.com/thiagokokada/blog/raw/main/posts/2024-10-07/photo_4909454744305642922_y.jpg" alt="LE Audio option inside Sound
       +Connect"&gt;&lt;/a&gt;&lt;/p&gt;
       +&lt;p&gt;After this, you will need to pair your headset with the device again. You can
       +do this as same as always: press and hold the button in case for a few seconds
       +until a blue light starts to blink. However, this is where things starts to get
       +janky: I couldn't get the headset to pair with Android again.&lt;/p&gt;
       +&lt;p&gt;A few of the things that I needed to do (in no specific order):&lt;/p&gt;
       +&lt;ul&gt;
       +&lt;li&gt;Remove the previous paired headset&lt;/li&gt;
       +&lt;li&gt;Restart the Android&lt;/li&gt;
       +&lt;li&gt;Clean-up &amp;quot;Sound Connect&amp;quot; storage (Long press the app icon -&amp;gt; &amp;quot;App info&amp;quot; -&amp;gt;
       +&amp;quot;Storage and Cache&amp;quot; -&amp;gt; &amp;quot;Clear storage&amp;quot;)&lt;/li&gt;
       +&lt;/ul&gt;
       +&lt;p&gt;If you can get the headset to connect, go to the &amp;quot;Bluetooth&amp;quot; settings in
       +Android, click in the gear icon for the headset and enable &amp;quot;LE Audio&amp;quot; option:&lt;/p&gt;
       +&lt;p&gt;&lt;a href="https://github.com/thiagokokada/blog/raw/main/posts/2024-10-07/photo_4909454744305642937_y.jpg"&gt;&lt;img src="https://github.com/thiagokokada/blog/raw/main/posts/2024-10-07/photo_4909454744305642937_y.jpg" alt="LE Audio option Bluetooth
       +Settings"&gt;&lt;/a&gt;&lt;/p&gt;
       +&lt;p&gt;If you can't, you may want to &lt;a href="https://helpguide.sony.net/mdr/2963/v1/en/contents/TP1000783925.html"&gt;restore the headset to factory
       +settings&lt;/a&gt;
       +and try again from the start (that means pairing your device with &amp;quot;Sound
       +Connect&amp;quot; again, and you may want to try to clear the storage before doing so).&lt;/p&gt;
       +&lt;p&gt;Yes, the process is extremely janky, but I think this is why both &amp;quot;Sound
       +Connect&amp;quot; and Android marks this feature as beta/experimental. And I still need
       +to test the latency, but from my initial testing there are some glitches when
       +the audio is only used for a short period of time (e.g.: Duolingo only enables
       +the audio when the character is speaking). So I only recommend this if you want
       +to test how LE Audio will behave, since it is clear that this needs more
       +polish.&lt;/p&gt;</summary></entry><entry><title>Quick bits: where does Nix store Flake's trusted settings?</title><link href="https://kokada.dev/blog/quick-bits-where-does-nix-store-flakes-trusted-settings/" rel="alternate"/><published>2024-09-30T00:00:00+00:00</published><id>https://kokada.dev/blog/quick-bits-where-does-nix-store-flakes-trusted-settings/</id><summary type="html">&lt;p&gt;Have you ever run a &lt;code&gt;nix build&lt;/code&gt; command and had this prompt?&lt;/p&gt;
       +&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; nix run .#darwinActivations/Sekai-MacBook-Pro
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;do you want to allow configuration setting &amp;#39;extra-substituters&amp;#39; to be set to &amp;#39;https://nix-community.cachix.org https://thiagokokada-nix-configs.cachix.org&amp;#39; (y/N)? y
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;do you want to permanently mark this value as trusted (y/N)? y
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And realise that you did/didn't want to mark this value as trusted? But where
       +is this stored? Well, I had to look at the Nix source code to find the answer,
       +since I can't find this anywhere in the web or in ChatGPT (but I am sure that
       +now that I posted this it will eventually be searchable), and the answer can be
       +found
       +&lt;a href="https://github.com/NixOS/nix/blob/c116030605bf7fecd232d0ff3b6fe066f23e4620/src/libflake/flake/config.cc#L13-L16"&gt;here&lt;/a&gt;:&lt;/p&gt;
       +&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="nf"&gt;trustedListPath&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;getDataDir&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;/trusted-settings.json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Where is &lt;code&gt;getDataDir()&lt;/code&gt; though? I found the answer
       +&lt;a href="https://github.com/NixOS/nix/blob/c116030605bf7fecd232d0ff3b6fe066f23e4620/src/libutil/users.cc#L52-L65"&gt;here&lt;/a&gt;:&lt;/p&gt;
       +&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="nf"&gt;getDataDir&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getEnv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;NIX_DATA_HOME&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;xdgDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getEnv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;XDG_DATA_HOME&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xdgDir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;xdgDir&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;/nix&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;getHome&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;/.local/share/nix&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So we solved the mystery:&lt;/p&gt;
       +&lt;ul&gt;
       +&lt;li&gt;If &lt;code&gt;NIX_DATA_HOME&lt;/code&gt; is set, the file will be in
       +&lt;code&gt;$NIX_DATA_HOME/trusted-settings.json&lt;/code&gt;&lt;/li&gt;
       +&lt;li&gt;If &lt;code&gt;XDG_DATA_HOME&lt;/code&gt; is set, the file will be in
       +&lt;code&gt;$XDG_DATA_HOME/nix/trusted-settings.json&lt;/code&gt;&lt;/li&gt;
       +&lt;li&gt;Otherwise Nix will fallback to &lt;code&gt;$HOME/.local/share/nix/trusted-settings.json&lt;/code&gt;&lt;/li&gt;
       +&lt;/ul&gt;
       +&lt;p&gt;By the way, if you don't know why you got this prompt, if &lt;code&gt;flake.nix&lt;/code&gt; has a
       +&lt;code&gt;nixConfig&lt;/code&gt; attribute inside &lt;code&gt;outputs&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; this &lt;code&gt;nixConfig&lt;/code&gt; is an unsafe
       +attribute (like &lt;code&gt;extra-substituters&lt;/code&gt;) you will get this prompt, unless you set
       +&lt;a href="https://nix.dev/manual/nix/2.23/command-ref/conf-file#conf-accept-flake-config"&gt;&lt;code&gt;accept-flake-config = true&lt;/code&gt;&lt;/a&gt;
       +in your Nix configuration (please &lt;strong&gt;do not do this&lt;/strong&gt;, it is dangerous because
       +it may allow running possible unsafe options without asking you first).&lt;/p&gt;
       +&lt;p&gt;You can inspect the JSON file or delete it and Nix will prompt you again the
       +next time you run a &lt;code&gt;nix&lt;/code&gt; command. And yes, saving this preference is
       +controversial considering this is Nix, but having the power to set &lt;code&gt;nixConfig&lt;/code&gt;
       +attributes is really powerful, and with great powers comes great
       +responsibilities.&lt;/p&gt;</summary></entry><entry><title>My coding experience with LLM</title><link href="https://kokada.dev/blog/my-coding-experience-with-llm/" rel="alternate"/><published>2024-09-02T00:00:00+00:00</published><id>https://kokada.dev/blog/my-coding-experience-with-llm/</id><summary type="html">&lt;p&gt;I don't want to talk about AI. AI fatigue is real, with (garbage) AI content
       +everywhere you go. However, I like to talk about tools, and AIs, or more
       +specifically, &lt;a href="https://en.wikipedia.org/wiki/Large_language_model"&gt;Large Language
       +Models&lt;/a&gt; (LLM), can be
       +really useful tools. Maybe someday we will have our AI overlords dominating
       +everything (including my job), but right now I don't feel particularly
       +threatened given my experience with AIs.&lt;/p&gt;
       +&lt;p&gt;Given that &lt;a href="https://mashable.com/article/google-search-low-quality-research"&gt;Google Search is getting
       +worse&lt;/a&gt;, I am
       +slowly relying in LLMs more and more. This is the focus of this post, basically
       +&lt;a href="https://www.rottentomatoes.com/m/the_good_the_bad_and_the_ugly"&gt;the good, the bad and the
       +ugly&lt;/a&gt; (by the
       +way, never saw this film) of LLMs, especially focused for solving coding
       +problems. I will take a look at the my chat history in
       +&lt;a href="https://chatgpt.com/"&gt;ChatGPT&lt;/a&gt; and see where it was a good tool, where it
       +shined, and where it just completely wasted my time.&lt;/p&gt;
       +&lt;p&gt;A disclaimer, I never bothered to buy a ChatGPT subscription because I don't
       +feel that the tool is useful enough (at least yet), so most of the examples
       +here are either with &lt;a href="https://openai.com/index/chatgpt/"&gt;GPT-3.5&lt;/a&gt; or &lt;a href="https://openai.com/index/gpt-4o-mini-advancing-cost-efficient-intelligence/"&gt;GPT-4o
       +mini&lt;/a&gt;,
       +since those where the models offered by free in ChatGPT.&lt;/p&gt;
       +&lt;p&gt;An addendum, I have some experience with &lt;a href="https://github.com/features/copilot"&gt;GitHub
       +Copilot&lt;/a&gt; (another LLM, but this one runs
       +inside your IDE or favorite text editor) in &lt;code&gt;$PREVIOUS_JOB&lt;/code&gt;. But my experience
       +with it is even more underwhelming than what I am going to describe in this
       +post: it was basically really good for generating fixture for tests and between
       +ok-ish to plain bad for everything else. Yes, that's would fit in a tweet (or
       +xeet?).&lt;/p&gt;
       +&lt;h2&gt;The good&lt;/h2&gt;
       +&lt;p&gt;&lt;a href="https://chatgpt.com/share/c58a1432-2761-4954-acac-cade29942c34"&gt;Chat history&lt;/a&gt;.&lt;/p&gt;
       +&lt;blockquote&gt;
       +&lt;p&gt;Is there any way that I can pass a context for a net.conn to cancel its
       +Read()?&lt;/p&gt;
       +&lt;/blockquote&gt;
       +&lt;p&gt;This is one of the good cases where ChatGPT felt to me that I was talking with
       +an expert in Go. To start, I didn't even mention in my initial prompt that I
       +was talking about Go, but it correctly inferred so. Also, the solution overview
       +was great:&lt;/p&gt;
       +&lt;blockquote&gt;
       +&lt;ol&gt;
       +&lt;li&gt;&lt;strong&gt;Use a separate goroutine&lt;/strong&gt; to handle the context cancellation.&lt;/li&gt;
       +&lt;li&gt;&lt;strong&gt;Set a deadline&lt;/strong&gt; on the connection using &lt;code&gt;SetReadDeadline()&lt;/code&gt; to unblock
       +the &lt;code&gt;Read()&lt;/code&gt; when the context is canceled.&lt;/li&gt;
       +&lt;/ol&gt;
       +&lt;/blockquote&gt;
       +&lt;p&gt;Before asking ChatGPT about this issue I had already coded my own naive
       +solution that was something similar to this:&lt;/p&gt;
       +&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="c1"&gt;// ...
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;    &lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}()&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="c1"&gt;// ...
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Compared this solution with the one from ChatGPT:&lt;/p&gt;
       +&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;readWithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;conn&lt;/span&gt; &lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="c1"&gt;// Start a goroutine to perform the read
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}()&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="c1"&gt;// Context was canceled or timed out
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;        &lt;span class="c1"&gt;// Set a short deadline to unblock the Read()
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;        &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="c1"&gt;// Wait for the read to finish
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// Read finished successfully
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The ChatGPT version is much better because:&lt;/p&gt;
       +&lt;ol&gt;
       +&lt;li&gt;It doesn't close the connection socket allowing it to be reused&lt;/li&gt;
       +&lt;li&gt;It waits until the goroutine is finished to avoid leaks&lt;/li&gt;
       +&lt;li&gt;It closes the channel after it finishes&lt;/li&gt;
       +&lt;/ol&gt;
       +&lt;p&gt;Now, I don't claim to be a Go expert (far from it), but this was one of those
       +cases where I felt that I was being guided by someone that is coding in Go for
       +years.&lt;/p&gt;
       +&lt;p&gt;But it didn't end there, I asked:&lt;/p&gt;
       +&lt;blockquote&gt;
       +&lt;p&gt;If I want to reuse the connection, do I need to reset the SetReadDeadline?&lt;/p&gt;
       +&lt;/blockquote&gt;
       +&lt;p&gt;Since in this particular case I wanted the underlying connection to be reused,
       +and ChatGPT correctly amended the code:&lt;/p&gt;
       +&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;readWithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;conn&lt;/span&gt; &lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="c1"&gt;// Same as before
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="c1"&gt;// Context was canceled or timed out
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;        &lt;span class="c1"&gt;// Set a short deadline to unblock the Read()
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;        &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="c1"&gt;// Wait for the read to finish
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="c1"&gt;// Reset the deadline so the connection can be reused
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;        &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;// Read finished successfully
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Also the explanation on why this happens was good:&lt;/p&gt;
       +&lt;blockquote&gt;
       +&lt;p&gt;When you set a read deadline with &lt;code&gt;conn.SetReadDeadline(time.Now())&lt;/code&gt; to unblock
       +the &lt;code&gt;Read()&lt;/code&gt; call, this deadline remains in effect for future &lt;code&gt;Read()&lt;/code&gt;
       +operations. This means that if you attempt another read operation after this,
       +it could immediately fail with a timeout error if the deadline is still in
       +effect.
       +To reuse the connection, you'll need to remove the deadline or set a new one.
       +You can do this by calling &lt;code&gt;conn.SetReadDeadline(time.Time{})&lt;/code&gt;, which clears
       +any existing deadline.&lt;/p&gt;
       +&lt;/blockquote&gt;
       +&lt;p&gt;I had one last question that I kind already knew the answer:&lt;/p&gt;
       +&lt;blockquote&gt;
       +&lt;p&gt;Do we need to defer the clearing?&lt;/p&gt;
       +&lt;/blockquote&gt;
       +&lt;p&gt;And ChatGPT correctly returned:&lt;/p&gt;
       +&lt;blockquote&gt;
       +&lt;p&gt;Whether you need to defer the clearing of the read deadline depends on how
       +your code is structured. If you want to ensure that the read deadline is
       +always cleared after a context cancellation, even if the code panics or exits
       +early, then deferring the &lt;code&gt;conn.SetReadDeadline(time.Time{})&lt;/code&gt; call is a good
       +idea.&lt;/p&gt;
       +&lt;/blockquote&gt;
       +&lt;p&gt;This whole interaction was one of the best ones I ever had in ChatGPT, one that
       +it gave me an actual functional code with good explanation on what was
       +happening. But still, it didn't talked at all about the gotcha of setting the
       +read deadline and reusing the underlying connection, needing another prompt to
       +give me this information.&lt;/p&gt;
       +&lt;p&gt;Also, there is one issue in ChatGPT solution though: we are discarding the
       +values of the buffer once the context is done by returning &lt;code&gt;n = 0&lt;/code&gt; instead of
       +the number of bytes read. In this particular case this is what I wanted, but
       +this is a possible issue that ChatGPT didn't talk.&lt;/p&gt;
       +&lt;p&gt;For comparison,
       +&lt;a href="https://stackoverflow.com/questions/61637359/how-to-use-context-context-with-tcp-connection-read"&gt;this&lt;/a&gt;
       +is the best that I got searching in both DuckDuckGo and Google, that is where I
       +kind based my first solution on. I still not sure where ChatGPT could give me
       +such a good answer for this question, because I just couldn't find anything
       +remotely similar during my searches.&lt;/p&gt;
       +&lt;h2&gt;The amazing&lt;/h2&gt;
       +&lt;p&gt;&lt;a href="https://chatgpt.com/share/0c9a148f-4cfd-4b4e-aa84-7486e185125b"&gt;Chat history&lt;/a&gt;.&lt;/p&gt;
       +&lt;blockquote&gt;
       +&lt;p&gt;I want to write an extension to &lt;a href="https://github.com/yuin/goldmark/"&gt;https://github.com/yuin/goldmark/&lt;/a&gt; that allows
       +me to rewrite &lt;code&gt;[link](../2024-07-30/post.md)&lt;/code&gt; to
       +&lt;code&gt;[link](https://kokada.capivaras.dev/slug)&lt;/code&gt;&lt;/p&gt;
       +&lt;/blockquote&gt;
       +&lt;p&gt;Here is the generated code:&lt;/p&gt;
       +&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nx"&gt;linkrewriter&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="s"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="s"&gt;&amp;#34;path&amp;#34;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="s"&gt;&amp;#34;strings&amp;#34;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="s"&gt;&amp;#34;github.com/yuin/goldmark&amp;#34;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="s"&gt;&amp;#34;github.com/yuin/goldmark/ast&amp;#34;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="s"&gt;&amp;#34;github.com/yuin/goldmark/parser&amp;#34;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="s"&gt;&amp;#34;github.com/yuin/goldmark/renderer&amp;#34;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="s"&gt;&amp;#34;github.com/yuin/goldmark/util&amp;#34;&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// LinkRewriter is the main struct for your extension
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;LinkRewriter&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// NewLinkRewriter returns a new instance of LinkRewriter
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;NewLinkRewriter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;LinkRewriter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;LinkRewriter&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Extend will be called by Goldmark to add your extension
       +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;LinkRewriter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;Extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="nx"&gt;goldmark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Markdown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;AddOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithASTTransformers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Prioritized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
       +&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Transform is the method that modifies the AST
codemadness.org:70 /git/sfeed_tests/commit/627538879a243435de10999fae80626ea58eea86.gph:500: line too long