URI:
       kokada.dev.rss.xml - 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
       ---
       kokada.dev.rss.xml (494372B)
       ---
            1 <?xml version="1.0" encoding="utf-8"?>
            2 <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>kokada</title><link>https://kokada.dev</link><description>
            3 # dd if=/dev/urandom of=/dev/brain0
            4 dd: error writing &amp;#39;/dev/brain0&amp;#39;: No space left on device
            5 
            6 </description><atom:link href="https://kokada.dev/rss/" rel="self"/><language>en-us</language><lastBuildDate>Wed, 04 Dec 2024 00:00:00 +0000</lastBuildDate><item><title>Praise to scdoc to generate man pages</title><link>https://kokada.dev/blog/praise-to-scdoc-to-generate-man-pages/</link><description>&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
            7 post&lt;/a&gt;. It is mostly
            8 because I ran out of things to write, but I expected this. This is probably
            9 more likely how I am actually going to post from now. At least, it shows that
           10 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
           11 time&lt;/a&gt;, that is
           12 easy to go back when I wanted is working fine, but I digress.&lt;/p&gt;
           13 &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
           14 page&lt;/a&gt; for the first time in years. I
           15 hate &lt;a href="https://en.wikipedia.org/wiki/Troff"&gt;troff&lt;/a&gt;, the typesetting system used
           16 for man pages (similar to &lt;a href="https://en.wikipedia.org/wiki/LaTeX"&gt;LaTeX&lt;/a&gt; for
           17 documents). It is one of the weirdest languages that I ever saw, and even the
           18 example in Wikipedia shows that:&lt;/p&gt;
           19 &lt;pre&gt;&lt;code class="language-troff"&gt;.ND &amp;quot;January 10, 1993&amp;quot;
           20 .AU &amp;quot;Ms. Jane Smith&amp;quot;
           21 .AT &amp;quot;Upcoming appointment&amp;quot;
           22 .MT 5
           23 .DS
           24 Reference #A12345
           25 .sp 4
           26 Mr. Samuel Jones
           27 Field director, Bureau of Inspections
           28 1010 Government Plaza
           29 Capitoltown, ST
           30 .sp 3
           31 Dear Mr. Jones,
           32 .sp 2
           33 .P
           34 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
           35 .B now ,
           36 in
           37 .I this
           38 year of
           39 .I this
           40 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.
           41 .P
           42 Thank you for your consideration of our position.
           43 .FC Sincerely
           44 .SG
           45 &lt;/code&gt;&lt;/pre&gt;
           46 &lt;p&gt;Keep in mind that the break lines are necessary every time you introduce a
           47 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
           48 as illegible as hell, and it is worse that the format lacks good tooling (or at
           49 least I didn't find any good ones).&lt;/p&gt;
           50 &lt;p&gt;Most people when they need to write a man page nowadays ends up using some
           51 other format that generates a man page. For example, in the past I used
           52 &lt;a href="https://pandoc.org/"&gt;Pandoc&lt;/a&gt; to convert Markdown to a man page, but even if
           53 Pandoc is a great project the result is sub-optimal at best: Markdowns are, at
           54 the end, designed for generating HTML (and a subset of it), and not man pages,
           55 so you basically ends up fighting the format for it to do what you want.
           56 Also, Pandoc is a big project, with a ~200MB binary (at least it is the default
           57 Pandoc binary in Nix).&lt;/p&gt;
           58 &lt;p&gt;For this specific project I needed something small. I am trying to replace one
           59 of the most essential pieces inside NixOS, &lt;code&gt;nixos-rebuild&lt;/code&gt;, written in Bash,
           60 with a &lt;a href="https://discourse.nixos.org/t/nixos-rebuild-ng-a-nixos-rebuild-rewrite/55606/"&gt;full rewritten in
           61 Python&lt;/a&gt;
           62 (sorry Rust zealots!), called &lt;code&gt;nixos-rebuild-ng&lt;/code&gt;.&lt;/p&gt;
           63 &lt;p&gt;Since this project will eventually (if successful) be in the critical path for
           64 NixOS, I want to reduce the number of dependencies as much as possible, so
           65 something as big as Pandoc is out. I could use
           66 &lt;a href="https://asciidoc.org/"&gt;AsciiDoc&lt;/a&gt;, but it is a big complicated Python project
           67 (this may seem ironic, but &lt;code&gt;nixos-rebuild-ng&lt;/code&gt; has only one runtime dependency,
           68 that is optional). And I also hated the last time I tried to use it to generate
           69 man pages: it more flexible than Markdown, but still far from optimal.&lt;/p&gt;
           70 &lt;p&gt;Thanks to Drew DeVault (creator of &lt;a href="https://swaywm.org/"&gt;SwayWM&lt;/a&gt;) that seems it
           71 had the same issues in the past and created
           72 &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
           73 page generator using a DSL inspired in Markdown, but specific to generate man
           74 pages. The binary is written in C (and advantage in this case since it means it
           75 is easier to bootstrap), is small (~1 Kloc) and has no dependencies, so it
           76 fits the requirement.&lt;/p&gt;
           77 &lt;p&gt;While the language suffers from being a niche project for a niche segment, the
           78 &lt;a href="https://man.archlinux.org/man/scdoc.5.en"&gt;man page&lt;/a&gt; for it is actually really
           79 nice. It is terse though and lacks examples, and this is what this blog post
           80 will try to accomplish.&lt;/p&gt;
           81 &lt;p&gt;To start, let's have a quick summary of the syntax, written in &lt;code&gt;scdoc&lt;/code&gt; as
           82 comments:&lt;/p&gt;
           83 &lt;pre&gt;&lt;code class="language-scdoc"&gt;; quick summary:
           84 ; # new section
           85 ; comments starts with ;
           86 ; - this is a list
           87 ;         - sub-list
           88 ; - *bold*: _underline_, force a line break++
           89 ; - [tables], \[ can be used to force an actual [
           90 ; . numbered list
           91 ; please configure your editor to use hard tabs
           92 ; see `man 5 scdoc` for more information about syntax
           93 ; or https://man.archlinux.org/man/scdoc.5.en
           94 &lt;/code&gt;&lt;/pre&gt;
           95 &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
           96 I wrote, so it is easy for someone that never saw the format to start
           97 collaborating.&lt;/p&gt;
           98 &lt;p&gt;And here an example of a (summarised) man page in &lt;code&gt;.scd&lt;/code&gt; format:&lt;/p&gt;
           99 &lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nixos-rebuild-ng(8)
          100 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          101 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# NAME
          102 &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;
          103 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nixos-rebuild - reconfigure a NixOS machine
          104 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          105 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# SYNOPSIS
          106 &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;
          107 &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]++
          108 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;                \[{switch,boot}]
          109 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          110 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# DESCRIPTION
          111 &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;
          112 &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.
          113 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;It must be one of the following:
          114 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          115 &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;
          116 &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.
          117 &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
          118 &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
          119 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        into the new configuration. Previous configurations activated with
          120 &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
          121 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        menu.
          122 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          123 &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;
          124 &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
          125 &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
          126 &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.
          127 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          128 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# OPTIONS
          129 &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;
          130 &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;
          131 &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
          132 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        system.
          133 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          134 &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
          135 &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
          136 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        also be updated.
          137 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          138 &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.
          139 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          140 &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.
          141 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          142 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# ENVIRONMENT
          143 &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;
          144 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NIXOS_CONFIG
          145 &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
          146 &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;.
          147 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          148 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# FILES
          149 &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;
          150 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/etc/nixos/flake.nix
          151 &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
          152 &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
          153 &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
          154 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        flake.
          155 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          156 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# AUTHORS
          157 &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;
          158 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Nixpkgs/NixOS contributors
          159 &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;
          160 &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
          161 file"&gt;&lt;/a&gt;&lt;/p&gt;
          162 &lt;p&gt;One of nice things that I found is how looking at the plain text looks kind
          163 like the man page result already. And if you know Markdown, you can basically
          164 understand most things that is happening. There are a few differences, like
          165 &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
          166 end of the world.&lt;/p&gt;
          167 &lt;p&gt;Now, the format has its quirks. The first line being the name of the program
          168 and section in parenthesis is required, but this makes sense, since you need
          169 this information for the corners. But for one, it requires the usage of hard
          170 tabs to create indentation, and the error messages are awful, in a situation
          171 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
          172 means that the traditional &lt;code&gt;app [command]&lt;/code&gt; needs in many cases to be escaped as
          173 &lt;code&gt;app \[command]&lt;/code&gt;. I found this a strange choice since this is supposed to be a
          174 format that is only used for man pages, and using &lt;code&gt;[command]&lt;/code&gt; to indicate an
          175 optional is common, but at least it is easy to escape.&lt;/p&gt;
          176 &lt;p&gt;In the end, I think all that matters is the result. And for the first time for
          177 all those years trying to write a man page, I am satisfied with the result. The
          178 man page looks exactly as I wanted once rendered, and the &lt;code&gt;.scd&lt;/code&gt; file looks
          179 reasonable good that it can work as a documentation for someone that for one
          180 reason or another can't use the man page (can't say the same for the troff
          181 version). Also, it is really easy for someone to just go there and update the
          182 man page, even without experience in the format (except for maybe the
          183 requirement of tabs). So all in all, I really liked the format, and will use it
          184 again if I need to write another man page in the future.&lt;/p&gt;</description><pubDate>Wed, 04 Dec 2024 00:00:00 +0000</pubDate><guid>https://kokada.dev/blog/praise-to-scdoc-to-generate-man-pages/</guid></item><item><title>Enabling LE Audio/LC3 in WF-1000XM5</title><link>https://kokada.dev/blog/enabling-le-audio-lc3-in-wf-1000xm5/</link><description>&lt;p&gt;One of things that I hate the most about the fact that we are all using
          185 wireless earbuds instead of wired earphones is the latency: it is bad, getting
          186 up to seconds(!) depending on your particular combination of OS/earbuds/device.&lt;/p&gt;
          187 &lt;p&gt;There is a solution though: Bluetooth LE Audio, that is supposed to fix
          188 multiple issues with the original design for Bluetooth Classic Audio, including
          189 a much lower latency, improved efficiency (e.g.: less battery power) and even
          190 multiple streams of audio. LE Audio also includes a new default codec for
          191 improved audio quality, &lt;a href="https://en.wikipedia.org/wiki/LC3_(codec)"&gt;LC3&lt;/a&gt;, that
          192 replaces the venerable &lt;a href="https://en.wikipedia.org/wiki/SBC_(codec)"&gt;SBC&lt;/a&gt; codec
          193 for audio.&lt;/p&gt;
          194 &lt;p&gt;However, the standard is a mess right now: a few wireless headphones already
          195 support it, but they're generally disabled by default and it is pretty messy to
          196 enable. And even after enabling it, getting it to work can be a pain.&lt;/p&gt;
          197 &lt;p&gt;I have pretty much the best setup to use LE Audio right now: a recently
          198 released Pixel 9 Pro with Sony's
          199 &lt;a href="https://www.sony.ie/headphones/products/wf-1000xm5"&gt;WF-1000XM5&lt;/a&gt; earbuds, and
          200 after lots of tries I got it to work. You can see below the versions of
          201 everything I am using:&lt;/p&gt;
          202 &lt;ul&gt;
          203 &lt;li&gt;Android: 14&lt;/li&gt;
          204 &lt;li&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.sony.songpal.mdr"&gt;Sound
          205 Connect&lt;/a&gt;:
          206 11.0.1&lt;/li&gt;
          207 &lt;li&gt;WM-1000XM5: 4.0.2&lt;/li&gt;
          208 &lt;/ul&gt;
          209 &lt;p&gt;The first thing you need to do is enable in &amp;quot;Sound Connect&amp;quot; app &amp;quot;LE Audio
          210 Priority&amp;quot; in &amp;quot;Device Settings -&amp;gt; System&amp;quot;:&lt;/p&gt;
          211 &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
          212 Connect"&gt;&lt;/a&gt;&lt;/p&gt;
          213 &lt;p&gt;After this, you will need to pair your headset with the device again. You can
          214 do this as same as always: press and hold the button in case for a few seconds
          215 until a blue light starts to blink. However, this is where things starts to get
          216 janky: I couldn't get the headset to pair with Android again.&lt;/p&gt;
          217 &lt;p&gt;A few of the things that I needed to do (in no specific order):&lt;/p&gt;
          218 &lt;ul&gt;
          219 &lt;li&gt;Remove the previous paired headset&lt;/li&gt;
          220 &lt;li&gt;Restart the Android&lt;/li&gt;
          221 &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;
          222 &amp;quot;Storage and Cache&amp;quot; -&amp;gt; &amp;quot;Clear storage&amp;quot;)&lt;/li&gt;
          223 &lt;/ul&gt;
          224 &lt;p&gt;If you can get the headset to connect, go to the &amp;quot;Bluetooth&amp;quot; settings in
          225 Android, click in the gear icon for the headset and enable &amp;quot;LE Audio&amp;quot; option:&lt;/p&gt;
          226 &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
          227 Settings"&gt;&lt;/a&gt;&lt;/p&gt;
          228 &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
          229 settings&lt;/a&gt;
          230 and try again from the start (that means pairing your device with &amp;quot;Sound
          231 Connect&amp;quot; again, and you may want to try to clear the storage before doing so).&lt;/p&gt;
          232 &lt;p&gt;Yes, the process is extremely janky, but I think this is why both &amp;quot;Sound
          233 Connect&amp;quot; and Android marks this feature as beta/experimental. And I still need
          234 to test the latency, but from my initial testing there are some glitches when
          235 the audio is only used for a short period of time (e.g.: Duolingo only enables
          236 the audio when the character is speaking). So I only recommend this if you want
          237 to test how LE Audio will behave, since it is clear that this needs more
          238 polish.&lt;/p&gt;</description><pubDate>Mon, 07 Oct 2024 00:00:00 +0000</pubDate><guid>https://kokada.dev/blog/enabling-le-audio-lc3-in-wf-1000xm5/</guid></item><item><title>Quick bits: where does Nix store Flake's trusted settings?</title><link>https://kokada.dev/blog/quick-bits-where-does-nix-store-flakes-trusted-settings/</link><description>&lt;p&gt;Have you ever run a &lt;code&gt;nix build&lt;/code&gt; command and had this prompt?&lt;/p&gt;
          239 &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
          240 &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
          241 &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
          242 &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
          243 is this stored? Well, I had to look at the Nix source code to find the answer,
          244 since I can't find this anywhere in the web or in ChatGPT (but I am sure that
          245 now that I posted this it will eventually be searchable), and the answer can be
          246 found
          247 &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;
          248 &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;
          249 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          250 &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;
          251 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          252 &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
          253 &lt;a href="https://github.com/NixOS/nix/blob/c116030605bf7fecd232d0ff3b6fe066f23e4620/src/libutil/users.cc#L52-L65"&gt;here&lt;/a&gt;:&lt;/p&gt;
          254 &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;
          255 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          256 &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;
          257 &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;
          258 &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;
          259 &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;
          260 &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;
          261 &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;
          262 &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;
          263 &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;
          264 &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;
          265 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
          266 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
          267 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          268 &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So we solved the mystery:&lt;/p&gt;
          269 &lt;ul&gt;
          270 &lt;li&gt;If &lt;code&gt;NIX_DATA_HOME&lt;/code&gt; is set, the file will be in
          271 &lt;code&gt;$NIX_DATA_HOME/trusted-settings.json&lt;/code&gt;&lt;/li&gt;
          272 &lt;li&gt;If &lt;code&gt;XDG_DATA_HOME&lt;/code&gt; is set, the file will be in
          273 &lt;code&gt;$XDG_DATA_HOME/nix/trusted-settings.json&lt;/code&gt;&lt;/li&gt;
          274 &lt;li&gt;Otherwise Nix will fallback to &lt;code&gt;$HOME/.local/share/nix/trusted-settings.json&lt;/code&gt;&lt;/li&gt;
          275 &lt;/ul&gt;
          276 &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
          277 &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
          278 attribute (like &lt;code&gt;extra-substituters&lt;/code&gt;) you will get this prompt, unless you set
          279 &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;
          280 in your Nix configuration (please &lt;strong&gt;do not do this&lt;/strong&gt;, it is dangerous because
          281 it may allow running possible unsafe options without asking you first).&lt;/p&gt;
          282 &lt;p&gt;You can inspect the JSON file or delete it and Nix will prompt you again the
          283 next time you run a &lt;code&gt;nix&lt;/code&gt; command. And yes, saving this preference is
          284 controversial considering this is Nix, but having the power to set &lt;code&gt;nixConfig&lt;/code&gt;
          285 attributes is really powerful, and with great powers comes great
          286 responsibilities.&lt;/p&gt;</description><pubDate>Mon, 30 Sep 2024 00:00:00 +0000</pubDate><guid>https://kokada.dev/blog/quick-bits-where-does-nix-store-flakes-trusted-settings/</guid></item><item><title>My coding experience with LLM</title><link>https://kokada.dev/blog/my-coding-experience-with-llm/</link><description>&lt;p&gt;I don't want to talk about AI. AI fatigue is real, with (garbage) AI content
          287 everywhere you go. However, I like to talk about tools, and AIs, or more
          288 specifically, &lt;a href="https://en.wikipedia.org/wiki/Large_language_model"&gt;Large Language
          289 Models&lt;/a&gt; (LLM), can be
          290 really useful tools. Maybe someday we will have our AI overlords dominating
          291 everything (including my job), but right now I don't feel particularly
          292 threatened given my experience with AIs.&lt;/p&gt;
          293 &lt;p&gt;Given that &lt;a href="https://mashable.com/article/google-search-low-quality-research"&gt;Google Search is getting
          294 worse&lt;/a&gt;, I am
          295 slowly relying in LLMs more and more. This is the focus of this post, basically
          296 &lt;a href="https://www.rottentomatoes.com/m/the_good_the_bad_and_the_ugly"&gt;the good, the bad and the
          297 ugly&lt;/a&gt; (by the
          298 way, never saw this film) of LLMs, especially focused for solving coding
          299 problems. I will take a look at the my chat history in
          300 &lt;a href="https://chatgpt.com/"&gt;ChatGPT&lt;/a&gt; and see where it was a good tool, where it
          301 shined, and where it just completely wasted my time.&lt;/p&gt;
          302 &lt;p&gt;A disclaimer, I never bothered to buy a ChatGPT subscription because I don't
          303 feel that the tool is useful enough (at least yet), so most of the examples
          304 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
          305 mini&lt;/a&gt;,
          306 since those where the models offered by free in ChatGPT.&lt;/p&gt;
          307 &lt;p&gt;An addendum, I have some experience with &lt;a href="https://github.com/features/copilot"&gt;GitHub
          308 Copilot&lt;/a&gt; (another LLM, but this one runs
          309 inside your IDE or favorite text editor) in &lt;code&gt;$PREVIOUS_JOB&lt;/code&gt;. But my experience
          310 with it is even more underwhelming than what I am going to describe in this
          311 post: it was basically really good for generating fixture for tests and between
          312 ok-ish to plain bad for everything else. Yes, that's would fit in a tweet (or
          313 xeet?).&lt;/p&gt;
          314 &lt;h2&gt;The good&lt;/h2&gt;
          315 &lt;p&gt;&lt;a href="https://chatgpt.com/share/c58a1432-2761-4954-acac-cade29942c34"&gt;Chat history&lt;/a&gt;.&lt;/p&gt;
          316 &lt;blockquote&gt;
          317 &lt;p&gt;Is there any way that I can pass a context for a net.conn to cancel its
          318 Read()?&lt;/p&gt;
          319 &lt;/blockquote&gt;
          320 &lt;p&gt;This is one of the good cases where ChatGPT felt to me that I was talking with
          321 an expert in Go. To start, I didn't even mention in my initial prompt that I
          322 was talking about Go, but it correctly inferred so. Also, the solution overview
          323 was great:&lt;/p&gt;
          324 &lt;blockquote&gt;
          325 &lt;ol&gt;
          326 &lt;li&gt;&lt;strong&gt;Use a separate goroutine&lt;/strong&gt; to handle the context cancellation.&lt;/li&gt;
          327 &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
          328 the &lt;code&gt;Read()&lt;/code&gt; when the context is canceled.&lt;/li&gt;
          329 &lt;/ol&gt;
          330 &lt;/blockquote&gt;
          331 &lt;p&gt;Before asking ChatGPT about this issue I had already coded my own naive
          332 solution that was something similar to this:&lt;/p&gt;
          333 &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;
          334 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="c1"&gt;// ...
          335 &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;
          336 &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;
          337 &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;
          338 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          339 &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;
          340 &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;
          341 &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;
          342 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}()&lt;/span&gt;
          343 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          344 &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;
          345 &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;
          346 &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;
          347 &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;
          348 &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;
          349 &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;
          350 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
          351 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="c1"&gt;// ...
          352 &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;
          353 &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;
          354 &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;
          355 &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;
          356 &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;
          357 &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;
          358 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          359 &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
          360 &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;
          361 &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;
          362 &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;
          363 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}()&lt;/span&gt;
          364 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          365 &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;
          366 &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
          367 &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()
          368 &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;
          369 &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
          370 &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;
          371 &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
          372 &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;
          373 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
          374 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          375 &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;
          376 &lt;ol&gt;
          377 &lt;li&gt;It doesn't close the connection socket allowing it to be reused&lt;/li&gt;
          378 &lt;li&gt;It waits until the goroutine is finished to avoid leaks&lt;/li&gt;
          379 &lt;li&gt;It closes the channel after it finishes&lt;/li&gt;
          380 &lt;/ol&gt;
          381 &lt;p&gt;Now, I don't claim to be a Go expert (far from it), but this was one of those
          382 cases where I felt that I was being guided by someone that is coding in Go for
          383 years.&lt;/p&gt;
          384 &lt;p&gt;But it didn't end there, I asked:&lt;/p&gt;
          385 &lt;blockquote&gt;
          386 &lt;p&gt;If I want to reuse the connection, do I need to reset the SetReadDeadline?&lt;/p&gt;
          387 &lt;/blockquote&gt;
          388 &lt;p&gt;Since in this particular case I wanted the underlying connection to be reused,
          389 and ChatGPT correctly amended the code:&lt;/p&gt;
          390 &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;
          391 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="c1"&gt;// Same as before
          392 &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;
          393 &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
          394 &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()
          395 &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;
          396 &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
          397 &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;
          398 &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
          399 &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;
          400 &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;
          401 &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
          402 &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;
          403 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
          404 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          405 &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;
          406 &lt;blockquote&gt;
          407 &lt;p&gt;When you set a read deadline with &lt;code&gt;conn.SetReadDeadline(time.Now())&lt;/code&gt; to unblock
          408 the &lt;code&gt;Read()&lt;/code&gt; call, this deadline remains in effect for future &lt;code&gt;Read()&lt;/code&gt;
          409 operations. This means that if you attempt another read operation after this,
          410 it could immediately fail with a timeout error if the deadline is still in
          411 effect.
          412 To reuse the connection, you'll need to remove the deadline or set a new one.
          413 You can do this by calling &lt;code&gt;conn.SetReadDeadline(time.Time{})&lt;/code&gt;, which clears
          414 any existing deadline.&lt;/p&gt;
          415 &lt;/blockquote&gt;
          416 &lt;p&gt;I had one last question that I kind already knew the answer:&lt;/p&gt;
          417 &lt;blockquote&gt;
          418 &lt;p&gt;Do we need to defer the clearing?&lt;/p&gt;
          419 &lt;/blockquote&gt;
          420 &lt;p&gt;And ChatGPT correctly returned:&lt;/p&gt;
          421 &lt;blockquote&gt;
          422 &lt;p&gt;Whether you need to defer the clearing of the read deadline depends on how
          423 your code is structured. If you want to ensure that the read deadline is
          424 always cleared after a context cancellation, even if the code panics or exits
          425 early, then deferring the &lt;code&gt;conn.SetReadDeadline(time.Time{})&lt;/code&gt; call is a good
          426 idea.&lt;/p&gt;
          427 &lt;/blockquote&gt;
          428 &lt;p&gt;This whole interaction was one of the best ones I ever had in ChatGPT, one that
          429 it gave me an actual functional code with good explanation on what was
          430 happening. But still, it didn't talked at all about the gotcha of setting the
          431 read deadline and reusing the underlying connection, needing another prompt to
          432 give me this information.&lt;/p&gt;
          433 &lt;p&gt;Also, there is one issue in ChatGPT solution though: we are discarding the
          434 values of the buffer once the context is done by returning &lt;code&gt;n = 0&lt;/code&gt; instead of
          435 the number of bytes read. In this particular case this is what I wanted, but
          436 this is a possible issue that ChatGPT didn't talk.&lt;/p&gt;
          437 &lt;p&gt;For comparison,
          438 &lt;a href="https://stackoverflow.com/questions/61637359/how-to-use-context-context-with-tcp-connection-read"&gt;this&lt;/a&gt;
          439 is the best that I got searching in both DuckDuckGo and Google, that is where I
          440 kind based my first solution on. I still not sure where ChatGPT could give me
          441 such a good answer for this question, because I just couldn't find anything
          442 remotely similar during my searches.&lt;/p&gt;
          443 &lt;h2&gt;The amazing&lt;/h2&gt;
          444 &lt;p&gt;&lt;a href="https://chatgpt.com/share/0c9a148f-4cfd-4b4e-aa84-7486e185125b"&gt;Chat history&lt;/a&gt;.&lt;/p&gt;
          445 &lt;blockquote&gt;
          446 &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
          447 me to rewrite &lt;code&gt;[link](../2024-07-30/post.md)&lt;/code&gt; to
          448 &lt;code&gt;[link](https://kokada.capivaras.dev/slug)&lt;/code&gt;&lt;/p&gt;
          449 &lt;/blockquote&gt;
          450 &lt;p&gt;Here is the generated code:&lt;/p&gt;
          451 &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;
          452 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          453 &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;
          454 &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;
          455 &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;
          456 &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;
          457 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          458 &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;
          459 &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;
          460 &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;
          461 &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;
          462 &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;
          463 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          464 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          465 &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
          466 &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;
          467 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          468 &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
          469 &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;
          470 &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;
          471 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          472 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          473 &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
          474 &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;
          475 &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;
          476 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          477 &lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
          478 &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/file/input/sfeed/realworld/kokada.dev.rss.xml.gph:489: line too long