<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Todd's blog</title>
  <id>/atom.xml</id>
  <updated>2025-07-11T00:00:00Z</updated>
  <link href="http://example.org/" />
  <link href="http://example.org/atom.xml" rel="self" />
  <author>
    <name>Todd Martin</name>
    <email>kj4ntv@gmail.com</email>
  </author>
  <subtitle type="text">For software engineering and technology</subtitle>
  
  <entry>
    <title type="text">SpellBook - An Elixir Story</title>
    <id>/post/spellbook-elixir/</id>
    <updated>2025-07-11T00:00:00Z</updated>
    <published>2025-07-11T00:00:00Z</published>
    <link href="http://example.org/post/spellbook-elixir/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>Lately, I have been wanting to finally wanting to dive deep into a dynamic language. In the past, I have written a little about Ruby because of Ruby On Rails. While I do like Ruby on Rails, I am not exactly a huge fan of Ruby. It is not bad, but it will still missing something. I have heard quiet a bit about Elixir, but never thought about it until recently. It is a dynamic language like Ruby, but with more a more functional nature. There is also some overlap in the Rust and Elixir fans. So I decided to give it a go being since I do like Rust and Swift, with Swift having some overlap in language features and concept with Rust. Also, I had heard some great things about Phoenix, a web framework inspired by Ruby on Rails, but in Elixir.</p>
<p>At first glance, Elixir looked pretty nice. But you can&#x27;t really get a feel for a language until you actually start to use it for something. So, being as there is homebrew written in Ruby, I decided to embark on a project to make a little system package manager in Elixir.</p>
<h1 id="why-a-package-manager-">Why a package manager?</h1>
<p>First a foremost, it has been something I&#x27;ve wanted to try my hand at for a long time. Since I was a young lad trying to bumble my way through LFS (Linux From Scratch). Outside of just doing <code>apt install</code> or <code>yum install</code> or <code>pacman -Ss</code>, I hadn&#x27;t looked too deeply in package management at the time until LFS and also subsequently checking out Slackware. But that was many moons ago. But, seems like a fun project for Elixir.</p>
<p>Also, as noted, I have a little experience packaging software. In the past, I packaged, or wrote a port in the ports tree, for a few packages in Ravenports (I have some articles about this). Not too long ago, I packaged comtrya for homebrew. You can learn a lot about software development and software by packaging. Just seems like the next level to go for learning more about packaging and distributing software on UNIX-y systems is to now write my own package manager.</p>
<p>In comes <code>spellbook</code>. A witch-y theme package manager written in elixir.</p>
<h1 id="what-do-i-want-it-to-do-">What do I want it to do?</h1>
<p>Alright, so now, what does it need to do? Well quiet a bit of it, for anyone with experience using a system package manager, is obvious. It needs to install, uninstall, and search for software. That is kind of the low hanging fruit, so I won&#x27;t spend much time on that. But specifically how do I want it to do these things?</p>
<p>Right now, I have mostly only thought through the installing. I want to have a ports tree. For those not familiar, a ports tree is a directory of recipies for building packages from source. These recipies cover things like downloading a package&#x27;s source code and then building it from source. So right now, I am ignoring installing binaries from a repository or grabbing binaries from github or other source. I am putting that off to later. So right now, it will be limited to building from source.</p>
<p>Okay, homebrew kind of does this! First, so what. Technically this is a &quot;competitor&quot; with homebrew, but I am mostly doing this out of fun and for learning. But, there is a future feature that I want to support that it doesn&#x27;t look like homebrew has. But, it is a feature of Ravenports. As a side tangent, I would love to use Ravenports on macOS (my daily driver now), but it can&#x27;t support any newer versions because Ravenports relies on nullfs, which is no longer very viable on macOS. At least that is what I remember when I was looking into a few years ago. But that feature is the concept of variants.</p>
<p>Variants in Ravenports are like supporting multiple versions of the same package, but with different feature sets. For those familiar with ebuilds, portage, and gentoo, variants in Ravenports is sort of like customizing your <code>FLAGS</code>. For an example for those not familiar, lets take a package like git. If you build git in the most basic way possible, you get the full package. But if you change some build variables, you can get a lighter version of git. In Ravenports, you can get the <code>git-full</code> or <code>git-lite</code> package. Its your choice. Another example is <code>less</code>. You can build less so it uses colors in it&#x27;s output, or for <code>less</code> to be colorless. I want to eventually support this idea of variants. But that is a future feature.</p>
<h1 id="what-does-a-port-look-like">What does a port look like</h1>
<p>Before going further, lets take a look at a current working sample of a port definition. Or, as it is called in <code>spellbook</code> (a package&#x2F;port), a spell definition.</p>
<pre><code>defmodule Htop do
  @behaviour Spellbook.Spell

  @impl true
  def name(), do: &quot;htop&quot;
  @impl true
  def version(), do: &quot;3.4.1&quot;
  @impl true
  def homepage(), do: &quot;https:&#x2F;&#x2F;htop.dev&quot;
  @impl true
  def license(), do: &quot;GPL-2.0&quot;
  @impl true
  def type(), do: &quot;bin&quot;
  @impl true
  def checksum(), do: &quot;&quot;
  @impl true
  def deps(), do: []
  @impl true
  def source(), do: &quot;https:&#x2F;&#x2F;github.com&#x2F;htop-dev&#x2F;htop&#x2F;archive&#x2F;refs&#x2F;tags&#x2F;3.4.1.tar.gz&quot;

  @impl true
  def install(args) do
    System.cmd(&quot;sh&quot;, [&quot;autogen.sh&quot;, &quot;--prefix=#{args.prefix}&quot;], cd: args.cwd)
    System.cmd(&quot;sh&quot;, [&quot;configure&quot;, &quot;--prefix=#{args.prefix}&quot;], cd: args.cwd)
    System.cmd(&quot;make&quot;, [], cd: args.cwd)
    System.cmd(&quot;make&quot;, [&quot;install&quot;], cd: args.cwd)

    :ok
  end
end</code></pre>
<p>Each spell is a module and it conforms to the <code>Spellbook.Spell</code> behavior, which is sort of like an interface. Quiet a bit of it is just package information like the name, version, license information, and where to get the source.</p>
<p>Then a spell definition needs to implement an <code>install&#x2F;1</code> function, these are the build instructions for building the software.</p>
<h1 id="building-the-port">Building the port</h1>
<p>To build a port right now, a function is ran that does a few things. First, it creates the &#x27;environment&#x27; for building. It does this by creating a temp directory and downloding the package there, then it extracts it&#x27;s contents. Afterwards, it will construct some environment variables and also create the information that will be injected into <code>install&#x2F;1</code> via the <code>args</code> parameter, then the method is called. The method executes it&#x27;s instructions. Returning from that, need to &#x27;install&#x27; it into the right place(s). So this would be some <code>bin</code> folder as an example, which it does by iterating over the build artifacts and creating symlinks to the appropraite spots. That is atleast the tldr of it. So far at least.</p>
<h2 id="output-from-a-build">Output from a build</h2>
<pre><code> ~&#x2F;ElixirProjects&#x2F;spellbook&#x2F; [main*] .&#x2F;spellbook cast ~&#x2F;ElixirProjects&#x2F;StandardBookOfSpells&#x2F;htop.exs
Casting spell: &#x2F;Users&#x2F;toddmartin&#x2F;ElixirProjects&#x2F;StandardBookOfSpells&#x2F;htop.exs
Warming up to perform cast...
Casting &#x2F;Users&#x2F;toddmartin&#x2F;ElixirProjects&#x2F;StandardBookOfSpells&#x2F;htop.exs
Build directory: &#x2F;var&#x2F;folders&#x2F;vf&#x2F;7r2g86991c788ppg6zq147r80000gn&#x2F;T&#x2F;htop-3.4.1
Now on to something else
Downloading https:&#x2F;&#x2F;github.com&#x2F;htop-dev&#x2F;htop&#x2F;archive&#x2F;refs&#x2F;tags&#x2F;3.4.1.tar.gz to &#x2F;var&#x2F;folders&#x2F;vf&#x2F;7r2g86991c788ppg6zq147r80000gn&#x2F;T&#x2F;htop-3.4.1&#x2F;3.4.1.tar.gz

22:13:14.923 [debug] redirecting to https:&#x2F;&#x2F;codeload.github.com&#x2F;htop-dev&#x2F;htop&#x2F;tar.gz&#x2F;refs&#x2F;tags&#x2F;3.4.1
Download complete
Extracing &#x2F;var&#x2F;folders&#x2F;vf&#x2F;7r2g86991c788ppg6zq147r80000gn&#x2F;T&#x2F;htop-3.4.1&#x2F;3.4.1.tar.gz....
Extraction complete: &#x2F;var&#x2F;folders&#x2F;vf&#x2F;7r2g86991c788ppg6zq147r80000gn&#x2F;T&#x2F;htop-3.4.1
autoreconf: export WARNINGS=all
autoreconf: Entering directory &#x27;.&#x27;
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: configure.ac: not using Intltool
autoreconf: configure.ac: not using Gtkdoc
autoreconf: running: &#x2F;opt&#x2F;homebrew&#x2F;Cellar&#x2F;autoconf&#x2F;2.72&#x2F;bin&#x2F;autoconf --force
autoreconf: running: &#x2F;opt&#x2F;homebrew&#x2F;Cellar&#x2F;autoconf&#x2F;2.72&#x2F;bin&#x2F;autoheader --force
autoreconf: running: automake --add-missing --copy --force-missing
autoreconf: Leaving directory &#x27;.&#x27;
Successfully installed htop
Linking...
[lib&#x2F;spellbook&#x2F;linker.ex:12: Spellbook.Linker.link_spell&#x2F;2]
base #=&gt; &quot;&#x2F;opt&#x2F;spellbook&#x2F;Spells&#x2F;htop&#x2F;3.4.1&quot;

Creating symlink &#x2F;opt&#x2F;spellbook&#x2F;Spells&#x2F;htop&#x2F;3.4.1&#x2F;bin&#x2F;htop -&gt; &#x2F;opt&#x2F;spellbook&#x2F;bin&#x2F;htop
Creating symlink &#x2F;opt&#x2F;spellbook&#x2F;Spells&#x2F;htop&#x2F;3.4.1&#x2F;share&#x2F;man&#x2F;man1&#x2F;htop.1 -&gt; &#x2F;opt&#x2F;spellbook&#x2F;share&#x2F;man&#x2F;man1&#x2F;htop.1
Creating symlink &#x2F;opt&#x2F;spellbook&#x2F;Spells&#x2F;htop&#x2F;3.4.1&#x2F;share&#x2F;pixmaps&#x2F;htop.png -&gt; &#x2F;opt&#x2F;spellbook&#x2F;share&#x2F;pixmaps&#x2F;htop.png
Creating symlink &#x2F;opt&#x2F;spellbook&#x2F;Spells&#x2F;htop&#x2F;3.4.1&#x2F;share&#x2F;icons&#x2F;hicolor&#x2F;scalable&#x2F;apps&#x2F;htop.svg -&gt; &#x2F;opt&#x2F;spellbook&#x2F;share&#x2F;icons&#x2F;hicolor&#x2F;scalable&#x2F;apps&#x2F;htop.svg
Creating symlink &#x2F;opt&#x2F;spellbook&#x2F;Spells&#x2F;htop&#x2F;3.4.1&#x2F;share&#x2F;applications&#x2F;htop.desktop -&gt; &#x2F;opt&#x2F;spellbook&#x2F;share&#x2F;applications&#x2F;htop.desktop
Done casting...</code></pre>
<p>As shown above, the build artifacts are in <code>&#x2F;opt&#x2F;spellbook&#x2F;Spells&#x2F;htop&#x2F;3.4.1</code>, following a conventions of <code>&#x2F;opt&#x2F;spellbook&#x2F;Spells&#x2F;&lt;PACKAGE_NAME&gt;&#x2F;&lt;VERSION&gt;</code>. When symlinking, it will see that there is a <code>bin</code> directory in <code>&#x2F;opt&#x2F;spellbook&#x2F;Spells&#x2F;htop&#x2F;3.4.1&#x2F;bin</code>. It will iterates over the files there and create symlinks in <code>&#x2F;opt&#x2F;spellbook&#x2F;bin</code>.</p>
<h1 id="going-full-witch-y-with-it">Going full witch-y with it</h1>
<p>Here is a the help menu from <code>spellbook</code>.</p>
<pre><code> ~&#x2F;ElixirProjects&#x2F;spellbook&#x2F; [main] .&#x2F;spellbook
Magical system package manager 0.0.1
Todd Martin
A magical system package manager

USAGE:
    spellbook
    spellbook --version
    spellbook --help
    spellbook help subcommand

SUBCOMMANDS:

    cast            Cast (install) a spell (package)
    dispel          Dispel (uninstall) a spell (package)
    scry            Search for a spell
    grimoire        List casted spells
    reveal          Reveal information about a spell
    renew           Renew your spellbook shelf
    empower         Upgrade a casted spell</code></pre>
<p>As shown above, to <code>install</code> we <code>cast</code>. To list all casted spells, we use the subcommand <code>grimoire</code> which will list all of our casted spells.</p>
<pre><code> ~&#x2F;ElixirProjects&#x2F;spellbook&#x2F; [main] .&#x2F;spellbook help cast
Cast (install) a spell (package)

USAGE:
    cast SPELL
    cast --version
    cast --help

ARGS:

    SPELL        Package</code></pre>
<p>And this is what the <code>&#x2F;opt&#x2F;spellbook</code> directory looks like.</p>
<pre><code> &#x2F;opt&#x2F;spellbook&#x2F; ls
bin     etc     lib     sbin    share   Shelves Spells</code></pre>
<h1 id="conclusion">Conclusion</h1>
<p>This is still very early days with a lot more left to implement. But all in all, I am enjoying my time with Elixir and as I get further in, I plan to post more about this project. And as I &#x27;live&#x27; in Elixir a little but more, I will post more about my experience with that. Afterall, it is hard to really know if you like something until you&#x27;ve lived in it for a bit.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="text">Zig and SDL3 interop</title>
    <id>/post/zig-sdl3-interop/</id>
    <updated>2024-12-12T00:00:00Z</updated>
    <published>2024-12-12T00:00:00Z</published>
    <link href="http://example.org/post/zig-sdl3-interop/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<p>My daughter has recently inspired me to play around with an idea. She had gotten a tomagotchi and thought the thing was pretty cool. Looking at it, I thought, &quot;huh, I can probably do something like that.&quot; Now, I&#x27;ve never played with one, but they seem pretty simple. Doing hardware and having a reason for doing some embedding programming, more or less an actual project, would be pretty fun also. However, before I juggle both, I just want to focus some on the software side of things. Also, I have been giving Zig the eye again, but I needed some decent and fun thing to do with Zig.</p>
<p>So, I have decided to try maybe proto-tpying a little bit of a tomagotchi clone in Zig. I&#x27;ve got a programming language, now I need some other bits. Obviously, I need to render something, so in walks SDL. Interoping Zig with C code is pretty simple. It is one of the &#x27;promises&#x27; of Zig. Why not give it a shot? I will go over some basic on getting started, but not too much indepth. Just setting Zig up to work with SDL and just a few basic things while also talking a little bit about the Zig language. Nothing too complicated or indepth.</p>
<h1 id="zig--3-c">Zig &lt;3 C</h1>
<p>I&#x27;ve tried experimenting with using SDL with Swift and its a bit of a pain. The libraries which provide wrappers and setting them up takes a bit to read through the documentation on SwiftPM. Rust isn&#x27;t too bad, but doing things with bindgen is not exactly easy or low effort. Zig though promises it to be pretty smooth.</p>
<p>First things first, need to have SDL on the machine. Another reason why I&#x27;ve had some issues with Swift is that since SDL3 has been around, I&#x27;ve been wanting to use the new hotness with SDL. Why build stuff on SDL2 when SDL3 is available. Granted, I was using it before they started releasing binaries, so I&#x27;ve been compiling it myself. Which SDL provides some good documentation for. Zig makes this easy. It really is just a line or two in the <code>zig.build</code> file and the compiler and build system handles the rest.</p>
<pre><code>exe.linkSystemLibrary(&quot;SDL3&quot;);
exe.linkSystemLibrary(&quot;c&quot;);</code></pre>
<p>That is really all there is to it for incorporating it in the build. </p>
<p>Much like Swift with SwiftPM, one thing that I like about Zig is that the build system is essentially defined in Zig itself. Well, with Swift, it might be more fair to say that defining dependencies and how those link and build are defined in Swift.</p>
<h1 id="setting-up-a-game-struct-and-the-main-file-">Setting up a Game struct and the main file.</h1>
<p>A lot of examples of Zig with SDL that I have come across have done all the important setup in the main function of <code>main.zig</code>. I didn&#x27;t want to do this, I wanted to to be somewhat separate. Here is what my <code>zig.main</code> looks like.</p>
<pre><code>const game = @import(&quot;game.zig&quot;);

pub fn main() !void {
	var g = game.Game.init();
	try g.initialize();
	defer g.destroy();
	try g.run();
}</code></pre>
<p>All of the &#x27;game&#x27; logic resides in the game struct and it&#x27;s methods&#x2F;functions. The first line is importing the <code>game.zig</code> file which contains the struct and it&#x27;s associated logic. The main function returns void, but can also return an error. This is almost like <code>fn main() -&gt; Result&lt;()&gt;</code> in Rust. What is does is simple, initialize a <code>Game</code> object, then we try to initialize it. The line after that I will get to in a second, but it is interesting, and then we just try to call the run method on the object.</p>
<p>The <code>defer g.destroy()</code> is interesting. It is used to ensure that resources are cleaned up with no longer needed. I am not fully aware of <em>all</em> of the details around it, but it works a little bit like the destructor on a smart pointer in C++ or the drop trait in Rust. Not exact, but so far, I have been able to get by with thinking about it like that.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="text">Homebrew - Adding Comtry to Core</title>
    <id>/post/homebrew-comtrya/</id>
    <updated>2024-11-19T00:00:00Z</updated>
    <published>2024-11-19T00:00:00Z</published>
    <link href="http://example.org/post/homebrew-comtrya/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<h1 id="homebrew--adding-comtrya-to-core">Homebrew: Adding Comtrya to Core</h1>
<p>I use a different mix of systems. The server this site is hosted on is a Debian VPS. I have two machines. I use some local test servers in my home that are in the form of Mac Minis; one has FreeBSD installed while the other has NetBSD. A desktop that runs Arch linux and a Macbook Pro running macOS. However, I am often using my Macbook Pro.</p>
<p>Having done a little port work for Ravenports on the BSDs and running primarily macOS right now, I have always been interested in Homebrew and how that system works as far as packaging software. Homebrew is also cross platform, however, I have never used it on Linux. Although, it is hard to get deep into packaging and actually doing it without having something to package.</p>
<p>In comes <a href="https://github.com/comtrya/comtrya">Comtrya</a>. I have not written about it before, but I should write a few articles. Comtrya is an open source project that I have been a contributor of for awhile and that I now am the primary maintainer and do the releases of. I won’t go too much into the details of Comtrya, since that is not the main focus of this writing. </p>
<p>What I will say is that Comtrya is distributed in a few ways. First, it is available in raw binaries under github <a href="https://github.com/comtrya/comtrya/releases/tag/v0.9.0">releases</a>. There is a script that can be curl’d and piped to bash that can pick the right binary and place it accordingly. I am not a huge fan of this method, but it is popular and for what Comtrya can do, I can see the reason why people would want it. Since it is a rust program, it can be gotten via cargo since it is published to <a href="https://crates.io/crates/comtrya">crates</a>. Installation can also occur through a small set of package managers. Primarily, before my work here, it was available in the AUR and in Ravenports. Even though I have introduced and maintained ports for Ravenports, I sadly am not the one to introduce Comtrya, or rather ironically. Instead a friend of mine does that, the same friend who introduced me to Comtrya to begin with. </p>
<p>Since I mostly work off macOS now, I figured I should make it available via Homebrew. </p>
<h2 id="initial-work---making-a-tap">Initial work - Making a tap</h2>
<p>Before looking too deep into what is needed and the requirements to get it into homebrew core, which will be explained a little later, I decided to make a tap for Comtrya. A tap you can think of as like a repository for a package or packages. If your familiar with Ubuntu’s PPA, it is sort of like that. </p>
<p>A tap also doesn’t have certain restrictions since it isn’t in homebrew-core. In a tap, it is okay to make a tap that just download the binary and places it. Which is the route I went for the tap, go with the easiest and make that available first.</p>
<p>Homebrew and the formula are primarily written in Ruby. Which is a little bit of coincidence since I recently have been using a little Ruby for a website with the Ruby on Rails framework. Packages are defined in Ruby and the recipe to make the package is called a formula. 
For someone to make use of a formula they just need to tell Homebrew to add the tap, which is like adding a PPA on Ubuntu for apt.</p>
<pre><code>brew tap comtrya&#x2F;comtrya
brew install comtrya</code></pre>
<p>The formula has some details about the package and can perform some actions. The main action I focus is the install action. As mentioned, the route I went with was just grabbing the binary and installing it.</p>
<pre><code># Documentation: https:&#x2F;&#x2F;docs.brew.sh&#x2F;Formula-Cookbook
#            	https:&#x2F;&#x2F;rubydoc.brew.sh&#x2F;Formula
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
class Comtrya &lt; Formula
  desc &quot;Configuration And Dotfile Management&quot;
  homepage &quot;https:&#x2F;&#x2F;comtrya.dev&quot;
  url &quot;https:&#x2F;&#x2F;github.com&#x2F;comtrya&#x2F;comtrya&#x2F;releases&#x2F;download&#x2F;v0.9.0&#x2F;comtrya-aarch64-apple-darwin&quot;
  sha256 &quot;1ca79b45a9c6cd91654fefe47a22fcfdfee7d05bb792b69e39e35e9d396dad6e&quot;
  license &quot;MIT&quot;
  version &quot;0.9.0&quot;

  def install
	bin.install &quot;comtrya-aarch64-apple-darwin&quot; =&gt; &quot;comtrya&quot;
  end
end</code></pre>
<p>It is that simple. There are a few drawbacks here. It only pulls the aarch64 build for macOS. So this would not work on a x86_64 macOS machine or linux. So pretty much only apple silicon. But, this was just getting a little bit of experience before looking into the requirement for homebrew-core.</p>
<p>The repository for the tap is located on <a href="https://github.com/comtrya/homebrew-comtrya">github</a> under Comtrya&#x27;s organization.</p>
<h2 id="getting-into-homebrew-core">Getting into homebrew-core</h2>
<p>Homebrew has what is called <a href="https://github.com/Homebrew/homebrew-core">“homebrew-core.”</a> This is pretty much the official repository. The main requirement that comes into play for me to get Comtrya packaged is that, for a package to make it in, the formula must handle building the application from source. There are also some quality controls that are required also. </p>
<p>To get an idea of how to do with rust, I took quiet a bit of inspiration from <a href="https://github.com/Homebrew/homebrew-core/blob/master/Formula/r/ripgrep.rb">ripgrep</a>, which is already in homebrew-core. Rust programs can be a bit of a beast to get into a ports tree or package manager depending on the philosophy. For instance, I believe Debian and FreeBSD’s ports tree want the package definition to be able to build itself, but also all of its dependencies with their package definitions to build the dependencies locally. Ravenports sort of does to, but a special short cut has been cut out for Rust programs and Go programs (with go mod). So taking Comtrya as an example, the last number I remember was somewhere in the ballpark of 387 dependencies. This includes transitive dependencies. Needing to bring in 387 recipes or package definitions isn’t fun, long and grueling work. Luckily, Homebrew does not require this. I don’t need to first package each dependency and make sure the versions are compatible, we can just trust the maker (in this case me) and cargo to do the right thing.</p>
<pre><code>class Comtrya &lt; Formula
  desc &quot;Configuration and dotfile management tool&quot;
  homepage &quot;https:&#x2F;&#x2F;comtrya.dev&quot;
  url &quot;https:&#x2F;&#x2F;github.com&#x2F;comtrya&#x2F;comtrya&#x2F;archive&#x2F;refs&#x2F;tags&#x2F;v0.9.0.tar.gz&quot;
  sha256 &quot;a5401004a92621057dab164db06ddf3ddb6a65f6cb2c7c4208a689decc404ad4&quot;
  license &quot;MIT&quot;
  head &quot;https:&#x2F;&#x2F;github.com&#x2F;comtrya&#x2F;comtrya.git&quot;, branch: &quot;main&quot;

  bottle do
	sha256 cellar: :any_skip_relocation, arm64_sequoia: &quot;56bcd6407ac6f14a3ba79414c0651e52a2e262ce16b1148c70abc2ac1a121ead&quot;
	sha256 cellar: :any_skip_relocation, arm64_sonoma:  &quot;6686fa03d6d26a52beb6db4aa60d1dc51dfe34fda8e490d65c0ed96ee1adf883&quot;
	sha256 cellar: :any_skip_relocation, arm64_ventura: &quot;eaed784b320caf01dbf1130b956a34d5bf75d93c09555d9d5c3cdc799de13cad&quot;
	sha256 cellar: :any_skip_relocation, sonoma:    	&quot;846c88f71d195eb80fe7a33024cd985bcd023455a6d2e52582e66b6a40613adc&quot;
	sha256 cellar: :any_skip_relocation, ventura:   	&quot;ca956905d382263bc9ce55ddcda6f57612565322d33aa918621fe24e744f565e&quot;
	sha256 cellar: :any_skip_relocation, x86_64_linux:  &quot;635873d62afde5a0e0e100273ec87da7d4d6bc3ee74f59c894bf7e8d346b3b77&quot;
  end

  depends_on &quot;rust&quot; =&gt; :build

  def install
	system &quot;cargo&quot;, &quot;install&quot;, *std_cargo_args(path: &quot;.&#x2F;app&quot;)
  end

  test do
	assert_match &quot;comtrya #{version}&quot;, shell_output(&quot;#{bin}&#x2F;comtrya --version&quot;)

	resource &quot;testmanifest&quot; do
  	url &quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;comtrya&#x2F;comtrya&#x2F;refs&#x2F;heads&#x2F;main&#x2F;examples&#x2F;onlyvariants&#x2F;main.yaml&quot;
  	sha256 &quot;0715e12cbbb95c8d6c36bb02ae4b49f9fa479e2f28356b8c1f3b5adfb000b93f&quot;
	end

	resource(&quot;testmanifest&quot;).stage do
  	system bin&#x2F;&quot;comtrya&quot;, &quot;-d&quot;, &quot;main.yaml&quot;, &quot;apply&quot;
	end
  end
end</code></pre>
<p>Above is the formula that is now in homebrew-core. As mentioned, we can just trust the maker and cargo to do the right thing. Defining rust as a build dependency pulls down all the rust tooling, including cargo, to build the package. Then building the package is as simple as invoking cargo to install.</p>
<p>One area I had an issue with that referencing ripgrep wasn’t much of a help with is how to build Comtrya for homebrew with it having workspaces and how the workspace are set up. The binary application is the app. There is also a lib that is built for the library crate and jsonschema crate. I did have to tell cargo to build specifically the app to successfully compile Comtrya with homebrew from source. From there, Homebrew&#x27;s tooling takes care of most of it, including placing the binary in the appropriate place on each system. Since it is built from source, this package should technically work on any platform that homebrew supports.</p>
<p>As mentioned, there is some quality control that is required here. That is the test section. Each package that is being introduced into homebrew has to have at least one test. The general rule of thumb is that the test needs to flex how the application is used and should not just be a version check. </p>
<p>In my test, I do run a version check. But I also pull down a resource, a test manifest and have Comtrya apply the manifest. The test passes so long as Comtrya doesn’t throw an error when running it. </p>
<p>And of course, now Comtrya is <a href="https://github.com/Homebrew/homebrew-core/pull/197214">officially avaible</a> in hombrew-core.</p>
<h2 id="interacting-with-the-maintainers-of-homebrew">Interacting with the maintainers of Homebrew</h2>
<p>I found them to be helpful and pretty welcoming. There were some issues I had to fix. First was styling. Homebrew does have a tool that will help fix the styling similar to how cargo’s fmt works. Also a little bit of guidance of what is expected with tests. It was also handy to look at other recently closed pull requests and pending pull requests to see if there was anything I was missing.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="text">Swift and SDL3 interop</title>
    <id>/post/swiftdl3-interop/</id>
    <updated>2024-07-16T00:00:00Z</updated>
    <published>2024-07-16T00:00:00Z</published>
    <link href="http://example.org/post/swiftdl3-interop/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<p>Over the last 6 months, I have been dabbling in a bit of graphics programming and game development. I started working on a framework called Flatland when I realized that I was perhaps a little over my head. I plan to write about that later. But there were definitely some areas I was weak in. The motivation of Flatland is a sort of framework&#x2F;engine to make 2D games that works with SwiftUI and Apple Metal as the graphics API. While I can render graphics, doing so well is the difficult part where I found that I couldn&#x27;t really figure out a good way to organize it. </p>
<p>So, I decided to take a bit of a step back and focus on perhaps a simpler engine. One that is more like a Wolfenstien-esque style engine. So 2D that fakes 3D via ray tracing. Plus, there are tons of reference material and posts to read about why various design choices are made regarding a Wolfenstein style engine. And of course, I want to do it in Swift.</p>
<p>Initially my plan was to stick with UIKit or SwiftUI, but then I figured, well, why not just use SDL? Especially since SDL3 is sorta out right now. Well, looking at the repository, there are not official tags, but the &#x27;main&#x27; branch is essentailly SDL3. Plus, it will simplify some things since I am not well versed in UIKit. Plus, SDL is also more cross platform. Perhaps getting back into dabbling with SDL, I can stick with SDL when I get back to Flatland to render using Metal. Or use a software renderer as a stepping stone for the design of the rendering engine with an Apple Metal backend. TBut the cross-platformness of SDL would be great because I would also be able to use this on Linux. And not going to lie, I am secrely hoping I wake up one day to find that there is some upstream support for FreeBSD&#x2F;NetBSD for Swift. </p>
<p>However, this presents a little bit of a problem. The current libraries available via Swift Package Manager (SPM) are a mix of either out of date, or still only target SDL2. So, guess what? I guess I need to make my own package to wrap SDL3. </p>
<p>So first things first, how do we do this? Well, Swift does provide a <a href="https://www.swift.org/documentation/articles/wrapping-c-cpp-library-in-swift.html">guide</a>, so lets follow along and see how it goes.</p>
<p>I create my folder.</p>
<pre><code>mkdir SwiftDL3</code></pre>
<p>Then time to navigate into it and initialize a new library package.</p>
<pre><code>cd SwiftDL3
swift package init --type library --name SwiftDL3</code></pre>
<p>Now, I have the skeleton for the project. A few more things to do before really digging in.</p>
<p>Unfortunately, it doesn&#x27;t appear to initialize a git repositority for us and that will be important with as per the instructions, we need to use a git submodule. Or atleast, that is route I plan to go.</p>
<pre><code>git init</code></pre>
<p>Also I don&#x27;t quiet like the <code>SwiftDL2.swift</code> file, so I want to get rid of that.</p>
<pre><code>rm Sources&#x2F;SwiftDL3&#x2F;SwiftDL3.swift</code></pre>
<p>Now, nagivate into the folder for the library and add our git submodule</p>
<pre><code>cd Sources&#x2F;SwiftDL3
git submodule add https:&#x2F;&#x2F;github.com&#x2F;libsdl-org&#x2F;SDL.git</code></pre>
<p>Once that is done cloning, verify the <code>.gitmodules</code> file.</p>
<pre><code>cat ..&#x2F;..&#x2F;.gitmodules
[submodule &quot;Sources&#x2F;SwiftDL3&#x2F;SDL&quot;]
	path = Sources&#x2F;SwiftDL3&#x2F;SDL
	url = https:&#x2F;&#x2F;github.com&#x2F;libsdl-org&#x2F;SDL.git</code></pre>
<p>Looks good so far.</p>
<pre><code>cd ..&#x2F;..&#x2F;</code></pre>
<p>Let take a look at the current <code>Package.Swift</code> file.</p>
<pre><code>&#x2F;&#x2F; swift-tools-version: 5.10
&#x2F;&#x2F; The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: &quot;SwiftDL3&quot;,
    products: [
        &#x2F;&#x2F; Products define the executables and libraries a package produces, making them visible to other packages.
        .library(
            name: &quot;SwiftDL3&quot;,
            targets: [&quot;SwiftDL3&quot;]),
    ],
    targets: [
        &#x2F;&#x2F; Targets are the basic building blocks of a package, defining a module or a test suite.
        &#x2F;&#x2F; Targets can depend on other targets in this package and products from dependencies.
        .target(
            name: &quot;SwiftDL3&quot;),
        .testTarget(
            name: &quot;SwiftDL3Tests&quot;,
            dependencies: [&quot;SwiftDL3&quot;]),
    ]
)</code></pre>
<p>Let try just running this.</p>
<pre><code>swift build</code></pre>
<p>Looks like I already hit an error.</p>
<pre><code>error: &#x27;swiftdl3&#x27;: manifest property &#x27;defaultLocalization&#x27; not set; it is required in the presence of localized resources</code></pre>
<p>Doing a quick google search, I found a <a href="https://stackoverflow.com/questions/67871929/swift-package-manifest-property-defaultlocalization-not-set">page</a> that provided a problem. Lets just add this to the <code>Package.swift</code>.</p>
<pre><code>defaultLocalization: &quot;en&quot;,</code></pre>
<p>Building now results in a different error.</p>
<pre><code>warning: &#x27;swiftdl3&#x27;: &#x27;SwiftDL3&#x27; was identified as an executable target given the presence of a &#x27;main.swift&#x27; file. Starting with tools version 5.4.0 executable targets should be declared as &#x27;executableTarget()&#x27;
error: &#x27;swiftdl3&#x27;: library product &#x27;SwiftDL3&#x27; should not contain executable targets (it has &#x27;SwiftDL3&#x27;)</code></pre>
<p>Seems a little odd that the simpiler is thinking it is an executable target and not a library. Especially since there is not a <code>main.swift</code> file.</p>
<p>Making some edits to the package file. It looks like I have some progress.</p>
<pre><code>&#x2F;&#x2F; swift-tools-version: 5.10
&#x2F;&#x2F; The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
  name: &quot;SwiftDL3&quot;,
  defaultLocalization: &quot;en&quot;,
    products: [
        &#x2F;&#x2F; Products define the executables and libraries a package produces, making them visible to other packages.
        .library(
            name: &quot;SwiftDL3&quot;,
            targets: [&quot;SwiftDL3&quot;]),
    ],
    targets: [
        .target(
          name: &quot;SwiftDL3&quot;,
          dependencies: [],
          exclude: [],
          sources: [],
          cSettings: []
        ),
    ]
)</code></pre>
<p>Now, I get the following error when building.</p>
<p>error: &#x27;swiftdl3&#x27;: public headers (&quot;include&quot;) directory path for &#x27;SwiftDL3&#x27; is invalid or not contained in the target</p>
<p>After reading some documentation and playing around, it looks like I&#x27;ve got something compiling. Lets take a look at the files.</p>
<pre><code>&#x2F;&#x2F; swift-tools-version: 5.10
&#x2F;&#x2F; The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
  name: &quot;SwiftDL3&quot;,
  defaultLocalization: &quot;en&quot;,
    products: [
        &#x2F;&#x2F; Products define the executables and libraries a package produces, making them visible to other packages.
        .library(
            name: &quot;SwiftDL3&quot;,
            targets: [&quot;SwiftDL3&quot;]),
    ],
    targets: [
        .target(
          name: &quot;SwiftDL3&quot;,
          dependencies: [],
          exclude: [],
          sources: [],
          publicHeadersPath: &quot;SDL&#x2F;include&#x2F;SDL3&quot;,
          cSettings: []
        ),
    ]
)</code></pre>
<p>I also modified the <code>.gitmodules</code> file to the following.</p>
<pre><code>[submodule &quot;SDL&quot;]
	path = Sources&#x2F;SwiftDL3&#x2F;SDL
	url = https:&#x2F;&#x2F;github.com&#x2F;libsdl-org&#x2F;SDL.git</code></pre>
<p>Now for the moment of truth. To see if it can be using in an actual executable.</p>
<p>Naviagting out of the directory for this, I will create a new folder and project within it. Then I plan to map SwiftDL3 as a dependency on my local file system.</p>
<pre><code>cd ..&#x2F;
mkdir SwiftDL3Test
cd SwiftDL3Test
swift package init --type executable --name SwiftDL3Test</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="text">Adventures into Ruby on Rails</title>
    <id>/post/adventures-into-ruby-on-rails/</id>
    <updated>2024-11-11T00:00:00Z</updated>
    <published>2024-11-11T00:00:00Z</published>
    <link href="http://example.org/post/adventures-into-ruby-on-rails/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>About a little over a month ago, the video for DHH&#x27;s <a href="https://www.youtube.com/watch?v=-cEn_83zRFw&t=3329s">keynote talk</a> at the Ruby on Rails conference caught my eye. I don&#x27;t really do a whole lot of web development. This blog I have been throwing together with static site generators and now the current iteration as of this writing is in the <a href="https://astro.build">Astro framework</a>. Ultimately, most of my &#x27;web application&#x27; experience has been using static generators and a few tutorials every once in awhile when I get an itch with react. But DHH&#x27;s talk caught my attention. First, I have always been a little curious of just seeing what Ruby on Rails is. I have heard it a lot, but have never really looked at the code. Second, it seems like a perfect match for a web development idiot like myself. I can learn web development, but I always run into an issue with, I read some documents and do some tutorials, but I never have a serious project to do with it.</p>
<p>Well, that is not entirely true. but for the most part it is. I technically did a little bit of a web development project at work where I had to modify an old ASP.NET MVC that probably had not been touched in 4 or 5 years to allow for a new feature. However, I did not have to do much with the UI, it was mostly adjusting the controllers and some of the logic within them. Still, I don&#x27;t necessarily count that. </p>
<h1 id="how-i-got-here">How I got here</h1>
<p>As timing would have it, a project came along right around the time I listened to this talk. My father in law recently took over his dad&#x27;s business doing carpet cleaning and with that, taking over the website and such. While out visiting, he said he had some struggles. He isn&#x27;t very tech literate either. I told him I can take a look and see if I can help. After all, I am a software engineer. So he pointed me to it and well, it was Godaddy. By Godaddy, I mean the domain is registered through GoDaddy and his site was thrown together by another family member via their point and click UI to build a site. </p>
<p>Now, I am not a huge fan of those interfaces. Maybe, its because I write software. Maybe, it is because I have been a user of Linux and other Unix system since when you had to custom compile kernels if you wanted your WiFi to work. I am much more comfortable dealing with text and not dragging and clicking. Also, he was paying somewhere northwards of $400 a year for a domain, hosting a pretty simple site, and an email plan I guess he got suckered into that he never plans to use. So, I told him I could play around with some stuff, but if I am going to do any work on it, the drag and drop website builder has to go.</p>
<p>So, now I had a project, and I just recently learned about a new framework.</p>
<h1 id="how-it-turned-out">How it turned out</h1>
<p>Before going too deep into details and talking about how I solved some problems, I will get to the conclusion on how this went. My father in law has a new website hosted on a server I rent for other projects and it does everything it does. The server I rent has way more capacity than needed, so it doesn&#x27;t really cost me anything to host it for him. It also saves him some money. He offered, but as I explained to him, whether or not his site is on it, I&#x27;d be paying for it anyways. Plus, I considered his payment for my service being his giving me a problem and a project I have been on the look out for, for awhile.</p>
<h1 id="give-me-the-dirty-details-on-working-with-ruby-on-rails">Give me the dirty details on working with Ruby on Rails</h1>
<p>So far, I feel like DHH makes a promise and that for the most part is true. That promise is a framework that makes it easy to work in once you get the hang of it. Also allowing a person to be a one person team. Which was perfect for this project. Instead of starting with 7.2, I started his website using 8.0.0-beta and living with it through upgrading it from 8.0.0-RC1 to 8.0.0-RC2 and recently upgrading it to 8.0.0.</p>
<h2 id="why-start-with-beta">Why start with Beta</h2>
<p>The main attraction was the authentication generation. I didn&#x27;t really want to have to deal with something like firebase&#x27;s auth or an external auth and relying on a free teir plan. There is nothing wrong with utilizing the free tiers, but it is also nice that I never have to worry about a rug pull. Granted, for users, his site could have probably sat in a free teir for forever. That is because as of right now, the authentication just gives access to a dashboard with functionality for him and my mother in law. Also myself just to double check things in production. So, at most 3 users roughly? </p>
<p>The scripts for authentication were as good as promised I feel. It pretty much took care of all of that auth without me having to tear too much into implementation and RFCs if I were going to roll my own or learning how to work with an auth provider. In about 5 minutes, I had a working authentication system.</p>
<p>The only part of auth that took me a little bit of reading to work with was how to specify which pages don&#x27;t require auth. Now, I am still not an expert, but from what I have seen, when you use the generate authentication system, it automatically assumes that every page, or at least pages produced by controllers, require a valid session token. To have a controller not require a session token, a declaration needs to be made after the class definition.</p>
<pre><code>allow_unauthenticated_access</code></pre>
<h2 id="a-design-i-was-somewhat-familiar-with">A design I was somewhat familiar with</h2>
<p>Ruby on Rails makes use of the MVC (Model-View-Controller) pattern which I was already familiar with from a little bit of work I did on an ASP.NET project at work, it is the one mentioned at the beginning of this article. </p>
<p>Don&#x27;t consider this an endorsement of MVC. I do not do enough web development to know if MVC is a superior patterns to other. I do know that Angular is based on an MVC pattern. In this case, it is just a pattern that I had seen before and technically worked with before when working on a website.</p>
<h2 id="mailers">Mailers</h2>
<p>This project was going to need some functionality with email. As of right now, there are three main use cases for working with email. First, supporting the &#x27;forgot password&#x27; functionality in the authentication system. Luckily, if the email server settings are configured, the auth generation provided by rails pretty much does this for you. Nothing to do, it just rather works without a thought. Next, I built the ability for my father-in-law to have a sort of newsletter. This he can leverage pretty well. He lives pretty far north so for winter, the business shuts down because the equipment will freeze. At the very least, he can have a sort of newsletter to notify people when he will be closing down or opening up depending on the season. People can subscribe on the homepage of his site by inputting in their email. An email is fired off to confirm subscription. Then, from the dashboard, I built an area where he can input a subject and email contents to send out to everyone on the list. Right now, it is pretty bare bones, but it is a start. I need to guide him through, and make he knows, he can make requests and I will work on them. Or in other words, coming up with requirements that will help him better.</p>
<p>Mailers is probably a killer feature of Ruby on Rails. It just makes it easy. I have some experience of the hell with working with email from work. There is a lot to be said about SMTP, but I&#x27;ll try not to air those grievances here. Like auth, rails can generate quiet a bit for you and also splits it into an MVC like pattern. A controller can control when and how emails are sent. Views are present that are the template for the email to be sent. Then configuring the email server is pretty straight forward from looking at the documentation. There is also a lot of stack overflow, blog posts, and other resources to help with this.</p>
<h1 id="conclusion">Conclusion</h1>
<p>All around, I am pretty happy with it. For a solo developer working on a project and needing a simple authentication system and mailers, Ruby on Rails makes it easy and I would recommend it.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="text">SBIG Game Jam 2024 Part I - Before the storm</title>
    <id>/post/sbig-game-jam-2024-1/</id>
    <updated>2024-06-27T00:00:00Z</updated>
    <published>2024-06-27T00:00:00Z</published>
    <link href="http://example.org/post/sbig-game-jam-2024-1/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<p>It has been awhile since I have written any new content to publish. Over the last almost year, I have been bouncing back and forth between different thing. However, over the last 6 months, I&#x27;ve spent most of my free programming time playing around with Swift and Apple&#x27;s Metal framework. Hopefully I will get a chance here soon to dive into that some.</p>
<p>Fast forward to today. As mentioned, I&#x27;ve been playing around with game development. Starting today, I am doing my first game jam. If your unfamiliar with what that is, it is a competition where you implement a game within a set time period. That is at least the simple explanation, mile high view. However, I have a little twist on this. My son, who is 8, has been asking me to make a game with him. So I decided that we would try to do that during this game jam.</p>
<p>Today starts the <a href="https://itch.io/jam/sbigjam2024">&#x27;So Bad It&#x27;s Good&#x27;</a> game jam. The rules are simple.</p>
<ul>
<li>Try to make something fun</li>
<li>It can be original or based off an existing IP</li>
<li>Use whatever you like, however many people</li>
<li>Games must be made during the jam period</li>
</ul>
<p>So, here is the plan of attack.</p>
<p>It is up to my son to design the high level parts of the game. This is the story line, game mechanics, rough idea of the assets, all of that. I will help some with narrowing his focus. I will take care of the programming and essentially everything that needs to be done on the computer. From there, we&#x27;ve got 8 days to slap something together that it hopefully fun.</p>
<p>For tech stack. I started working on my own library in Swift that uses Metal called &#x27;Flatland.&#x27; However, due to some other side projects, I wasn&#x27;t able to get it where I feel confident enough to live in it for 8 days. So over the last couple of day, I have pivoted on my tooling. My plan is to use a small project called <a href="https://github.com/AdaEngine/AdaEngine">AdaEngine</a> to implement the game. The benefit is, AdaEngine appears to be architected in a way I was shooting for for Flatland. But also, it&#x27;ll give me an idea of what kind of interfaces and such that I want to eventually bring into Flatland. So the tech stack is simple. Swift and Apple Metal using AdaEngine, targeting macOS.</p>
<p>My plan is to try to document my process and progress over the course of the game jam.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="text">Terminal Drawing with Swift</title>
    <id>/post/terminal-drawing-with-swift/</id>
    <updated>2023-06-25T00:00:00Z</updated>
    <published>2023-06-25T00:00:00Z</published>
    <link href="http://example.org/post/terminal-drawing-with-swift/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Terminal based UIs have always held a certain fascination with me. They can be incredibly functional while also, at least from looks, being incredibly minimal. There is also something beutiful about a simple terminal UI. In a previous article I played around with crossterm in Rust and recently thought, huh, wonder what it would be like with Swift. This also gave me the change to play with some lower level things in Swift that so far, most of my tinkering has not lead me to. This got me to look at pointers and some unicode encoding.</p>
<p>Unlike with Rust where I used crossterm, I decided not to use a library that abstracts all the nitty gritty details of the terminal. Instead, I will be placing the terminal into raw mode and drawing without too many abstractions on top. The place to begin, is by looking at termios. Termios, for those who are unaware, well, I will just copy and past it from the <a href="https://man.freebsd.org/cgi/man.cgi?query=termios&sektion=4">FreeBSD man pages</a>.</p>
<pre><code>This describes a general terminal line discipline that is supported on tty asynchronous communication ports.</code></pre>
<p>This can be thought of as the low level settings for the terminal. Not things like fonts or colors, but instead how the terminal actually functions at a deeper level. In case your wondering why I pulled the FreeBSD man page for this, lots of userland utilities on macOS come from the BSDs. You can see this when you run &#x27;man termios&#x27; in iterm or the macOS terminal and go down to the bottom. It pretty much is the FreeBSD man page. Also, termios is a pretty generic structure, as in, most unix-like systems all have pretty much the same struct with same settings. So, this code should not only work on macOS, but also Linux and the BSDs.</p>
<p>Here is what I get after running my code in the terminal. Only this.</p>
<pre><code>┏━━━━━━━━━━━━━━━━━━━┓
┃                   ┃
┃                   ┃
┃                   ┃
┃                   ┃
┃                   ┃
┃                   ┃
┃                   ┃
┃                   ┃
┃                   ┃
┗━━━━━━━━━━━━━━━━━━━┛</code></pre>
<p>A simple box, but it takes a bit of code to get there, so lets jump in.</p>
<p>First things first, it is better to work off of the FreeBSD documentation or using the man page in macOS, which is essentially the FreeBSD man page. Online, the documentation apple gives is can be found <a href="https://developer.apple.com/documentation/kernel/termios">here</a>. It doesn&#x27;t tell me too much other than the termios structure is rather accessible to me without any weird imports. Importing the Foundation should be good enough.</p>
<h1 id="main-method">Main method</h1>
<p>Next, take a look at the main method, it is fairly straight forward, from there, I will jump into the methods thar are called.</p>
<pre><code>import Foundation</code></pre>
<pre><code>func main() {
  let fd = STDIN_FILENO
  var tio: termios = termios()
  enableRawMode(fd: fd, orig_termios: &amp;tio)
  clearScreen(fd: fd)
  let box = Box(x: 1, y: 1, width: 20, height: 10)
  box.draw()
  while true {
    var buf: UInt8 = 0
    let readResult = read(fd, &amp;buf, 1)
    if readResult &lt; 0 {
      fatalError()
    } else if readResult == 0 {
      break
    } else {
      assert(readResult == 1)
      print(buf)
    }
    if buf == Character(&quot;q&quot;).asciiValue! {
      break
    }
  }
  disableRawMode(fd: fd, tio: &amp;tio)
}</code></pre>
<pre><code>main()</code></pre>
<p>The main.swift file serves as the main entry point and is written a little like a script this way. So my main method needs to be called. If we don&#x27;t want to have to directly invoke main, you need to put the main method in a class or structure and use an attribute of @main to do it. I didn&#x27;t feel it necessary to this here, at least not yet. In the main method, I get the file descripter for STDIN_FILENO, which is the terminal for our purposes. Creating an instance of the termios structure and placing it into a mutable variable named tio. Then, enable raw mode (will get to this later). After that, clear out the screen, make the box and draw it. From there, loop on input, the important part here is that this will infinitely loop unless the user presses the letter q, there is some error handling also. When q is typed, break the loop and disable raw mode. Now, lets get to the fun bits.</p>
<h2 id="enabling-raw-mode">Enabling Raw Mode</h2>
<pre><code>func enableRawMode(fd: Int32, orig_termios: UnsafeMutablePointer&lt;termios&gt;) {
  guard isatty(fd) != 0 else { fatalError() }
  &#x2F;&#x2F; get the original terminal settings
  guard tcgetattr(fd, &amp;orig_termios.pointee) &gt;= 0 else  {
    fatalError(&quot;Issue initializing termina&quot;)
  }
  var tio = orig_termios.pointee
  tio.c_iflag &amp;= ~UInt(IXON | ICRNL | ISTRIP | BRKINT)
  tio.c_oflag &amp;= ~UInt(OPOST)
  tio.c_cflag &amp;= ~UInt(CS8)
  tio.c_lflag &amp;= ~UInt(ICANON | ECHO | ISIG | IEXTEN)
  guard tcsetattr(fd, TCSAFLUSH, &amp;tio) &gt;= 0 else {
    fatalError(&quot;Issue initializing terminal&quot;)
  }
  tcflush(fd, TCIOFLUSH)
}</code></pre>
<p>Enabling raw mode is one of the important functions at play here. We can consider when a terminal is initially launched, it is in &#x27;cooked mode.&#x27; That is sort of the default. Raw mode entails disabling some processing and allowing us to pass input directly to the program running in the terminal rather allowing some default processing to happen. That is a quick birds eye view. These settings are changed by mutating the termios structure.</p>
<p>The arguments are an Int32 named fd (file descriptor) and a rather weird one, UnsafeMutablePointer of type termios named orig termios. File decsriptor is fairly straight forward, but the second one, not so much. Swift allows pointers and there are several kinds, and they are typed via generics. UnsafeMutablePointer is a generic that we can provide the unerlying type. The variable is named orig_termios since we are passing in the termios structure from main and this will be used to get and sort of stash the current settings the terminal operates on by default. This helps later when exiting raw mode and restoring back to where we were.</p>
<p>The first line calls a function in a guard statement to check if is atty. This function takes in a file descriptor and just checks if the file descripter points to a terminal. This is a guard so we don&#x27;t try to pass in a filed descriptor for something like a simple text file named hello.txt. This should fail and throw the fatalError.</p>
<p>Following that is the tcgetattr function. This is how I get the original terminal settings. Or should I say, the termios structure that is tied to STDIN_FILENO tty. It works by passing in the file descriptor and a termios structure. I dereference the termios structurewith &amp;orig termios.pointee. UnsafeMutablePointer is like a wrapper. To get to the value within, we must dereference it&#x27;s pointee property within. Should this fall fail, a fatalError is thrown.</p>
<p>A new instance of a termios structure is created copying the data in the orig_termios. It is dereferenced via the UnsafeMutablePointer&#x27;s pointee. Following that is to manipulate the data within the new instance of termios by setting the flags. Each of these modes are described in detail in the man pages. Quiet a few of them disable processing of things like hitting Ctrl + C. Some hvae to deal with echoing and more. The man page is an interesting read and I really recommend you giving it a <a href="https://man.freebsd.org/cgi/man.cgi?query=termios&sektion=4">read</a>.</p>
<p>Then, we need to do something with tio. We need the terminal to now use it for it&#x27;s tty settings. This is done with <a href="https://man.freebsd.org/cgi/man.cgi?tcsetattr">tcsetattr</a>. This function takes our file descriptor for the terminal, an <em>action</em>, and the reference to the termios struct we want to put there. The action parameter determines when this change takes place. There are three options; TCSAFLUSH, TCSANOW, and TCSADRAIN. I opted for TCSAFLUSH which is described as</p>
<pre><code>The change occurs after all output written to fd has been transmitted to the terminal. Additionally, any input that has been received but not read is discarded.</code></pre>
<p>Finally, calling flush on the file descriptor with <a href="https://man.freebsd.org/cgi/man.cgi?query=tcflush&apropos=0&sektion=3&manpath=FreeBSD+11-current&format=html">tcflush</a>. Once this is done, the new terminal settings will take affect. This also takes an action, which is described in the man page as</p>
<pre><code>Flush both data received but not read and data written but not transmitted.</code></pre>
<h2 id="diabling-raw-mode">Diabling Raw Mode</h2>
<p>Jumping ahead, now lets look at disabling raw mode.</p>
<pre><code>func disableRawMode(fd: Int32, tio: UnsafeMutablePointer&lt;termios&gt;) {
  guard tcsetattr(fd, TCSAFLUSH, &amp;tio.pointee) &gt;= 0 else {
    fatalError(&quot;Issue disabling raw mode&quot;)
  }
}</code></pre>
<p>This is needed to get back to the original settings when the program is being exited. Here the UnsafeMutablePointer for the original termios structure reappears. Inside the function, like when setting the termios structure to disable settings, the termios restructure will be set back to the original settings we saved earlier. If you&#x27;ve got a grip on enabling raw mode, disabling it is easy and simple.</p>
<h2 id="box-structure">Box Structure</h2>
<p>The box to draw is a simple swift structure. This is some of the code for it.</p>
<pre><code>struct Box {
  var x: Int16
  var y: Int16
  var width: Int16
  var height: Int16</code></pre>
<p>    init(x: Int16, y: Int16, width: Int16, height: Int16) {
      self.x = x
      self.y = y
      self.width = width
      self.height = height
    }
  }

This is the base of the structure. For now, I left out the drawing code just to give a demonstration of the data I am working with. This structure has an x and y as a starting point. This serves as the upper left hand corner of the box. I guess, technically rectangle since it&#x27;s sides can be variable length. Then the box has a height and a width. An intializer (constructor in non swift languages) is provided just to initialze the box with its values.</p>
<h2 id="helper-functions">Helper functions</h2>
<p>Before drawing a box, it is good to talk about some helper functions.</p>
<pre><code>import Foundation</code></pre>
<pre><code>func writeToTerminal(fd: Int32, message: String) {
  write(fd, message, message.utf8.count)
}</code></pre>
<pre><code>func jumpToPosition(fd: Int32, x: Int16, y: Int16) {
  writeToTerminal(fd: fd, message: &quot;\u{1b}[\(x);\(y)H&quot;)
}</code></pre>
<p>These are the helper functions for drawing. Two simple functions are needed; writing to terminal and jumping to position. Jumping to position is where we tell the cursor to go on the screen, then from there, we can write linearly along that row. Jump position is an abstraction over writing to the terminal since to do anything, we must write to the terminal. Jump to terminal just formats what we write as the escape sequence to jump the cursor. So instead of writing physical text on the screen, this can be seen as a command to the terminal or a function.</p>
<p>To break down the commands a little, since they look a little weird. Some excellent documentation can be found <a href="https://notes.burke.libbey.me/ansi-escape-codes/">here</a>. For jumping, a focus is on the function in the article described as &#x27;Cursor Position&#x27;. The command written to the terminal looks like</p>
<pre><code>\x1b[x;yH</code></pre>
<p>Or using a point such as (1,1)</p>
<pre><code>\x1b[1;1H</code></pre>
<p>However, swift, I found to be a little funky here. I couldn&#x27;t simple pass in &#x27;x1b&#x27; because I kept getting errors related to an invalid escape sequence. What I found usefule is to use the unicode escape sequence, which luckily evaluates out to the same hex code. the x specifies that the input is hex and the actual escape code is #1B. So instead, using (1,1), for us it looks like</p>
<pre><code>\u1b[1;1H</code></pre>
<p>Writing to the terminal is simple, pass the file descriptor, message and the length of the message by calling on the message&#x27;s utf8 count property.</p>
<h2 id="back-to-main--clearscreen">Back to Main: ClearScreen</h2>
<p>Now with that described, we can address the clearScreen method in main.</p>
<pre><code>func clearScreen(fd: Int32) {
  writeToTerminal(fd: fd, message: &quot;\u{1b}[2J&quot;)
}</code></pre>
<p>I will leave it up to you to figure out what that command does using the documentation linked above. One hint.</p>
<pre><code>\x1b[2J</code></pre>
<h2 id="drawing-the-box">Drawing the Box</h2>
<p>Finally drawing the box, here is the complete code for the Box structure.</p>
<pre><code>import Foundation</code></pre>
<pre><code>struct Box {
  var x: Int16
  var y: Int16
  var width: Int16
  var height: Int16
  init(x: Int16, y: Int16, width: Int16, height: Int16) {
    self.x = x
    self.y = y
    self.width = width
    self.height = height
  }
  func draw() {
    jumpToPosition(fd: STDIN_FILENO, x: self.x, y: self.y+1)
    for _ in x...x+width-1 {
      writeToTerminal(fd: STDIN_FILENO, message: &quot;\u{2501}&quot;)
    } 
    jumpToPosition(fd: STDIN_FILENO, x: x + height, y: y)
    for _ in x...x+width-1 {
      writeToTerminal(fd: STDIN_FILENO, message: &quot;\u{2501}&quot;)
    }
    jumpToPosition(fd: STDIN_FILENO, x: self.x, y: self.y + width)
    writeToTerminal(fd: STDIN_FILENO, message: &quot;\u{2513}&quot;)
    jumpToPosition(fd: STDIN_FILENO, x: self.x, y: self.y)
    writeToTerminal(fd: STDIN_FILENO, message: &quot;\u{250f}&quot;)
    for i in x+1...x+height-1 {
      jumpToPosition(fd: STDIN_FILENO, x: i, y: self.y)
      writeToTerminal(fd: STDIN_FILENO, message: &quot;\u{2503}&quot;)
    }
    jumpToPosition(fd: STDIN_FILENO, x: self.x + height, y: self.y)
    writeToTerminal(fd: STDIN_FILENO, message: &quot;\u{2517}&quot;)
    jumpToPosition(fd: STDIN_FILENO, x: self.x+height, y: self.y + width)
    writeToTerminal(fd: STDIN_FILENO, message: &quot;\u{251b}&quot;)
    for i in x+1...x+height-1 {
      jumpToPosition(fd: STDIN_FILENO, x: i, y: self.y+width)
      writeToTerminal(fd: STDIN_FILENO, message: &quot;\u{2503}&quot;)
    }
  }
}</code></pre>
<p>The addition is the draw function which will render the box to the terminal, taking advanatage of the helper functions to jump to position and write. The algorithm is simple, draw a side and move to another side, occasionally jumping to corners of the box and drawing the corner.</p>
<h2 id="conclusion">Conclusion</h2>
<p>That is the code to draw a box in the terminal in swift. Through it, the terminal was placed into raw mode, and drew the box. Input was polled on the q character, break from the polling and disable raw mode, returning the terminal back to it&#x27;s original set up. </p>
]]></content>
  </entry>
  
  <entry>
    <title type="text">Swift On Linux (2023)</title>
    <id>/post/swift-on-linux/</id>
    <updated>2023-05-23T00:00:00Z</updated>
    <published>2023-05-23T00:00:00Z</published>
    <link href="http://example.org/post/swift-on-linux/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>As seen from previous posts, I have taken to dabbling with Swift on my M1 MacBook Air running MacOS. Now, it is time to take a look at how swift does on Linux. I believe Swift is an interesting language that can bring a rather unique value proposition. As someone who has written Rust for open sourced projects and professionally (for a paycheck) C#, Swift strikes a really interesting balance. In Rust, I sometimes end up at a point where I am tackling a problem and I am thinking to myself, &quot;if only I had X from C# to do this.&quot; And likewise, in C# (especailly when it comes to errors and enums), I hit a situation where I look at something and go, &quot;if I only I had Y from Rust.&quot; Swift, seems to be able to strike that balance some. It has the features of C# I want while also have quiet a few (not all) of the features of Rust I want. So I tend to describe it as, it is a perfect middle ground (or at least the best middel ground present) between C# and Rust.</p>
<h1 id="creating-an-initial-project-on-linux">Creating an initial project on Linux</h1>
<p>My main linux machine right now is running Fedora 37. Swift has been in the main repositories of Fedora for awhile. So getting Swift 5.8 was as simple as invoking the package manager.</p>
<pre><code>sudo dnf install swift</code></pre>
<p>Now, with the basic tool chain installed, it is time to get to work. I create a work space, which was just a folder called &quot;Hello.&quot; Navigating inside of that folder, time to invoke swift to create the project essentially.</p>
<pre><code>swift package init --type executable</code></pre>
<p>This is just to create a simple executable package. Which gives me a little folder structure and a <code>main.swift</code> file.</p>
<pre><code>&#x2F;&#x2F; The Swift Programming Language
&#x2F;&#x2F; https:&#x2F;&#x2F;docs.swift.org&#x2F;swift-book</code></pre>
<pre><code>print(&quot;Hello, world!&quot;)</code></pre>
<p>Just a simple hello world. First, to see if it actually works.</p>
<pre><code>swift build</code></pre>
<p>Okay, it compiles fine apparently. Now, how about running?</p>
<pre><code>swift run</code></pre>
<p>Look like it can at least run a hello world.</p>
<pre><code>╭─todd@fedora ~&#x2F;Learning&#x2F;Swift&#x2F;Hello 
╰─$ swift run
warning: &#x27;hello&#x27;: warning: direct reference to protected function `$sSJ12isWhitespaceSbvg&#x27; in `&#x2F;usr&#x2F;libexec&#x2F;swift&#x2F;5.8&#x2F;bin&#x2F;..&#x2F;lib&#x2F;swift&#x2F;linux&#x2F;libswiftCore.so&#x27; may break pointer equality
Building for debugging...
Build complete! (0.08s)
Hello, world!</code></pre>
<p>Looks like we have lift off.</p>
<h1 id="package-swift">Package.swift</h1>
<p>Creating the project also gives us a <code>Package.swift</code> file. Which, at least shown what we are given, defines some simple things about the package. This is also, I believe, how 3rd party packages can be pulled in. From my understanding, you can do something like define dependencies by linking to their git repos and even specify a release from the repo and during the build phase, it will pull in the code and compile it with the application. Like with all good Linux applications, we need a command line interface, so I will use this as an opportunity to try this out.</p>
<p>There is a library, apparently from a google employee, that help provides a nice way to help build a command line driven program called <a href="https://github.com/objecthub/swift-commandlinekit">CommandlineKit</a>. Unfortunatley, the github repo also appears to make mention of Swift 5.5, but lets hope versioning is on my side here. The current version Fedora has is 5.8 (5.9 should be out with WWDC just happening). So, lets hope it is compatible.</p>
<pre><code>&#x2F;&#x2F; swift-tools-version: 5.8
&#x2F;&#x2F; The swift-tools-version declares the minimum version of Swift required to build this package.</code></pre>
<pre><code>import PackageDescription</code></pre>
<pre><code>let package = Package(
  name: &quot;Hello&quot;,
  dependencies: [
      .package(url: &quot;https:&#x2F;&#x2F;github.com&#x2F;jordanbaird&#x2F;Prism&quot;, from: &quot;0.1.2&quot;),
  ],
  targets: [
      &#x2F;&#x2F; Targets are the basic building blocks of a package, defining a module or a test suite.
      &#x2F;&#x2F; Targets can depend on other targets in this package and products from dependencies.
      .executableTarget(
          name: &quot;Hello&quot;,
          dependencies: [&quot;Prism&quot;],
          path: &quot;Sources&quot;),
  ]
)</code></pre>
<p>Alright, so far, I am impressed. When I first looked at this file, I didn&#x27;t pay much attention to it, but adding a dependency made me actually look at it and see something here. This file defines the package, duh. However, the package is just defined like a <em>struct</em> in Swift. I like this a lot. When the build system is essentially written in the language itself. This is something zig does with <em>zig.build</em>. Rust does have a <em>build.rs</em> but you still have a <em>Cargo.toml</em> file, which is good, but its not optimal. C# has solution and csproj files which are XML&#x2F;XAML&#x2F;XML-like (YUK!).</p>
<p>I think coloring can look pretty good for a command line utility, so Prism is a nice package that looks like it can give some coloring.</p>
<pre><code>&#x2F;&#x2F; The Swift Programming Language
&#x2F;&#x2F; https:&#x2F;&#x2F;docs.swift.org&#x2F;swift-book</code></pre>
<pre><code>import Prism</code></pre>
<pre><code>let text = Prism(spacing: .spaces) {
  ForegroundColor(.green, &quot;This text&#x27;s color is green&quot;)
}</code></pre>
<pre><code>print(text)</code></pre>
<p>It does indeed print the text as green.</p>
<p>Now, lets get some text from the command line and run it.</p>
<pre><code>&#x2F;&#x2F; The Swift Programming Language
&#x2F;&#x2F; https:&#x2F;&#x2F;docs.swift.org&#x2F;swift-book</code></pre>
<pre><code>import Prism
import Foundation</code></pre>
<pre><code>if CommandLine.arguments.isEmpty {
  print(Prism(spacing: .spaces) {
      ForegroundColor(.red, &quot;No input into program&quot;)
  })
}</code></pre>
<pre><code>for argument in CommandLine.arguments {
  print(Prism(spacing: .spaces) {
      ForegroundColor(.green, &quot;Arg: \(argument)&quot;)
  })
}</code></pre>
<pre><code>╭─todd@fedora ~&#x2F;Learning&#x2F;Swift&#x2F;Hello 
╰─$ .&#x2F;.build&#x2F;x86_64-unknown-linux-gnu&#x2F;debug&#x2F;Hello hello
Arg: .&#x2F;.build&#x2F;x86_64-unknown-linux-gnu&#x2F;debug&#x2F;Hello
Arg: hello</code></pre>
<p>So, interestingly enough, there will always be atleast one argument. We also need to ensure we run the program from the debug folder. Using <em>swift run</em> and trying to pass in arguments doesnt work.</p>
<p>To tame, this a little more, there is a nice library that is available called <em>Swift-CommandLineKit</em>. This also introduces in how to do the <em>package.swift</em> file to entertain more than a single dependency.</p>
<pre><code>&#x2F;&#x2F; swift-tools-version: 5.8
&#x2F;&#x2F; The swift-tools-version declares the minimum version of Swift required to build this package.</code></pre>
<pre><code>import PackageDescription</code></pre>
<pre><code>let package = Package(
  name: &quot;Hello&quot;,
  products: [
      .executable(name: &quot;Hello&quot;, targets: [&quot;Hello&quot;])
  ],
  dependencies: [
    .package(url: &quot;https:&#x2F;&#x2F;github.com&#x2F;jordanbaird&#x2F;Prism&quot;, from: &quot;0.1.2&quot;),
    .package(url: &quot;https:&#x2F;&#x2F;github.com&#x2F;objecthub&#x2F;swift-commandlinekit&quot;, from: &quot;0.3.5&quot;)
  ],
  targets: [
      &#x2F;&#x2F; Targets are the basic building blocks of a package, defining a module or a test suite.
      &#x2F;&#x2F; Targets can depend on other targets in this package and products from dependencies.
      .executableTarget(
          name: &quot;Hello&quot;,
          dependencies: [
            .product(name: &quot;Prism&quot;, package: &quot;Prism&quot;),
            .product(name: &quot;CommandLineKit&quot;, package: &quot;swift-commandlinekit&quot;)
          ],
          path: &quot;Sources&quot;),
  ]
)</code></pre>
<p>Now that is sorted, how about something a little more proper?</p>
<pre><code>&#x2F;&#x2F; The Swift Programming Language
&#x2F;&#x2F; https:&#x2F;&#x2F;docs.swift.org&#x2F;swift-book</code></pre>
<pre><code>import CommandLineKit
import Foundation
import Prism</code></pre>
<pre><code>var flags = Flags()</code></pre>
<pre><code>let help = flags.option(&quot;h&quot;, &quot;help&quot;, description: &quot;Show description of usage.&quot;)</code></pre>
<pre><code>try flags.parse()</code></pre>
<pre><code>if help.wasSet {
  print(Prism(spacing: .spaces) {
            ForegroundColor(.red, &quot;hello&quot;)
  })
}</code></pre>
<p>Look like it works so far. However, I want to print the actual flag description. I will change out the string that is printed from <em>ForegroundColor</em>.</p>
<pre><code>print(Prism(spacing: .spaces) {
  ForegroundColor(.red, &quot;\(flags.usageDescription())&quot;)
})</code></pre>
<p>Here is the output</p>
<pre><code>╭─todd@fedora ~&#x2F;Learning&#x2F;Swift&#x2F;Hello 
╰─$ .&#x2F;.build&#x2F;x86_64-unknown-linux-gnu&#x2F;debug&#x2F;Hello -h
USAGE: Hello [&lt;option&gt; ...] [--] [&lt;arg&gt; ...]
OPTIONS:
  -h, --help
    Show description of usage.</code></pre>
<p>Alright, looks like I am getting somewhere. Now to do something a little useful. One thing I am excited to try out eventually is <a href="https://vapor.codes/">Vapor</a>, however before going there, it would be a good idea to make sure any networking at all works as it should. I assume it does, but Swift is such an Apple focused language, there is a chance that perhaps things don&#x27;t work exactly as they should. So, my plan is to add a REST API call to a free HTTP REST API for a <a href="https://deckofcardsapi.com/">deck of card</a>. There will be a new flag which will be called &#x27;new&#x27; that will request a new deck from the API. I am not going to worry about actually deserializing the returned JSON, just make the call and ensure that I get back a 200 OK response.</p>
<p>The following is the endpoint to hit.</p>
<pre><code>https:&#x2F;&#x2F;deckofcardsapi.com&#x2F;api&#x2F;deck&#x2F;new&#x2F;shuffle&#x2F;?deck_count=1</code></pre>
<p>Here is the code</p>
<pre><code>&#x2F;&#x2F; The Swift Programming Language
&#x2F;&#x2F; https:&#x2F;&#x2F;docs.swift.org&#x2F;swift-book</code></pre>
<pre><code>import CommandLineKit
import Foundation
import FoundationNetworking
import Prism</code></pre>
<pre><code>var flags = Flags()</code></pre>
<pre><code>let help = flags.option(&quot;h&quot;, &quot;help&quot;, description: &quot;Show description of usage.&quot;)</code></pre>
<pre><code>let newDeck = flags.option(&quot;n&quot;, &quot;new&quot;, description: &quot;Request a new deck.&quot;)</code></pre>
<pre><code>try flags.parse()</code></pre>
<pre><code>if help.wasSet {
  print(Prism(spacing: .spaces) {
            ForegroundColor(.yellow, &quot;\(flags.usageDescription())&quot;)
        })
  exit(0);
}</code></pre>
<pre><code>if newDeck.wasSet {
  let semaphore = DispatchSemaphore(value: 0)
  
  guard let url = URL(string: &quot;https:&#x2F;&#x2F;deckofcardsapi.com&#x2F;api&#x2F;deck&#x2F;new&#x2F;shuffle&#x2F;?deck_count=1&quot;) else {
      print(Prism(spacing: .spaces) {
                ForegroundColor(.red, &quot;Error making url&quot;)
            })
      exit(0)
  }</code></pre>
<pre><code>let task = URLSession.shared.dataTask(with: url) {
    (data, response, error) in
    guard let data = data, error == nil else {
        fatalError(error!.localizedDescription)
    }
    print(&quot;Error: \(String(describing: response))&quot;)
    print(&quot;Fetched data size: \(data)&quot;)
    semaphore.signal()
}</code></pre>
<p>    task.resume()
    semaphore.wait()
  }

Lets do a diff to see the difference.</p>
<pre><code>diff main.swift.old main.swift &gt; diff</code></pre>
<p>Now the contents of the diff</p>
<pre><code>--- main.swift.old	2023-06-07 21:34:11.054633442 -0700
+++ main.swift	2023-06-07 21:29:47.711075885 -0700
@@ -3,16 +3,45 @@
import CommandLineKit
import Foundation
+import FoundationNetworking
import Prism
var flags = Flags()
let help = flags.option(&quot;h&quot;, &quot;help&quot;, description: &quot;Show description of usage.&quot;)
+let newDeck = flags.option(&quot;n&quot;, &quot;new&quot;, description: &quot;Request a new deck.&quot;)
+
try flags.parse()
if help.wasSet {
     print(Prism(spacing: .spaces) {
-              ForegroundColor(.red, &quot;\(flags.usageDescription)&quot;)
-    })
-}
\ No newline at end of file
+              ForegroundColor(.yellow, &quot;\(flags.usageDescription())&quot;)
+          })
+    exit(0);
+}
+
+if newDeck.wasSet {
+    let semaphore = DispatchSemaphore(value: 0)
+    
+    guard let url = URL(string: &quot;https:&#x2F;&#x2F;deckofcardsapi.com&#x2F;api&#x2F;deck&#x2F;new&#x2F;shuffle&#x2F;?deck_count=1&quot;) else {
+        print(Prism(spacing: .spaces) {
+                  ForegroundColor(.red, &quot;Error making url&quot;)
+              })
+        exit(0)
+    }
+
+    let task = URLSession.shared.dataTask(with: url) {
+        (data, response, error) in
+        guard let data = data, error == nil else {
+            fatalError(error!.localizedDescription)
+        }
+
+        print(&quot;Response: \(String(describing: response))&quot;)
+        print(&quot;Fetched data size: \(data)&quot;)
+        semaphore.signal()
+    }
+
+    task.resume()
+    semaphore.wait()
+}</code></pre>
<p>The first change is a little odd, or atleast, I have not seen it in swift projects on macOS. From what I have seen, you only need to import <em>FoundationNetworking</em> on linux and potentially other non-macOS operating systems such as Windows?</p>
<p>A new flag option is added for requesting a new deck.</p>
<p>The next biggest change is down towards the bottom where the program handles if an option is set for <em>newDeck</em>. A semaphore is needed to make the program wait for the task to finish as seen in the lower portion of the program. Otherwise, creat a URL object from a string representation of the URL, using a guard let for if for some reason that fails. Followed by creating a <em>URLSession</em> with a <em>dataTask</em> using the url. A closure takes in <em>data</em>, <em>response</em>, and <em>error</em>. If <em>error</em> <strong>is not</strong> nil, then perform a <em>fatalError</em>.  Otherwise, print the response and the data. The data, with how it is being printed, will only print the length of the data. Signal the semaphore so that way we can resume and finish out the program,</p>
<pre><code>╭─todd@fedora ~&#x2F;Learning&#x2F;Swift&#x2F;Hello 
╰─$ .&#x2F;.build&#x2F;x86_64-unknown-linux-gnu&#x2F;debug&#x2F;Hello -n
Response: Optional(&lt;HTTPURLResponse 0x00007f8f2c12f6d0&gt; { URL: https:&#x2F;&#x2F;deckofcardsapi.com&#x2F;api&#x2F;deck&#x2F;new&#x2F;shuffle&#x2F;?deck_count=1 }{ status: 200, headers {
   &quot;Access-Control-Allow-Origin&quot; = *;
   &quot;Alt-Svc&quot; = h3=&quot;:443&quot;; ma=86400;
   &quot;Cf-Cache-Status&quot; = DYNAMIC;
   &quot;Cf-Ray&quot; = 7d3e7e4f3ec5eb73-SEA;
   &quot;Content-Encoding&quot; = br;
   &quot;Content-Type&quot; = &quot;application&#x2F;json&quot;;
   &quot;Date&quot; = Thu, 08 Jun 2023 04:46:50 GMT;
   &quot;Nel&quot; = {&quot;success_fraction&quot;:0,&quot;report_to&quot;:&quot;cf-nel&quot;,&quot;max_age&quot;:604800};
   &quot;Referrer-Policy&quot; = same-origin;
   &quot;Report-To&quot; = {&quot;endpoints&quot;:[{&quot;url&quot;:&quot;https:\&#x2F;\&#x2F;a.nel.cloudflare.com\&#x2F;report\&#x2F;v3?s=29uaD8qnUgUPvB1r5yx0zVHRvkrKn%2BxmSIEJZre%2FcZmGzVhlcshKWNymfLhVxSdRi4pvg4pmMuMIHMbenKYeaYTU0Wo%2F66xNGTCCzFbaRa4pAOizwibFnSJPYw5%2FeivxrkKlYhY9hTJt00s1E5%2BlFZg%3D&quot;}],&quot;group&quot;:&quot;cf-nel&quot;,&quot;max_age&quot;:604800};
   &quot;Server&quot; = cloudflare;
   &quot;Vary&quot; = Origin;
   &quot;x-content-type-options&quot; = nosniff;
   &quot;x-frame-options&quot; = DENY;
} })
Fetched data size: 79 bytes</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="text">Roku ECP Programming with Swift 2</title>
    <id>/post/swift-ecp-programming-2/</id>
    <updated>2023-05-23T00:00:00Z</updated>
    <published>2023-05-23T00:00:00Z</published>
    <link href="http://example.org/post/swift-ecp-programming-2/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<p>In the previous <a href="https://enigmaticbits.com/post/swift-ecp-programming-1/">article</a>, I went over a little bit about discovery of Roku devices on the network. Accomplished by sending out a UDP call on port 239.255.255.250 on port 1900. A response comes back with the a message with two important blocks of information, the unique device identifier and the IP address for the device on the local area network. Now, for a little bit of code to make the device do something.</p>
<p>Looking at the <a href="https://developer.roku.com/docs/developer-program/dev-tools/external-control-api.md">documentation</a>, there are a number of endpoints we can hit on the device&#x27;s HTTP REST server. The initial one we will target is the keypress, since this is probably the most basic thing we want to do. We want to be able to navigate the screen. In the table where it talks about the endpoint, we can also see there is a link which takes up to how we can specify the <a href="https://developer.roku.com/docs/developer-program/dev-tools/external-control-api.md#keypress-key-values">key</a>.</p>
<p>A little bit below that on the page, it shows some examples using curl. While I did this for some initial playing, the main point of interest is to be able to control the thing via code written in swift.</p>
<pre><code>import Foundation</code></pre>
<pre><code>let host = &quot;192.168.0.14&quot;
let port = 8060</code></pre>
<pre><code>let direction = &quot;Right&quot;</code></pre>
<pre><code>let url: URL? = URL(string: &quot;http:&#x2F;&#x2F;\(host):\(port)&#x2F;keypress&#x2F;\(direction)&quot;)
var request: URLRequest = URLRequest(url: url!)
request.httpMethod = &quot;POST&quot;
print(&quot;Sending request&quot;)</code></pre>
<pre><code>let (data, response) = try await URLSession.shared.data(for: request)</code></pre>
<pre><code>print(&quot;Response: \(response)&quot;)</code></pre>
<p>The code is simple. Just a quick script to run in Swift playgrounds. The request for a keypress must be sent as a <em>POST</em> request, so the method is set. Using string interpolation, we set the url. The full url looks like so</p>
<pre><code>http:&#x2F;&#x2F;192.169.0.14:8060&#x2F;keypress&#x2F;Right</code></pre>
<p>Using swift&#x27;s async&#x2F;await, make the request and print out the response. The following is the response we get back</p>
<pre><code>&lt;NSHTTPURLResponse: 0x1286d4790&gt; { URL: http:&#x2F;&#x2F;192.168.0.14:8060&#x2F;keypress&#x2F;Left } { Status Code: 200, Headers {
  &quot;Content-Length&quot; =     (
      0
  );
  Server =     (
      &quot;Roku&#x2F;12.0.0 UPnP&#x2F;1.0 Roku&#x2F;12.0.0&quot;
  );
} }</code></pre>
<p>Not a whole lot of exciting data, the most important bit is the status code of 200 telling us everything went well.</p>
<p>The API provides a lot of different endpoints with my main focus being on keypress. It provides the usualy expected navigation such as left, right, up, and down. Along with an endpoint for home, back and several others.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="text">Roku ECP Programming with Swift 1</title>
    <id>/post/swift-ecp-programming-1/</id>
    <updated>2023-05-22T19:42:16Z</updated>
    <published>2023-05-22T19:42:16Z</published>
    <link href="http://example.org/post/swift-ecp-programming-1/" />
    <author>
      <name>Todd Martin</name>
      <email>kj4ntv@gmail.com</email>
    </author>
    <content type="html"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>Here recently, I have taken to dabble in swift a little bit. A little bit of a shout out to <a href="https://www.hackingwithswift.com/">Hacking With Swift</a> for some great tutorials to get started with swift. This came about with my recently acquiring an Apple watch SE. I figured, I had a M1 Macbook Air, I might as well play around in the ecosystem some. One thing I&#x27;ve ran into recently as a headache is dealing with my Roku. Great little devices, but with small kids, I always seem to permanently loose the Roku remote. So we started using the Roku app on our phones in lieu. However, the app is rather clunky and a pain to deal with. However, I found some neat <a href="https://developer.roku.com/docs/developer-program/dev-tools/external-control-api.md">documentation</a> on how to interact with the Rokue with my own code.</p>
<h1 id="simple-service-discovery-protocol">Simple Service Discovery Protocol</h1>
<p>First thing we may want to do is to be able to do is discover any roku devices on our network. Roku make their devices discoverable using <a href="https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol">SSDP</a> (Simple Service Discovery Protocol). It is a simple protocol to be able to query on a network for any kind of devices and to get some information on them. In the context of a roku device, it will send us information on how to communicate further over TCP directly with the device. Lets take a look at the request and response in Wireshark.</p>
<h2 id="sending-out-the-query-for-devices">Sending out the query for Devices</h2>
<p>We can make thie query by sending a UDP packet to 239.255.255.250 on port 1900. All Roku devices listen on this. The packet we send is fairly simple.</p>
<pre><code>M-SEARCH * HTTP&#x2F;1.1
Host: 239.255.255.250:1900
Man: &quot;ssdp:discover&quot;
ST: roku:ecp</code></pre>
<p>That goes into the body of the UDP packet being sent out. The bottom of the packet does require a carriage return line feed (rn). So it looks more like this</p>
<pre><code>M-SEARCH * HTTP&#x2F;1.1\r\n
Host: 239.255.255.250:1900\r\n
Man: &quot;ssdp:discover&quot;\r\n
ST: roku:ecp\r\n
\r\n</code></pre>
<h2 id="what-we-get-in-response">What we get in response</h2>
<p>In response we get the following, at least for the details we care about.</p>
<pre><code>Frame 5110: 268 bytes on wire (2144 bits), 268 bytes captured (2144 bits) on interface en0, id 0
Ethernet II, Src: Roku_b3:68:af (ac:ae:19:b3:68:af), Dst: Apple_46:9e:c8 (3c:a6:f6:46:9e:c8)
Internet Protocol Version 4, Src: 192.168.0.14, Dst: 192.168.0.88
User Datagram Protocol, Src Port: 1900, Dst Port: 57101
Simple Service Discovery Protocol
  HTTP&#x2F;1.1 200 OK\r\n
  Cache-Control: max-age=3600\r\n
  ST: roku:ecp\r\n
  USN: uuid:roku:ecp:YH000T494575\r\n
  Ext: \r\n
  Server: Roku&#x2F;12.0.0 UPnP&#x2F;1.0 Roku&#x2F;12.0.0\r\n
  LOCATION: http:&#x2F;&#x2F;192.168.0.14:8060&#x2F;\r\n
  device-group.roku.com: 3022633342B2DCFCBCB2\r\n
  \r\n
  [HTTP response 1&#x2F;1]</code></pre>
<p>In the response, we get a HTTP 200 OK. The two important fields we care about are the USN and the LOCATION. The USN has a uuid which in the above is YH000T494575. This uniquely identifies an individual Roku on a network with several other Rokus. The location is going to tell us where it&#x27;s webserver lives. All Roku webservers live on port 8060 according to the documentation. So we don&#x27;t really need the query for that. What we care most about is the IP address tied to that specific Roku. With this, we can now use the REST API that each Roku runs in order to fully control it.</p>
<h1 id="code">Code</h1>
<p>The following is some simple code drafted up in a playground.</p>
<pre><code>import Foundation
import Network</code></pre>
<pre><code>let hostUDP: NWEndpoint.Host = &quot;239.255.255.250&quot;
let portUDP: NWEndpoint.Port = 1900</code></pre>
<pre><code>let packet = &quot;M-SEARCH * HTTP&#x2F;1.1\r\nHost: \(hostUDP):\(portUDP)\r\nMan: \&quot;ssdp:discover\&quot;\r\nST: roku:ecp\r\n\r\n&quot;</code></pre>
<pre><code>print(&quot;Packet to send:\n\(packet)&quot;)</code></pre>
<pre><code>let connection: NWConnection? = NWConnection(host: hostUDP, port: portUDP, using: .udp)</code></pre>
<pre><code>connection?.stateUpdateHandler = { (newState) in
  switch(newState) {
  case .ready:
    print(&quot;State: ready\n&quot;)
    let content = packet.data(using: String.Encoding.utf8)
    connection?.send(content: content, completion: NWConnection.SendCompletion.contentProcessed(({ (NWError) in
      if (NWError == nil) {
        print(&quot;Data was sent&quot;)
      } else {
        print(&quot;Error: \(String(describing: NWError))&quot;)
      }
    })))
  case .setup:
    print(&quot;Setup\n&quot;)
  case .cancelled:
    print(&quot;Cancelled\n&quot;)
  case .preparing:
    print(&quot;Preparing\n&quot;)
  default:
    print(&quot;State not defined\n&quot;)
  }
}</code></pre>
<pre><code>connection?.start(queue: .global())</code></pre>
<pre><code>while(true) { }</code></pre>
<p>Here you will need to bear with me since its been awhile since I&#x27;ve done any programming with UDP and more specifically, my first time with Swift. The beginning of the code is faily simple, import some libraries and create some variables for the host and port. I also type out the search packet with string interpolation for the port and host. Next, using NWConnection, start creating the connection. After that is the handler. One thing of importance here is, the connection must be in the <em>ready</em> state in order to send or receive. In this program, receiving is not handled. I did the receiving in wireshark. At the bottom, start the connection on the global DispactchQueue and enter in an infinite while loop. This is just the keep the program running as the DispatchQueue works it&#x27;s way through the various states in the UDP socket and sends our request packet.</p>
]]></content>
  </entry>
  
</feed>
