<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>dave eddy</title>
		<description>All Dropped Packets go to Heaven</description>
		<link type="application/atom+xml" href="https://www.daveeddy.com" rel="self"/>
		<link type="text" href="https://www.daveeddy.com" rel="alternate"/>
		<atom:link href="https://www.daveeddy.com/rss.xml" rel="self" type="application/rss+xml" />
		<updated>2024-06-02T21:13:41-04:00</updated>
		<id>https://www.daveeddy.com</id>
		<rights>Copyright (c) 2024 dave eddy</rights>
		
		<item>
			<title>You Suck at Programming</title>
			<link>https://www.daveeddy.com/2024/03/23/you-suck-at-programming/</link>
			<updated>2024-03-23T00:00:00-04:00</updated>
			<pubDate>2024-03-23T00:00:00-04:00</pubDate>
			<id>https://www.daveeddy.com/2024/03/23/you-suck-at-programming/</id>
			<gid>https://www.daveeddy.com/2024/03/23/you-suck-at-programming/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;In late 2022 I started a new series on TikTok called You Suck at Programming.
In it I mostly talk about really cool Bash and Unix tricks and pitfalls and just
general advice.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://ysap.daveeddy.com&quot;&gt;&lt;img src=&quot;/static/media/2024/ysap.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;I recently went through and cataloged all of the episodes and made them
available on a new website that you can view in the browser, or on your
terminal:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://ysap.daveeddy.com&quot;&gt;&lt;img src=&quot;/static/media/2024/ysap-tiktok.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To pull the episodes run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ curl ysap.daveeddy.com
 _   _ ___  __ _ _ __
| | | / __|/ _` | '_ \   You suck at programming
| |_| \__ \ (_| | |_) |  Episodes and guide by dave eddy
 \__, |___/\__,_| .__/   https://www.daveeddy.com
  __/ |         | |
 |___/          |_|      Source: https://github.com/bahamas10/you-suck-at-programming

...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</summary>
		</item>
		
		<item>
			<title>Void Linux Bhyve Image on OmniOS</title>
			<link>https://www.daveeddy.com/2022/09/19/void-linux-bhyve-image-on-omnios/</link>
			<updated>2022-09-19T00:00:00-04:00</updated>
			<pubDate>2022-09-19T00:00:00-04:00</pubDate>
			<id>https://www.daveeddy.com/2022/09/19/void-linux-bhyve-image-on-omnios/</id>
			<gid>https://www.daveeddy.com/2022/09/19/void-linux-bhyve-image-on-omnios/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;&lt;a href=&quot;/static/media/2022/bhyve-void/omnios-on-void.jpg&quot;&gt;&lt;img src=&quot;/static/media/2022/bhyve-void/omnios-on-void.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This guide will show how to install &lt;a href=&quot;https://voidlinux.org&quot;&gt;Void Linux&lt;/a&gt; as a guest on
&lt;a href=&quot;https://omnios.org&quot;&gt;OmniOS&lt;/a&gt; using hardware virtualization with &lt;a href=&quot;https://bhyve.org&quot;&gt;bhyve&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;configure-the-system&quot;&gt;Configure the system&lt;/h1&gt;

&lt;p&gt;To get started, first install &lt;a href=&quot;https://github.com/omniosorg/zadm&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zadm&lt;/code&gt;&lt;/a&gt; on OmniOS inside the global zone.
This tool makes creating and managing zones simple and is reminiscent of the
&lt;a href=&quot;https://wiki.smartos.org/managing-instances-with-vmamd/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmadm&lt;/code&gt;&lt;/a&gt; command on &lt;a href=&quot;https://smartos.org&quot;&gt;SmartOS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zadm&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pkg install zadm
pkg install zones/brand/bhyve
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I personally use this config for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zadm&lt;/code&gt; (shoutouts to
&lt;a href=&quot;http://mikezeller.net&quot;&gt;@papertigers&lt;/a&gt; for this), but feel free to customize this as you
like.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/opt/ooce/zadm/zadm.conf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;CONFIG&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;format&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;toml&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;CONSOLE&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;auto_connect&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;off&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;auto_disconnect&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;on&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;escape_char&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;SNAPSHOT&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;prefix&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;zadm__&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Test that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zadm&lt;/code&gt; was installed and works as expected by running:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@datadyne:~# zadm list
NAME              STATUS     BRAND       RAM    CPUS  SHARES
global            running    ipkg       256G      64       1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that for this blog post I ran all of these commands on a fresh system so
only 1 zone is running (the global zone).&lt;/p&gt;

&lt;p&gt;Create the datasets needed.  You can customize these if you’d like but for the
sake of this post I’ll be using these datasets:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;zfs create -o mountpoint=/zones rpool/zones
zfs create rpool/zones/config
zfs create rpool/zones/data
zfs create rpool/zones/zones
mkdir /zones/config/iso
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zones/config&lt;/code&gt; toml files for each zone used during zone creation.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zones/data&lt;/code&gt; dataset to store persistent data for each zone that can be LOFS
mounted into the zone.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zones/zones&lt;/code&gt; confusingly named, but each zones root data will live in this
  directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a zone named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo&lt;/code&gt; would have files like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zones/config/foo.toml&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zones/data/foo&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zones/zones/foo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;create-the-initial-void-vm&quot;&gt;Create the initial void VM&lt;/h1&gt;

&lt;p&gt;Pull the full ISO from the void Linux download page.  I’m using the “Base Live
Image x86_64 glibc” for this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://voidlinux.org/download/&quot;&gt;https://voidlinux.org/download/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Download this ISO (yours might be named differently) to the machine:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd /zones/config/iso
wget https://alpha.de.repo.voidlinux.org/live/current/void-live-x86_64-20210930.iso
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create the zone toml file:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zones/config/void-golden-image.toml&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;py&quot;&gt;zonename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;void-golden-image&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;cdrom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/zones/config/iso/void-live-x86_64-20210930.iso&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;zonepath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/zones/zones/void-golden-image&quot;&lt;/span&gt;

&lt;span class=&quot;py&quot;&gt;ram&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2G&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;vcpus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4&quot;&lt;/span&gt;

&lt;span class=&quot;py&quot;&gt;dns-domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rapture.com&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;resolvers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=[&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;10.0.1.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;10.0.1.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;py&quot;&gt;acpi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;on&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;xhci&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;on&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;autoboot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;bootorder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cd&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;brand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bhyve&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ip-type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;exclusive&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;limitpriv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[capped-memory]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# should match global &quot;ram&quot; key above&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;physical&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2G&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2G&quot;&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[[net]]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# will use DHCP when creating the golden image&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;global-nic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;e1000g0&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;physical&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;voidgoldenimage0&quot;&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[bootdisk]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;blocksize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;8K&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rpool/zones/zones/void-golden-image/root&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;50G&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;sparse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[vnc]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# needed for installation&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;on&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are a lot of options in this toml file, but hopefully most of them are
self-explanatory - just make sure to update options like the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dns-domain&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global-nic&lt;/code&gt; to match your environment.&lt;/p&gt;

&lt;p&gt;Create the zone:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo zadm create create -b bhyve -t void-golden-image.toml void-golden-image
sudo zadm boot void-golden-image
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Verify with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo zadm list void-golden-image
NAME              STATUS     BRAND       RAM    CPUS  SHARES
void-golden-image running    bhyve        2G       4       1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this point the zone should be running, and inside the zone is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bhyve&lt;/code&gt;
process, which is responsible for booting the Void Linux image.  We can’t quite
connect to the console using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zadm console&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zlogin -C&lt;/code&gt;, so for now we must
use VNC.  Luckily, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zadm&lt;/code&gt; comes with a simple VNC server built-in.&lt;/p&gt;

&lt;p&gt;Create VNC server (leave this command running):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo zadm webvnc 0.0.0.0:8080 void-golden-image
Web application available at http://0.0.0.0:8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you are quick enough you may be able to see this grub menu!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2022/bhyve-void/void-grub.jpg&quot;&gt;&lt;img src=&quot;/static/media/2022/bhyve-void/void-grub.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If not don’t worry, grub will automatically pick the top option which is what we
want.&lt;/p&gt;

&lt;p&gt;You should end up with a screen that looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2022/bhyve-void/void-installer-console.jpg&quot;&gt;&lt;img src=&quot;/static/media/2022/bhyve-void/void-installer-console.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As it says in the output, you can now login with the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; and the
password &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;voidlinux&lt;/code&gt;.  At this point I prefer to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bash&lt;/code&gt;, so I’m using the
bash shell for the installation process as opposed to just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/bin/sh&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;install-void-linux&quot;&gt;Install Void Linux&lt;/h1&gt;

&lt;p&gt;Now, run the command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;void-installer&lt;/code&gt; to bring up the graphical installer - it
should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2022/bhyve-void/void-installer.jpg&quot;&gt;&lt;img src=&quot;/static/media/2022/bhyve-void/void-installer.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;void-installer&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;p&gt;In the installer make sure to set these options:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RootPassword&lt;/code&gt; - set to something you’ll remember&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BootLoader&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Set “use graphical terminal?” to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Partition&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cfdisk&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpt&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;disk-partitions&quot;&gt;Disk Partitions&lt;/h2&gt;

&lt;p&gt;Now, you should be inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cfdisk&lt;/code&gt; to set up the underlying hard drive (the 50G
disk created in the toml file) for Void.  Create the following:&lt;/p&gt;

&lt;p&gt;3 partitions&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/vda1&lt;/code&gt;: 1G, EFI System&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/vda2&lt;/code&gt;: 2G, Linux swap&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/vda3&lt;/code&gt;: 47G (remaining), Linux filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your output should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2022/bhyve-void/void-cfdisk.jpg&quot;&gt;&lt;img src=&quot;/static/media/2022/bhyve-void/void-cfdisk.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Make sure to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write&lt;/code&gt; before &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;quit&lt;/code&gt; - otherwise your changes won’t be
saved.&lt;/p&gt;

&lt;h2 id=&quot;file-systems&quot;&gt;File Systems&lt;/h2&gt;

&lt;p&gt;With the partitions created you can now create the file systems in the
installer, they should be this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileSystems&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/vda1&lt;/code&gt;: vfat (FAT32) - mounted at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot/efi&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/vda1&lt;/code&gt;: swap (Linux Swap)&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/vda1&lt;/code&gt;: xfs (SGI’s XFS) - mounted at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xfs&lt;/code&gt; is optional - pick whatever filesystem you prefer.&lt;/p&gt;

&lt;p&gt;Finally, click &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Install&lt;/code&gt; and everything should just work.&lt;/p&gt;

&lt;h2 id=&quot;efi-configuration&quot;&gt;EFI Configuration&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DON’T REBOOT - we’re not done yet!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Back in the live system and outside of the installer, mount the newly installed
boot partition:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mount /dev/vda1 /mnt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Move the grub efi file into the proper location (from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot/efi/EFI/void_grub/grubx64.efi&lt;/code&gt; -&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot/efi/EFI/BOOT/bootx64.efi&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mv /mnt/EFI/void_grub /mnt/EFI/BOOT
mv /mnt/EFI/BOOT/grubx64.efi /mnt/EFI/BOOT/bootx64.efi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Unmount the filesystem and power off the machine:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;umount /mnt
poweroff
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;configure-serial-console&quot;&gt;Configure serial console&lt;/h2&gt;

&lt;p&gt;Inside the global zone, edit the zones config file with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zadm&lt;/code&gt; to remove the CD
device (I just commented the lines out for my system):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo zadm edit void-golden-image
...
# cdrom=[
#   &quot;/zones/config/iso/void-live-x86_64-20210930.iso&quot;
# ]
...
$ sudo zadm boot void-golden-image
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This way, the machine will boot from the newly installed OS from the hard drive
and not the CD ROM (where the installer ISO was mounted).&lt;/p&gt;

&lt;p&gt;You may have to refresh the VNC webpage to access the zone, if it all works you
should see a login prompt.  You can use the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; with the root password
you setup earlier:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2022/bhyve-void/void-console.jpg&quot;&gt;&lt;img src=&quot;/static/media/2022/bhyve-void/void-console.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before going any further, we can make our lives easier by enabling the serial
console:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ln -s /etc/sv/agetty-ttyS0 /var/service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, instruct grub to work over the serial console as well.  Add these lines
(or modify the existing lines) in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/default/grub&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;loglevel=4 console=ttyS0,115200n8&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;GRUB_TERMINAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;serial
&lt;span class=&quot;nv&quot;&gt;GRUB_SERIAL_COMMAND&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;update-grub
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, power off the machine again:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;poweroff
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, from the global zone, boot the machine and connect to the console.  We can
do this all in one single command so we don’t miss anything on the console when
the machine powers on:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo zadm boot -C void-golden-image
[Connected to zone 'void-golden-image' console]

[NOTICE: Zone booting up]
Loading Linux 5.13.19_1 ...
Loading initial ramdisk ...
- runit: $Id: 25da3b86f7bed4038b8a039d2f8e8c9bbcf0822b $: booting.
- runit: enter stage: /etc/runit/1
=&amp;gt; Welcome to Void!
...
_.
$
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Use the escape sequence defined in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zadm&lt;/code&gt; config to break out of the console
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_.&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;If everything works, then you should see the kernel messages via the console on
the terminal and not have to rely on VNC.&lt;/p&gt;

&lt;h2 id=&quot;setup-the-vm-image&quot;&gt;Setup the VM image&lt;/h2&gt;

&lt;p&gt;From here you are able to setup this machine however you’d like!  I’d recommend
running updates and installing some optional tools like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;xbps-install -Syu
xbps-install jq htop bwm-ng vim vsv vpm bat fd ripgrep
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check running services with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vsv&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2022/bhyve-void/void-vsv.jpg&quot;&gt;&lt;img src=&quot;/static/media/2022/bhyve-void/void-vsv.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also remove the existing virtual terminals if you just plan on using the
serial console.  I personally leave one active in the event that I need to VNC
back in for whatever reason.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rm /var/service/agetty-tty{2..6}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After you do whatever setup you’d like for the base image, we can get this
prepared to be cloned for future VMs.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshd&lt;/code&gt; is configured on Void Linux to generate new host keys if none exist when
the service is started.  These commands will make it so new keys will be
generated on the next
reboot:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sv down sshd
rm /etc/ssh/*_host_*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, optionally setup the skeleton for a static IP address (if you don’t want
to use DHCP):&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/rc.local&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#ip link set dev eth0 up
#ip addr add 10.0.1.53/24 brd + dev eth0
#ip route add default via 10.0.1.1
&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# mkdir -p /data
# mount /data
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I leave these commented out in the golden image so I can simply uncomment them
and modify them when I create a new machine.&lt;/p&gt;

&lt;p&gt;The last thing I like to do is a put a text file like this in the root home
directory - this is for future me so I can quickly remember how to setup a new
machine that I clone from this image:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[root@void-golden-image ~]# cat getting-started.txt
1. run `hostname` and edit `/etc/hostname`
2. disable `dhcpcd`
3. put IP info in `/etc/rc.local`
4. put DNS info in `/etc/resolv.conf`
5. reboot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Break out of the console using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_.&lt;/code&gt; or whatever you’ve defined.&lt;/p&gt;

&lt;h2 id=&quot;create-the-image&quot;&gt;Create the image&lt;/h2&gt;

&lt;p&gt;Snapshot the image root disk:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo zfs snapshot rpool/zones/zones/void-golden-image/root@golden-2022-05-23
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we have this image which is ready to be cloned for new VMs to make the
installation process way easier for us!&lt;/p&gt;

&lt;h2 id=&quot;create-a-new-instance-of-the-vm&quot;&gt;Create a new instance of the VM&lt;/h2&gt;

&lt;p&gt;We’re going to create a new VM named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;void-test&lt;/code&gt; using this image.  Create a new
toml file:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zones/config/void-test.toml&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;py&quot;&gt;zonename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;void-test&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;zonepath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/zones/zones/void-test&quot;&lt;/span&gt;

&lt;span class=&quot;py&quot;&gt;ram&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2G&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;vcpus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4&quot;&lt;/span&gt;

&lt;span class=&quot;py&quot;&gt;dns-domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rapture.com&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;resolvers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=[&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;10.0.1.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;10.0.1.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;py&quot;&gt;acpi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;on&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;xhci&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;on&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;autoboot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;bootorder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cd&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;brand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bhyve&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ip-type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;exclusive&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;limitpriv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;default&quot;&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[capped-memory]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# should match global &quot;ram&quot; key above&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;physical&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2G&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2G&quot;&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[[net]]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# using static IP for this instance&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;allowed-address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;10.0.1.54/24&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;defrouter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;10.0.1.1&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;global-nic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;e1000g0&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;physical&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;voidtest0&quot;&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[bootdisk]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;blocksize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;8K&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rpool/zones/zones/void-test/root&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;50G&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;sparse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[vnc]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# needed for installation&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;on&quot;&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[[fs]]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/data&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;special&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/zones/data/void-test&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lofs&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=[]&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[[virtfs]]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;data&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/data&quot;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is a lot of new stuff in this toml - I’ll go through all of it below.
Create a new dataset for the VMs persistent storage and then create the zone&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo zfs create rpool/zones/data/void-test
sudo zadm create create -b bhyve -t void-test.toml void-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Before booting the machine, we destroy the created root disk and clone the
golden image into the same location:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo zfs destroy rpool/zones/zones/void-test/root
sudo zfs clone rpool/zones/zones/void-golden-image/root@golden-2022-05-23 rpool/zones/zones/void-test/root
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This means that we have a brand new zone and VM created, but the root disk is a
clone of the golden image we created above.  Boot the VM with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo zadm boot -C void-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The username and password are the same as we set above for the image we created.
To configure this new instance we have instructions waiting for us:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cat getting-started.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Following those instructions I simply ran:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;hostname void-test
hostname &amp;gt; /etc/hostname
rm /var/service/dhcpcd
vim /etc/rc.local
vim /etc/resolv.conf
reboot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;persistent-data&quot;&gt;Persistent data&lt;/h2&gt;

&lt;p&gt;It may be confusing that I keep talking about persistent data in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zone/data/void-test&lt;/code&gt; when all of the data on the VM is technically persistent.
The point of this is to a have a mount that exists in the zone that won’t be
tied to the VM itself and won’t contain any OS installation files.&lt;/p&gt;

&lt;p&gt;When just using zones, we accomplish this by LOFS mounting (analogous to bind
mounts in Linux) files from the global zone into the zone.  We are going to do
that as well here (in fact, we do that in the toml file in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[[fs]]&lt;/code&gt;
sections).  But, we must go a step further because of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bhyve&lt;/code&gt; and expose those
mounts inside the zone into the hardware VM itself.&lt;/p&gt;

&lt;p&gt;We accomplish this through 9pfs.&lt;/p&gt;

&lt;p&gt;In the void VM you have newly created you must install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9mount&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;xbps-install 9mount
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, you can add this line to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;data /data 9p rw,relatime,dirsync,uname=root,cache=mmap,access=client,trans=virtio,_netdev 0 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And make sure the mount point exists:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With all of this in place, you can finally run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mount /data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And that directory inside the VM will now be the same as the directory in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/zones/data/void-test&lt;/code&gt; on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rpool&lt;/code&gt; zpool!  This allows for easy file sharing
between the guest and the host, as well as persisting data in the event that you
want to reprovision the VM from a new image. Make sure to uncomment the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkdir&lt;/code&gt;
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mount&lt;/code&gt; commands in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/rc.local&lt;/code&gt; so the directory mounts at boot.&lt;/p&gt;

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

&lt;p&gt;Running void under LX is great, but some software really doesn’t like running
under LX virtualization and it’s just easier to use hardware virtualization at
that point.  bhyve makes it super nice and easy to accomplish this on OmniOS!&lt;/p&gt;

</summary>
		</item>
		
		<item>
			<title>Programmatically Generated Piano Music</title>
			<link>https://www.daveeddy.com/2021/12/17/programmatically-generated-piano-music/</link>
			<updated>2021-12-17T00:00:00-05:00</updated>
			<pubDate>2021-12-17T00:00:00-05:00</pubDate>
			<id>https://www.daveeddy.com/2021/12/17/programmatically-generated-piano-music/</id>
			<gid>https://www.daveeddy.com/2021/12/17/programmatically-generated-piano-music/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;I wrote a computer program to generate piano music on the command line.  The
generation is done with a simple algorithm to create patterns in MIDI format,
which is then imported into my DAW to process the data and turn it into music.
There is no AI or Machine Learning in this algorithm - the music is
programmatically generated and this video covers the algorithm that I created
in detail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I Made a Computer Program to Generate Piano Music&lt;/strong&gt;&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/v4oRZaSU5E0&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write;
encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;strong&gt;5 HOURS of ALGORITHMICALLY GENERATED Piano Music&lt;/strong&gt;&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/rUKQYtI4Yaw&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write;
encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;The source code can be found on GitHub:
&lt;a href=&quot;https://github.com/bahamas10/music-generator&quot;&gt;https://github.com/bahamas10/music-generator&lt;/a&gt;&lt;/p&gt;
</summary>
		</item>
		
		<item>
			<title>Plex Media Server on Void Linux</title>
			<link>https://www.daveeddy.com/2021/11/15/plex-media-server-on-void-linux/</link>
			<updated>2021-11-15T00:00:00-05:00</updated>
			<pubDate>2021-11-15T00:00:00-05:00</pubDate>
			<id>https://www.daveeddy.com/2021/11/15/plex-media-server-on-void-linux/</id>
			<gid>https://www.daveeddy.com/2021/11/15/plex-media-server-on-void-linux/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;&lt;img src=&quot;/static/media/2021/plex-on-void/plex-on-void.jpg&quot; alt=&quot;plex-on-void&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;how-to-install-plex-on-void&quot;&gt;How to install Plex on Void&lt;/h2&gt;

&lt;p&gt;Download &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plex-install-manager&lt;/code&gt; from:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bahamas10/plex-install-manager&quot;&gt;https://github.com/bahamas10/plex-install-manager&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install deps:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;xbps-install -S binutils tar curl xz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create user and directories needed:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;useradd -s /bin/false -d /var/empty _plex
mkdir /opt/plex /opt/plex/src /opt/plex/data
chown _plex:_plex /opt/plex/data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install Plex:&lt;/p&gt;

&lt;!-- more --&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./plex-install-manager -a -d /opt/plex/src
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Verify Plex installed:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ls -lh /opt/plex/src
total 2.0K
lrwxrwxrwx 1 root root 43 Nov 15 02:44 active -&amp;gt; plexmediaserver_1.24.5.5173-8dcc73a59_amd64/
drwxr-xr-x 4 root root  4 Nov 15 02:44 plexmediaserver_1.24.5.5173-8dcc73a59_amd64/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create Plex service:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir /etc/sv/plex
vim /etc/sv/plex/run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# label=Plex Media Serever&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;2&amp;gt;&amp;amp;1
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/plex/src/active/root/usr/lib/plexmediaserver'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PLEX_MEDIA_SERVER_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/plex/src/active/root/usr/lib/plexmediaserver
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/plex/data
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
&lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;chpst &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; _plex:_plex ./Plex&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Media&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ln -s /etc/sv/plex /var/service/plex
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;how-to-upgrade&quot;&gt;How to upgrade&lt;/h2&gt;

&lt;p&gt;To upgrade plex you simply need to run the following commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./plex-install-manager -a -d /opt/plex/src
sv restart plex
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</summary>
		</item>
		
		<item>
			<title>New Album - Inspired</title>
			<link>https://www.daveeddy.com/2021/06/01/new-album-inspired/</link>
			<updated>2021-06-01T00:00:00-04:00</updated>
			<pubDate>2021-06-01T00:00:00-04:00</pubDate>
			<id>https://www.daveeddy.com/2021/06/01/new-album-inspired/</id>
			<gid>https://www.daveeddy.com/2021/06/01/new-album-inspired/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;I released my latest album on June 1st, 2021!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://music.daveeddy.com/albums/inspired&quot;&gt;&lt;img src=&quot;/static/media/2021/inspired/inspired.jpg&quot; style=&quot;max-width: 600px; width: 100%; &quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My 5th album (4th full-length). Inspired consists of songs mostly written
during 2020 and 2021 - when I decided to quit my job and focus more on music
creation. It’s comprised of piano and instrumental tracks.&lt;/p&gt;

&lt;p&gt;Download or stream &lt;a href=&quot;https://music.daveeddy.com/albums/inspired&quot;&gt;Inspired&lt;/a&gt;.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/IzFz_5WqmeQ&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay;
clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;tracklist&quot;&gt;Tracklist&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Journey Ahead &lt;small&gt;0:52&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Morning Sun &lt;small&gt;3:23&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Piano Night &lt;small&gt;4:08&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;In My Dream &lt;small&gt;3:33&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Accordance &lt;small&gt;3:20&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Sis Puella Magica (Piano Cover) &lt;small&gt;2:38&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Hidden Away &lt;small&gt;3:18&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;I’m With You &lt;small&gt;4:58&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Something Beautiful &lt;small&gt;3:48&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Lost Corridors &lt;small&gt;3:57&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Frozen &lt;small&gt;3:47&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Secret Place &lt;small&gt;3:15&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Undercurrents &lt;small&gt;4:00&lt;/small&gt;&lt;/li&gt;
  &lt;li&gt;Letting Go &lt;small&gt;3:41&lt;/small&gt;&lt;/li&gt;
&lt;/ol&gt;
</summary>
		</item>
		
		<item>
			<title>sshp Rewrite from JavaScript to C</title>
			<link>https://www.daveeddy.com/2021/05/20/sshp-rewrite-from-javascript-to-c/</link>
			<updated>2021-05-20T00:00:00-04:00</updated>
			<pubDate>2021-05-20T00:00:00-04:00</pubDate>
			<id>https://www.daveeddy.com/2021/05/20/sshp-rewrite-from-javascript-to-c/</id>
			<gid>https://www.daveeddy.com/2021/05/20/sshp-rewrite-from-javascript-to-c/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/bahamas10/sshp&quot;&gt;&lt;img src=&quot;/static/media/github/sshp/c/logo.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In 2013, I wrote a program in Node.js called &lt;a href=&quot;https://github.com/bahamas10/node-sshp&quot;&gt;sshp&lt;/a&gt;.  This was right
around the time I was investing heavily into learning node, and
honestly having a blast doing it.  Node is quick and fun to write, and with
only a couple hundred lines of code, I was able to write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-sshp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-sshp&lt;/code&gt; is a command line utility that acts as a parallelizer for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt;.
It works by taking in a file containing a list of hosts to connect to and
looping over each host firing off an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt; command in parallel (with a
configurable maximum number of concurrent processes).  The tool’s description
is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; manages multiple ssh processes and handles coalescing the output to the
terminal.  By default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; will read a file of newline-separated hostnames
or IPs and fork ssh subprocesses for them, redirecting the stdout and stderr
streams of the child line-by-line to stdout of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Writing this tool in Node was an obvious choice at the time: the company I was
working for was using Node heavily, and this tool was written specifically to
be used at my job.  Managing multiple concurrent child processes and IO streams
also made Node the obvious choice.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;Fast-forward eight years, and I decided it might be fun to revisit this code.  I
still use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; at home and rely on it heavily; I don’t know if the company I
worked for in 2013 is still using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-sshp&lt;/code&gt;, however.  Looking at the existing
code in Node, I thought it would be fun to try and rewrite it in C.&lt;/p&gt;

&lt;p&gt;Jump to the &lt;a href=&quot;#sshp-finished-program&quot;&gt;finished program&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;how-sshp-works&quot;&gt;How sshp Works&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-sshp&lt;/code&gt; has 3 modes of execution:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;line mode&lt;/code&gt; (line-by-line output, default).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group mode&lt;/code&gt; (grouped by hostname output, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-g&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;join mode&lt;/code&gt; (grouped by unique output, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-j&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first 2 modes, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;line&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group&lt;/code&gt;, operate in largely the same way,
differing only in how data is buffered from the child processes and printed to
the screen.  Line mode buffers the data line-by-line, whereas group mode does
no buffering at all and prints the data once it is read from the child.&lt;/p&gt;

&lt;p&gt;The last mode however, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;join&lt;/code&gt;, buffers &lt;em&gt;all&lt;/em&gt; of the data from all of the child
processes and outputs once all processes have finished.  Instead of grouping
the output by host, it is grouped by the output itself to show which hosts had
the same output.&lt;/p&gt;

&lt;p&gt;My goal in this rewrite was to keep &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; largely the same.  Only the
following options have changed, the rest of the user-facing interface
remained exactly the same:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-b&lt;/code&gt; has been changed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-c off&lt;/code&gt; (disable color output).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-N&lt;/code&gt; has been removed in favor of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-o StrictHostKeyChecking=no&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-o&lt;/code&gt; has been added to allow for any ssh option to be passed in.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-u&lt;/code&gt; has been removed (not applicable without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-y&lt;/code&gt; has been removed in favor of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-o RequestTTY=force&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-decision-to-rewrite&quot;&gt;The Decision to Rewrite&lt;/h2&gt;

&lt;p&gt;The truth is, I didn’t really have any reason for wanting to rewrite
this code other than it looked “ugly” to me now.  I found many places that I
could “do better”, and a lot of places that had repeated lines of code with a
single variable changed.  Basically, there was a lot of sloppiness in the code I
thought I could clean and make better, if for no other reason than to make
myself feel better about the code.&lt;/p&gt;

&lt;p&gt;I don’t think 2013 me would have ever attempted to this.  I wasn’t at all
confident in my ability in writing C (in fact, I was afraid of it and thought I
would just have bugs and memory leaks everywhere).  Now, in 2021, I’m still not
super confident, but I think I’m just naive enough to start a rewrite and
stubborn enough to finish it.&lt;/p&gt;

&lt;h2 id=&quot;the-process-of-rewriting&quot;&gt;The Process of Rewriting&lt;/h2&gt;

&lt;p&gt;Rewriting from Node.js to C brought a &lt;em&gt;lot&lt;/em&gt; of challenges.  Like, a lot.  Node
has a lot of built-in facilities for handling multiple asynchronous processes
and IO streams (thanks to &lt;a href=&quot;https://github.com/libuv/libuv&quot;&gt;libuv&lt;/a&gt;).  On top of that, the JavaScript
portions of Node are all single-threaded.  When considering how to approach
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp.c&lt;/code&gt;, I had to decide if using threads made sense.  Basically, with C I had
a &lt;em&gt;lot&lt;/em&gt; of options, which meant a lot decisions I had to make.&lt;/p&gt;

&lt;h3 id=&quot;modes-of-execution&quot;&gt;Modes of Execution&lt;/h3&gt;

&lt;p&gt;As mentioned above, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; has 3 modes of execution.  When I originally wrote
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-sshp&lt;/code&gt;, this was something that I hadn’t considered explicitly - it sort of
just so happened that there was a default mode, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-j&lt;/code&gt; mode, and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-g&lt;/code&gt; mode
that popped up as I was iterating on it.&lt;/p&gt;

&lt;p&gt;Because of this, it was easier to approach the rewrite since I had the blessing
of hindsight to know how the program should look.  Writing a new program that
matches the interface of an existing program is similar to composing a cover or
a remix of a song as opposed to writing one completely from scratch - it’s an
easier process since a lot of the foundation is already laid.&lt;/p&gt;

&lt;h3 id=&quot;file-descriptor-events&quot;&gt;File Descriptor Events&lt;/h3&gt;

&lt;p&gt;In C, it was up to me to figure out how I was going to approach this.  I could
just pull in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libuv&lt;/code&gt; like Node.js does  myself and have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; depend on it,
but I wanted to have as little dependencies as possible.&lt;/p&gt;

&lt;p&gt;I made the choice to use &lt;a href=&quot;https://man7.org/linux/man-pages/man7/epoll.7.html&quot;&gt;epoll&lt;/a&gt; to simplify the process a bit.
This would limit the number of operating systems that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; will work on, but I
mainly wanted to target the two operating systems I use the most at home:
&lt;a href=&quot;https://github.com/joyent/smartos-live&quot;&gt;SmartOS&lt;/a&gt; and &lt;a href=&quot;https://voidlinux.org&quot;&gt;Void Linux&lt;/a&gt;, which both support the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt;
interface natively.  Other than the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt; dependency, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; should work on
any POSIX system with a C compiler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Since I originally wrote this blog post I have updated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; to work
with &lt;a href=&quot;https://en.wikipedia.org/wiki/Kqueue&quot;&gt;kqueue&lt;/a&gt; as well as &lt;a href=&quot;https://man7.org/linux/man-pages/man7/epoll.7.html&quot;&gt;epoll&lt;/a&gt;.  You can see the &lt;a href=&quot;#sshp-update-1&quot;&gt;update
below&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h3 id=&quot;threading&quot;&gt;Threading&lt;/h3&gt;

&lt;p&gt;I originally imagined that I would need 2 threads.  In fact, in the early
commits of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt;, you can see how this was originally implemented with threads.
It looked something like:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Child process execution manager&lt;/li&gt;
  &lt;li&gt;Child process stdio manager&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At a certain point, I realized I had semaphores signaling each thread back and
forth that 1. the child had executed and 2. the child needed to be reaped.
Because they were mostly just blocking on each other to do work I eventually
just pulled out the threading and just made it all a single thread with
non-blocking IO from the child processes.&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;How many lines of code is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;--------------------------------------------------------------------------------
 Language             Files        Lines        Blank      Comment         Code
--------------------------------------------------------------------------------
 C                        1         1966          239          494         1233
 JavaScript               1          393           39           33          321
--------------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The C version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; is about 5x more lines than the Node version - it
contains more lines of comments than the entire source of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-sshp&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You rewrote a program to have 5x more lines of code and less cross-platform
compatibility?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Short answer: yes.  I at least had fun during the process :).&lt;/p&gt;

&lt;p&gt;Long answer: Node.js isn’t required to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; now.  So, yay? :).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;How long did it take to write originally? How long did the rewrite take?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The original program didn’t have all of the same functionality from the
beginning of its life.  For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-sshp&lt;/code&gt;, it took about 2-3 days to get the line
mode and group mode working and another 2-3 days (months later) to get the
join mode working.&lt;/p&gt;

&lt;p&gt;For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; in C however, it took about 2 full weeks of working to get it
working.  It was significantly faster to iterate in Node than C - but wow, am I
way more proud of the code in C than I am of the code in JavaScript!&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;sshp-finished-program&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-finished-program&quot;&gt;The Finished Program&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; can be found on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bahamas10/sshp&quot;&gt;https://github.com/bahamas10/sshp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had a ton of fun working on this, and am really happy with how it turned out.
I hope you enjoy it! :).&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;sshp-examples&quot;&gt;sshp Examples&lt;/h3&gt;

&lt;p&gt;See the GitHub page linked above for more information and usage.&lt;/p&gt;

&lt;p&gt;Given the following hosts file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hosts.txt&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# example hosts file
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arbiter&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;rapture&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cifs&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;rapture&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;decomp&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;rapture&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Parallel ssh into hosts supplied by a file running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uname -v&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/github/sshp/c/line-by-line-cropped.jpg&quot;&gt;&lt;img src=&quot;/static/media/github/sshp/c/line-by-line-cropped.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pass in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-e&lt;/code&gt; to get the exit codes of the commands on the remote end.  The
local exit code will be 0 if all ssh processes exit successfully, or 1 if any
of the ssh processes exit with a failure:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/github/sshp/c/exit-codes-cropped.jpg&quot;&gt;&lt;img src=&quot;/static/media/github/sshp/c/exit-codes-cropped.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also note that the hosts file can be passed in via stdin if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-f&lt;/code&gt; is not
supplied.&lt;/p&gt;

&lt;p&gt;Run with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-d&lt;/code&gt; to get debug information, making it clear what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; is doing:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/github/sshp/c/debug-id-cropped.jpg&quot;&gt;&lt;img src=&quot;/static/media/github/sshp/c/debug-id-cropped.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-g&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group mode&lt;/code&gt;) to group the output by hostname as it comes in.
To illustrate this, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; is set to 1 to limit the maximum number of concurrent
child processes to 1, effectively turning &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; into an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt; serializer:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/github/sshp/c/serialize-group-mode-cropped.jpg&quot;&gt;&lt;img src=&quot;/static/media/github/sshp/c/serialize-group-mode-cropped.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-j&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;join mode&lt;/code&gt;) to join the output by the output itself and not the
hostname:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/github/sshp/c/join-mode-cropped.jpg&quot;&gt;&lt;img src=&quot;/static/media/github/sshp/c/join-mode-cropped.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Send the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; process a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGSUR1&lt;/code&gt; signal to print out process status
information while it is running.  In this example, a signal was sent twice to
the process:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/github/sshp/c/sigusr1-status-cropped.jpg&quot;&gt;&lt;img src=&quot;/static/media/github/sshp/c/sigusr1-status-cropped.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a id=&quot;sshp-update-1&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;kqueue-and-epoll-update&quot;&gt;kqueue and epoll update&lt;/h2&gt;

&lt;p&gt;A little over a week after finishing up this blog post and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt;, I decided to
actually look into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kqueue&lt;/code&gt; and see how hard it would be to implement alongside
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt;.  This task turned out to be a lot easier than I initially planned since
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kqueue&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt; have very similar interfaces when it comes to watching for
file descriptor read events.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bahamas10/sshp/pull/1&quot;&gt;This pull request&lt;/a&gt; contains all of the code to get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kqueue&lt;/code&gt;
supported.  From a high level, I decided to start by abstracting the existing
and working &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt; logic in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; into its own interface called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FdWatcher&lt;/code&gt;.
The interface works with the following functions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FdWatcher *fdwatcher_create()&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int fdwatcher_add(FdWatcher *fdw, int fd, void *ptr)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int fdwatcher_remove(FdWatcher *fdw, int fd)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int fdwatcher_wait(FdWatcher *fdw, void **events, int nevents, int timeout)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;void fdwatcher_destroy(FdWatcher *fdw)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first I was able to get this interface working for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt; only.  Once that
functioned properly, I started implementing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kqueue&lt;/code&gt; support by using simple
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#ifdef&lt;/code&gt;s.  After just an hour or so I had a working interface on my Mac using
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kqueue&lt;/code&gt;!  This approach turned out to be really great in my opinion.  Starting
with a working implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;epoll&lt;/code&gt; made it easier to decide what the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FdWatcher&lt;/code&gt; interface should look like and fit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kqueue&lt;/code&gt; into it.&lt;/p&gt;

&lt;p&gt;The new code count is:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ loc
--------------------------------------------------------------------------------
 Language             Files        Lines        Blank      Comment         Code
--------------------------------------------------------------------------------
 C                        2         2140          270          523         1347
 Markdown                 2          382          112            0          270
 Makefile                 1           57           11            5           41
 Plain Text               2           32            3            0           29
 C/C++ Header             1          132            8          111           13
--------------------------------------------------------------------------------
 Total                    8         2743          404          639         1700
--------------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshp&lt;/code&gt; works on systems with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kqueue&lt;/code&gt; - like MacOS and FreeBSD!&lt;/p&gt;

</summary>
		</item>
		
		<item>
			<title>Super Mario 64 Decompilation on Void Linux</title>
			<link>https://www.daveeddy.com/2020/09/09/super-mario-64-decompilation-on-void-linux/</link>
			<updated>2020-09-09T00:00:00-04:00</updated>
			<pubDate>2020-09-09T00:00:00-04:00</pubDate>
			<id>https://www.daveeddy.com/2020/09/09/super-mario-64-decompilation-on-void-linux/</id>
			<gid>https://www.daveeddy.com/2020/09/09/super-mario-64-decompilation-on-void-linux/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;&lt;a href=&quot;https://www.mariowiki.com/Super_Mario_64&quot;&gt;Super Mario 64&lt;/a&gt; is one of my all-time favorite games.  Last year, the
source code for the decompilation project was made available to the public.  I
won’t go into detail on the decompilation project itself (&lt;a href=&quot;https://news.ukikipedia.net/index.php/2019/08/28/decomp-is-out-but-what-does-that-mean-ukikipedia-news-week-10/&quot;&gt;see this post
here&lt;/a&gt; for more information), but instead will focus on
getting Super Mario 64 compiled on &lt;a href=&quot;https://voidlinux.org/&quot;&gt;Void Linux&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;A couple of dependencies will need to be installed that will be used throughout
the installation process.  Note that root privileges are only required in
commands where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt; is used - the rest of the commands can be run as an
unprivileged user.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo xbps-install git
sudo xbps-install make
sudo xbps-install wget

mkdir ~/dev ~/src
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For this guide, the sm64 source code will be checked out into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/dev&lt;/code&gt;, and the
required dependencies that are installed manually will be in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/src&lt;/code&gt;, of which
there are 2:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-irix&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binutils-mips64&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;qemu-irix&quot;&gt;qemu-irix&lt;/h2&gt;

&lt;p&gt;To install this package, I found it easiest to take the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-irix&lt;/code&gt; release as a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.deb&lt;/code&gt; file from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n64decomp&lt;/code&gt; GitHub organization and extract the deb
myself.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;In order to do this, you must first install a couple of dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo xbps-install binutils # installs 'ar'
sudo xbps-install libglib-devel
sudo xbps-install xz

mkdir ~/src/qemu-irix
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, pull the package and “install” it (in this case, just extract it):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd ~/src/qemu-irix
wget https://github.com/n64decomp/qemu-irix/releases/download/v2.11-deb/qemu-irix-2.11.0-2169-g32ab296eef_amd64.deb
ar x qemu-irix-2.11.0-2169-g32ab296eef_amd64.deb
tar xf data.tar.xz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, test the installed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-irix&lt;/code&gt; program to ensure it runs:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./usr/bin/qemu-irix -version
qemu-irix version 2.11.50 (v2.11.0-2169-g32ab296eef-dirty)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;binutils-mips64&quot;&gt;binutils-mips64&lt;/h2&gt;

&lt;p&gt;This package will be installed manually, so a C compiler is required.  Install
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;xbps-install gcc

mkdir ~/src/binutils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, pull the source code and prepare it for compilation:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd ~/src/binutils

wget ftp://ftp.gnu.org/gnu/binutils/binutils-2.35.tar.xz
tar xf binutils-2.35.tar.xz
cd binutils-2.35/

sed -i &quot;/ac_cpp=/s/\$CPPFLAGS/\$CPPFLAGS -O2/&quot; libiberty/configure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I don’t know if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sed&lt;/code&gt; command is strictly necessary - I based this process
off of the &lt;a href=&quot;https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mips64-elf-binutils&quot;&gt;mips64-elf-binutils PKGBUILD&lt;/a&gt; file used by the
package in the AUR (for Arch Linux).&lt;/p&gt;

&lt;p&gt;Next, compile the package:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./configure --target=mips64-elf --prefix=/usr --with-sysroot=/usr/mips64-elf --with-gnu-as --with-gnu-ld --enable-64-bit-bfd --enable-multilib --enable-plugins --disable-gold --disable-nls --disable-shared --disable-werror
make
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, “install” the package into a local directory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;make &quot;DESTDIR=$PWD/dest&quot; install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, test that the program works by executing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mips64-elf-as&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./dest/usr/bin/mips64-elf-as -version
GNU assembler (GNU Binutils) 2.35
Copyright (C) 2020 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `mips64-elf'.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;compile-sm64&quot;&gt;Compile SM64&lt;/h2&gt;

&lt;p&gt;Finally, we are able to compile Super Mario 64!&lt;/p&gt;

&lt;p&gt;Install the required dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo xbps-install audiofile-devel
sudo xbps-install python3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Clone the project from GitHub:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd ~/dev
git clone git://github.com/n64decomp/sm64.git
cd sm64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to avoid any legal issues, the static assets from SM64 are NOT shipped
with the decompiled source code.  You must supply a rom to use as a “base”.  In
our case, we will need the following rom with the exact sha1 hash:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sha1sum 'Super Mario 64 (U) [!].z64'
9bef1128717f958171a4afac3ed78ee2bb4e86ce  Super Mario 64 (U) [!].z64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I can’t tell you where to get this rom so please don’t ask - but once you have
the rom, move it into the decompilation repository and name it as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mv ~/'Super Mario 64 (U) [!].z64' baserom.us.z64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we are almost ready to begin the compilation!  The final step is to setup
our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATH&lt;/code&gt; to use the programs we installed above.  This step should be done
once per session before you want to compile or recompile Mario.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PATH=$PATH:~/src/binutils/binutils-2.35/dest/usr/bin:~/src/qemu-irix/usr/bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And finally, compile it!&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ make
...

build/us/sm64.us.z64: OK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Success! Part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; process is that the sha sum being compared to the
expected base rom, but we cany verify the output file manually with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sha1sum build/us/sm64.us.z64
9bef1128717f958171a4afac3ed78ee2bb4e86ce  build/us/sm64.us.z64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;test-the-rom&quot;&gt;Test The Rom&lt;/h2&gt;

&lt;p&gt;All of the above steps can be run on a headless Void Linux installation.  The
file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./build/us/sm64.us.z64&lt;/code&gt; is created by the compilation process and can be
used in any N64 emulator or even sent to a fashcart like the everdrive and ran
on a real N64.&lt;/p&gt;

&lt;p&gt;We can also test this on Void Linux with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mupen64plus&lt;/code&gt;, assuming there is a
windowing system installed and it is not a server/headless installation.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo xbps-install mupen64plus
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, to test the rom:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mupen64plus --gfx mupen64plus-video-glide64mk2 --audio mupen64plus-audio-sdl --windowed ./build/us/sm64.us.z64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can pass whatever options you like, but I find these create the most
performant result.  I also use a &lt;a href=&quot;https://www.raphnet-tech.com/products/n64_usb_adapter_gen3/index.php&quot;&gt;raphnet N64 to USB adapter&lt;/a&gt; to be
able to use an original N64 controller on my computer.&lt;/p&gt;

&lt;p&gt;This screenshot shows Mario is working as expected!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/static/media/2020/sm64/good-mario.png&quot; alt=&quot;good-mario&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;rom-hacking&quot;&gt;Rom Hacking&lt;/h2&gt;

&lt;p&gt;With all of this in place, we now have C source code that can be compiled
perfectly into a Super Mario 64 rom file.  As such, we are free to make any
modifications to the source code we like.&lt;/p&gt;

&lt;p&gt;As a simple example I had an idea for a (terrible) basic rom hack.  When Mario
is a certain distance away from the camera, for performance reasons, his high
quality model is replaced with a low-polygon version of his model.  This can
become apparent during boss fights or when the camera is fixed, such as in the
big house on Rainbow Ride.  The idea is to make the low-poly version of Mario
the default model regardless of camera distance.&lt;/p&gt;

&lt;p&gt;In searching the source code to figure out how this logic is handled, I ended
up actually learning something I didn’t know!  This block comment in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./src/engine/graph_node.h&lt;/code&gt; explains what I didn’t know:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/** GraphNode that only renders its children if the current transformation matrix
 *  has a z-translation (in camera space) greater than minDistance and less than
 *  maxDistance.
 *  Usage examples: Mario has three level's of detail: Normal, low-poly arms only, and fully low-poly
 *  The tower in Whomp's fortress has two levels of detail.
 */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It turns out Mario has 3 levels of detail! I wasn’t aware of the “medium” level
which is low-poly arms only.  So already I’ve learned something new about this
game!&lt;/p&gt;

&lt;p&gt;Now, onto hacking - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./actors/mario/geo.inc.c&lt;/code&gt; controls the Mario model.  The
variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mario_geo_render_body&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mario_geo&lt;/code&gt; are the important ones to
note here.  Starting with the first function:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 0x17002D7C&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoLayout&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_render_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_NODE_START&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_RENDER_RANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// HIGH POLY (normal mario)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_RENDER_RANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_medium_poly_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// MEDIUM POLY&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_RENDER_RANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32767&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_low_poly_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// LOW POLY&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_RETURN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve added comments to better understand when each model is used.  We can
modify this to &lt;em&gt;always&lt;/em&gt; load the medium poly Mario:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 0x17002D7C&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoLayout&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_render_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_NODE_START&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_RENDER_RANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_medium_poly_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// HIGH POLY (normal mario)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_RENDER_RANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_medium_poly_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// MEDIUM POLY&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_RENDER_RANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32767&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_medium_poly_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// LOW POLY&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_RETURN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also, the variable below it needs to be modified as well:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 0x17002DD4&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoLayout&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_SHADOW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SHADOW_CIRCLE_PLAYER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xB4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_SCALE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16384&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_ASM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;geo_mirror_mario_backface_culling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_ASM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;geo_mirror_mario_set_alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_SWITCH_CASE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;geo_switch_mario_stand_run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// THIS LINE&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_render_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_ASM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;geo_mirror_mario_backface_culling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Changing the line that I commented earlier to match the polygon level we want:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GEO_BRANCH(1, mario_geo_load_medium_poly_body), // THIS LINE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With these two changes in place, we can now recompile our own personalized
version of Super Mario 64 that will only use the medium-poly version of Mario.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ make
...
tools/n64cksum build/us/sm64.us.bin build/us/sm64.us.z64
build/us/sm64.us.z64: FAILED
sha1sum: WARNING: 1 computed checksum did NOT match
The build succeeded, but did not match the official ROM. This is expected if you are making changes to the game.
To silence this message, use &quot;make COMPARE=0&quot;.
make: *** [Makefile:339: all] Error 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It broke?! Well not quite.  The build was successful, but the sha1 hash check I
mentioned above failed.  This is ok - in fact this is expected - since we are
modifying the source and intend to have a different version.  We can instead
run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; with a variable set to not compare hashes after the build succeeds:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;make COMPARE=0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, booting up the run with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mupen64plus&lt;/code&gt; we can see what medium-poly Mario
looks like.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/static/media/2020/sm64/medium-poly-mario.png&quot; alt=&quot;medium-poly-mario&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The model looks mostly the same, but you can really see his arms just aren’t
quite right.&lt;/p&gt;

&lt;p&gt;This is cool, but I think we can make it more cursed.  Let’s swap out the
variables to only have low-poly Mario instead.  The 2 variables inside
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./actors/mario/geo.inc.c&lt;/code&gt; should look like:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 0x17002D7C&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoLayout&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_render_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_NODE_START&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_RENDER_RANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_low_poly_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_RENDER_RANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_low_poly_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_RENDER_RANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32767&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_low_poly_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_RETURN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// This last geo is used to load all of Mario Geo in the Level Scripts&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 0x17002DD4&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoLayout&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_SHADOW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SHADOW_CIRCLE_PLAYER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xB4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_SCALE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16384&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_ASM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;geo_mirror_mario_backface_culling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_ASM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;geo_mirror_mario_set_alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_SWITCH_CASE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;geo_switch_mario_stand_run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_OPEN_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_load_low_poly_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;GEO_BRANCH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mario_geo_render_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;GEO_ASM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;geo_mirror_mario_backface_culling&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_CLOSE_NODE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;GEO_END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Build the new rom with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ make COMPARE=0
...
mips64-elf-objcopy --pad-to=0x800000 --gap-fill=0xFF build/us/sm64.us.elf build/us/sm64.us.bin -O binary
tools/n64cksum build/us/sm64.us.bin build/us/sm64.us.z64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mupen64plus&lt;/code&gt; and:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/static/media/2020/sm64/low-poly-mario.png&quot; alt=&quot;low-poly-mario&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Bam! the most cursed romhack of Super Mario 64 done by only modifying 4 lines
of code.&lt;/p&gt;

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

&lt;p&gt;This just scratches the surface of what could be done with the SM64
decompilation project.  I hope to do more, and I hope this blog post also
inspires you to do something with this :).&lt;/p&gt;

&lt;p&gt;Some final thoughts I have are: how could this be made more efficient? If we
are always using the same model, do we still need the logic to swap the model
at a certain camera distance? Most likely not.&lt;/p&gt;

&lt;p&gt;But for now the low-polygon version of Super Mario 64 that no one asked for is
now here!&lt;/p&gt;

&lt;h2 id=&quot;looking-forward&quot;&gt;Looking Forward&lt;/h2&gt;

&lt;p&gt;I’m currently working on my first rom hack! The idea is very simple: toggle
the water physics on and off completely with the L button.  This means the
whether will be completely dry, or completely flooded, with the push of a
button.  It’s already making for some really cool speedrunning strats:&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;thanks to the Super
Mario 64 decomp project I present to you...&lt;br /&gt;cursed sm64 decomp strat 1: ship
clip 2.0 &lt;a href=&quot;https://t.co/Ue57mOkTiD&quot;&gt;pic.twitter.com/Ue57mOkTiD&lt;/a&gt;&lt;/p&gt;&amp;mdash; dave
eddy (@bahamas10_) &lt;a href=&quot;https://twitter.com/bahamas10_/status/1303834932482113539?ref_src=twsrc%5Etfw&quot;&gt;September
9, 2020&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

</summary>
		</item>
		
		<item>
			<title>Pump It Up Pad Refurbishment and Upgrade</title>
			<link>https://www.daveeddy.com/2020/02/06/pump-it-up-pad-refurbishment-and-upgrade/</link>
			<updated>2020-02-06T00:00:00-05:00</updated>
			<pubDate>2020-02-06T00:00:00-05:00</pubDate>
			<id>https://www.daveeddy.com/2020/02/06/pump-it-up-pad-refurbishment-and-upgrade/</id>
			<gid>https://www.daveeddy.com/2020/02/06/pump-it-up-pad-refurbishment-and-upgrade/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;In 2018 I created my own &lt;a href=&quot;/2018/03/27/diy-pump-it-up-arcade-pad-platform-with-bars/&quot;&gt;DIY Pump It Up Pad Platform With Bars&lt;/a&gt; - it
was a combination of &lt;a href=&quot;http://www.precisiondancepads.com/en/dance-pads/11-omega-px.html&quot;&gt;Precision Dance Pads&lt;/a&gt; and a platform with bars
I created myself.  This setup was… decent at best.  I wanted the full arcade
experience, and knew that nothing was going to satisfy that except for the real
arcade pads.&lt;/p&gt;

&lt;p&gt;Luckily for me, my friend Kate added me to a buy/sell/trade Facebook group for
arcade rhythm games, and within the first week there was a post for used Pump
It Up pads for sale about 8 hours away from my house.  I jumped on that
opportunity immediately!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0068.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0068.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;!-- more --&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Spoiler:&lt;/strong&gt; &lt;a href=&quot;#the-pads-in-action&quot;&gt;Scroll down&lt;/a&gt; to see videos of the pads in
action!&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;getting-the-pads&quot;&gt;Getting the Pads&lt;/h2&gt;

&lt;p&gt;I woke up early on a Sunday, got in my (relatively small) car, and drove 8
hours from Buffalo, New York, to Maryland.  I picked up the pads from &lt;a href=&quot;http://www.winbigarcade.com&quot;&gt;the
seller&lt;/a&gt;, barely got them loaded into my car, and drove 8 hours back
home.  It was a crazy day but I managed to stop once on the way there, and once
on the way back at &lt;a href=&quot;https://www.sheetz.com/&quot;&gt;Sheetz&lt;/a&gt; so it was a good day :).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2259.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2259.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These pads originated from a PIU Zero machine in Ontario, Canada.&lt;/p&gt;

&lt;p&gt;The pads inside my house ready to be connected to the computer with
&lt;a href=&quot;https://stepf2.blogspot.com/&quot;&gt;StepF2&lt;/a&gt;.  In order to do this I had remove the top most panel to swap
out the existing PCB with the &lt;a href=&quot;http://www.winbigarcade.com/product/barr-io-pump-it-up-pad-io/&quot;&gt;BARR.io&lt;/a&gt; adapter.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2275.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2275.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Jess and Kate testing out the pads! They were not structurally sound at the
time of testing :p.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0123.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0123.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I added the bar to the right pad.  I also started doing some basic cleanup
beneath the panels - the pads were really dirty.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2286.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2286.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The left pad with &lt;em&gt;all&lt;/em&gt; of the panels removed.  I went through and gutted the entire pad to clean it and wipe it all down.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2309.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2309.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another angle of the pad close-up.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2310.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2310.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I went through a lot of paper towels and lysol wipes cleaning this pad. It was
insane how much dirt and other stuff managed to get in there during its time
at the arcade.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2311.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2311.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moving the old set of pads out of the way.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2287.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2287.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reassembling the pads now that they are cleaned up.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0002.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0002.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;pad-refurbishing&quot;&gt;Pad Refurbishing&lt;/h2&gt;

&lt;p&gt;At this point, the pads have been cleaned and the USB adapters have been
installed, and the pads all work!  However, they have a lot of issues.  Some of
the panels are more responsive than others, and some just really need to be
stomped on to register a click.&lt;/p&gt;

&lt;p&gt;I followed the advice in this video.  Using this I:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Replaced the metal bracket pads with Gorilla tape.  The existing pads had
absolutely no give to them.&lt;/li&gt;
  &lt;li&gt;Countersunk the metal corner brackets so the screws wouldn’t protrude and
catch your feet.&lt;/li&gt;
&lt;/ol&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/TDXEAgH_fiU&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h3 id=&quot;metal-bracket-padding&quot;&gt;Metal Bracket Padding&lt;/h3&gt;

&lt;p&gt;The existing metal brackets with the worn out pads.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2354.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2354.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scraping off the existing padding.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2355.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2355.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It took a long time but I eventually got all of them clean.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2357.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2357.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using Gorilla tape to add new life to the padding on the metal brackets.  I
would try to keep the brackets in groups of 5 to make them easier to cut.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2365.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2365.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used an exacto knife to cut them into the groups of 5, and then I would put
the groups of 5 back onto Gorilla tape until there were about 7 layers of tape.
From there, I would use the knife to cut them one-by-one.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2366.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2366.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used this paper cutter thing to cut off any excess tape from the brackets.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2625.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2625.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reassembling the panels with the newly padded metal brackets.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2557.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2557.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;countersinking-corner-brackets&quot;&gt;Countersinking Corner Brackets&lt;/h3&gt;

&lt;p&gt;The next step in refurbishing was to countersink the metal corner brackets.
This will make it so the screws sit flush with the pads.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2548.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2548.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The old style bracket on the left and the new style on the right.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2550.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2550.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another before and after shot - the bottom hole is countersunk and the top is
not.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2552.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2552.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A before picture of the metal bracket installed without the countersunk holes.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2559.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2559.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An after picture of the metal bracket installed with the countersunk holes.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2560.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2560.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One panel installed in all of its glory.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2561.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2561.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slowly reassembling the pads.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2564.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2564.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After removing the old PCB I used Gorilla tape to cover the metal on the inside
to ensure that there’s no chance of shorting the BARR.io adapter.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2565.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2565.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pad almost reassembled.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2574.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2574.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pad reassembled.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2575.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2575.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The left pad is complete - on to working on the right pad.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2663.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2663.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both pads fully assembled!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2721.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2721.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;attaching-the-pads&quot;&gt;Attaching the Pads&lt;/h2&gt;

&lt;p&gt;In order to connect the two pads to each other, almost all arcade pads have a
metal bracket on the front and the back that screw into the pads and hold them
in place.  The pads I bought didn’t come with the bracket, so I had to
improvise.  I decided to save money, and make my own brackets out of plywood.&lt;/p&gt;

&lt;p&gt;To do this, I used a piece of paper held over the pads, and stabbed holes where
the screw holes are.  Then, I used that as a template to cut pieces of plywood.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2745.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2745.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two pieces of plywood cut.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2746.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2746.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Spray painted black.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2749.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2749.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I taped the 2 plywood pieces together and then used the template to scroll
holes through them.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2754.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2754.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Screw holes cut!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2755.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2755.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Installed with some of the screws in place.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2756.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2756.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pads held together with the new wooden brackets.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_2757.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_2757.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;customizing&quot;&gt;Customizing&lt;/h2&gt;

&lt;p&gt;Nothing too fancy, but I taped USB LED lights to the bottom of the pads.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_3187.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_3187.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same pic in the dark.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_3188.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_3188.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A pic of the pads with the lights on.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_3190.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_3190.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same pic in the dark.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_3189.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_3189.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final thing is some of the caster wheels were broken on the original pads
(or just missing), so I hit up Lowes and grabbed a couple of new wheels of the
same size.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_3192.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_3192.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New wheels installed.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_3193.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_3193.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;bracketless-upgrade&quot;&gt;Bracketless Upgrade&lt;/h2&gt;

&lt;p&gt;Even though this is a single blog post, this project spanned over the duration
of an entire year.  I’ve used the pads with the metal corner brackets for about
6 months without issue and things have been good.  However, playing some of the
newer charts as well as still playing on the machine at the arcade, I decided
that I wanted to upgrade my pads to be the newer style without the metal
brackets.&lt;/p&gt;

&lt;p&gt;On the same Facebook group where I found the seller of the pads, I found
another seller that was selling a full “upgrade kit” complete with all new
panels and frames.  I bought the new kit and followed the below video.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/z33H6vsqj10&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;The upgrade kit.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_4018.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_4018.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The YouTube video above outlines the screws needed to install the newer panels
in the description.  Below is the full list of screws I purchased from
&lt;a href=&quot;https://www.boltdepot.com/&quot;&gt;BoltDepot&lt;/a&gt;.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Part Number&lt;/th&gt;
      &lt;th&gt;Name&lt;/th&gt;
      &lt;th&gt;Quantity&lt;/th&gt;
      &lt;th&gt;Price&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;5187&lt;/td&gt;
      &lt;td&gt;Metric machine screws, Phillips pan head, Stainless steel 18-8 (A-2), 6mm x 1.0mm x 10mm&lt;/td&gt;
      &lt;td&gt;1 bag of 100&lt;/td&gt;
      &lt;td&gt;$13.31&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;5179&lt;/td&gt;
      &lt;td&gt;Metric machine screws, Phillips pan head, Stainless steel 18-8 (A-2), 5mm x 0.8mm x 20mm&lt;/td&gt;
      &lt;td&gt;1 bag of 100&lt;/td&gt;
      &lt;td&gt;$10.17&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4824&lt;/td&gt;
      &lt;td&gt;Metric lock washers, Zinc plated steel, 5mm&lt;/td&gt;
      &lt;td&gt;1 bag of 100&lt;/td&gt;
      &lt;td&gt;$2.18&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4526&lt;/td&gt;
      &lt;td&gt;Metric flat washers, Zinc plated steel, 5mm&lt;/td&gt;
      &lt;td&gt;1 bag of 100&lt;/td&gt;
      &lt;td&gt;$1.40&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0003.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0003.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had to Gorilla Glue the sensor holders onto the plastic frames.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_4298.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_4298.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The middle panel installed alongside the older panels.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_4368.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_4368.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One pad done! You can see how ridiculous it looks having an upgraded pad next
to an older style pad ha.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0050.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0050.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another angle of one completed pad.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0051.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0051.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The left pad with the new frames installed.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0053.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0053.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Almost all of the panels installed (without any lighting as the BARR.io
currently doesn’t support lights).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0122.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0122.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;9/10 new panels installed.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0126.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0126.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-finished-pads&quot;&gt;The Finished Pads&lt;/h2&gt;

&lt;p&gt;The fully upgraded pad!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/pump-it-up-pads/IMG_0068.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/pump-it-up-pads/thumb-IMG_0068.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;a id=&quot;the-pads-in-action&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-pads-in-action&quot;&gt;The Pads In Action&lt;/h2&gt;

&lt;p&gt;I sometimes stream on &lt;a href=&quot;https://www.twitch.tv/bahamas10&quot;&gt;twitch.tv&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;void---idealized-romance-s16&quot;&gt;void - Idealized Romance S16&lt;/h3&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/0sFtXglDNsU&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;beltaine---rockhill-d12&quot;&gt;Beltaine - Rockhill D12&lt;/h3&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/wVgkObQsOxM&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

</summary>
		</item>
		
		<item>
			<title>DIY Wooden Long Desk</title>
			<link>https://www.daveeddy.com/2019/12/17/diy-wooden-long-desk/</link>
			<updated>2019-12-17T00:00:00-05:00</updated>
			<pubDate>2019-12-17T00:00:00-05:00</pubDate>
			<id>https://www.daveeddy.com/2019/12/17/diy-wooden-long-desk/</id>
			<gid>https://www.daveeddy.com/2019/12/17/diy-wooden-long-desk/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;In 2016 I built an &lt;a href=&quot;/2016/07/18/overwatch-themed-desk-and-pc/&quot;&gt;Overwatch Themed
Desk&lt;/a&gt; for my bedroom to use with my
gaming machine.  Recently, I’ve been getting really into &lt;a href=&quot;https://www.twitch.tv/bahamas10&quot;&gt;streaming on
Twitch&lt;/a&gt; and I needed more desk space.  I want
to do more tech related streams, and gaming in general, and need more desk
space for multiple computers.&lt;/p&gt;

&lt;p&gt;I decided I should build a new longer desk to replace the desk I currently use.
I wanted it to be the same height and depth, but this time make it 6 feet
long.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0363.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0363.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;The desk proportions are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;6’ wide&lt;/li&gt;
  &lt;li&gt;30” deep&lt;/li&gt;
  &lt;li&gt;30” height&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used the following pieces of lumber to make this desk:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;6x 1x6x6 (trimmed to 5” wide for each board)&lt;/li&gt;
  &lt;li&gt;3x 2x4x8&lt;/li&gt;
  &lt;li&gt;3x 4x4x8&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0266.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0266.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I cut the pieces down to the proper sizes first.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0268.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0268.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used my table saw to trim off edges of the lumber to get rid of the rounded
edges.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0269.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0269.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lining up the 1x6 (now 1x5) pieces to get ready to glue for the desktop.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0298.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0298.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pieces glued and lined up.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0299.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0299.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Glued and clamped.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0300.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0300.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I lined up the 4x4’s by eye only to figure out where I wanted the legs to be.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0307.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0307.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using a pocket hole jig to get the 2x4’s ready to support the desktop.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0312.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0312.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used an electric hand planer to get rid of the excess glue and prep the
desktop for sanding.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0313.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0313.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another shot of the desktop.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0314.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0314.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Random orbit sander for the desktop next.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0315.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0315.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used my chop saw to cut the logs of the 4x4’s to look a little fancy.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0317.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0317.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used my table saw to start cutting the cross halving joint on the support
pieces.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0318.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0318.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cross halving joints so far.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0319.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0319.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beginning of assembling the desk.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0321.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0321.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The desk with the desktop (not assembled yet, just a teaser).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0322.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0322.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another shot of the assembly.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0323.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0323.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Getting the support beams ready to glue.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0324.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0324.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Side and back supports have been glued and clamped.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0325.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0325.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another shot of the glued and clamped supports.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0326.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0326.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Getting the frame and desktop ready to stain.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0327.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0327.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Espresso stain on the frame and Golden Oak stain on the desktop.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0328.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0328.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m an idiot and completely missed staining this part of the frame so I had to
stain it separately.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0349.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0349.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The stained and polyurethaned frame in my house.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0361.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0361.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Signed my work the same way I did with my Overwatch desk :).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0362.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0362.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Overhead view of the table top (i love it!).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0364.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0364.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A shot of the finished desk.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0365.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0365.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The desk in its new home.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0369.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0369.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A wide-angle lens shot of the desk in its new home.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0370.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0370.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The desk with my streaming gear on it!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/diy/long-desk/IMG_0374.jpg&quot;&gt;&lt;img src=&quot;/static/media/diy/long-desk/thumb-IMG_0374.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</summary>
		</item>
		
		<item>
			<title>SmartOS COAL on Linux KVM with Virt Manager</title>
			<link>https://www.daveeddy.com/2019/02/12/smartos-coal-on-linux-kvm-with-virt-manager/</link>
			<updated>2019-02-12T00:00:00-05:00</updated>
			<pubDate>2019-02-12T00:00:00-05:00</pubDate>
			<id>https://www.daveeddy.com/2019/02/12/smartos-coal-on-linux-kvm-with-virt-manager/</id>
			<gid>https://www.daveeddy.com/2019/02/12/smartos-coal-on-linux-kvm-with-virt-manager/</gid>
			<author>Dave Eddy</author>
			<summary type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/joyent/sdc-headnode&quot;&gt;COAL&lt;/a&gt;, or Cloud-on-a-Laptop, is an
easy way to run and test &lt;a href=&quot;https://smartos.org&quot;&gt;SmartOS&lt;/a&gt; and the &lt;a href=&quot;https://github.com/joyent/triton&quot;&gt;Triton
Stack&lt;/a&gt; in a self-contained VM meant to be run
on a laptop.  The &lt;a href=&quot;https://github.com/joyent/sdc-headnode&quot;&gt;sdc-headnode&lt;/a&gt;
repository makes a lot of assumptions when building a COAL image about using
VMWare for virtualization on an OS X laptop.  However, with some modifications
it is possible to run COAL on Linux via KVM managed through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virt-manager&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virt-manager&lt;/code&gt; setup and running on Void Linux, you can follow my guide
&lt;a href=&quot;/2019/02/11/kvm-virtualization-with-virtmanager-on-void-linux/&quot;&gt;KVM Virtualization with virt-manager on Void
Linux&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/booted.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/booted.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;nested-virtualization-optional&quot;&gt;Nested Virtualization (optional)&lt;/h3&gt;

&lt;p&gt;Before getting started with the COAL building process, you can choose to enable
nested virtualization if your hardware supports it.  This is required if you
would like to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bhyve&lt;/code&gt; zones on your COAL setup.  Note that this setup
assumes an Intel CPU.&lt;/p&gt;

&lt;p&gt;You can check if your CPU supports nested virtualization by running:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ grep ^flags /proc/cpuinfo | grep -c ' vmx '
8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;!-- more --&gt;

&lt;p&gt;If the number returned is greater than 0, then nested virtualization is
supported.  Create the following file:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/modprobe.d/kvm-nested.conf&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cfg&quot;&gt;options kvm-intel nested=1
options kvm-intel enable_shadow_vmcs=1
options kvm-intel enable_apicv=1
options kvm-intel ept=1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can either reboot the machine here for good measure or remove and re-add
the module to enable nested virtualization:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo modprobe -r kvm_intel
sudo modprobe -a kvm_intel
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, you can check to make sure it worked by running:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cat /sys/module/kvm_intel/parameters/nested
Y
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It will return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Y&lt;/code&gt; if nested virtualization is enabled.&lt;/p&gt;

&lt;h3 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h3&gt;

&lt;p&gt;You’ll need some external tools to build a COAL image.  On Void Linux these can
be installed with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo vpm i git nodejs parted ksh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To get started, pull the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sdc-headnode&lt;/code&gt; source code:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone git://github.com/joyent/sdc-headnode.git
cd sdc-headnode
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I use a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.spec.local&lt;/code&gt; file, as well as an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;answers.json&lt;/code&gt; file.
Feel free to modify these to fit your environment - I put what I consider the
fields that can be easily modified without issue at the top of the files.  The
IP addresses and NIC mac addresses will be used later on.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.spec.local&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;coal-memsize&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8192&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;answer-file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;answers.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;build-tgz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;vmware_version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;default-boot-option&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;clean-cache&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;answers.json&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;root_password&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;external_nic&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;52:54:00:00:00:01&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;external_ip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;10.88.88.200&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;admin_nic&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;52:54:00:00:00:00&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;admin_ip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;10.99.99.7&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;config_console&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;vga&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;skip_instructions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;simple_headers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;skip_final_confirm&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;skip_edit_config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;datacenter_company_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Joyent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;region_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;coal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;datacenter_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;coal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;datacenter_location&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My Laptop&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;admin_provisionable_start&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;admin_netmask&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;255.255.255.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;admin_gateway&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;10.99.99.7&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;setup_external_network&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;external_vlan_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;external_provisionable_start&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;external_provisionable_end&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;external_netmask&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;255.255.255.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;external_gateway&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;10.88.88.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;headnode_default_gateway&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_resolver1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_resolver2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_domain&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;joyent.us&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dns_search&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;joyent.us&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dhcp_range_end&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;10.99.99.253&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ntp_host&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;admin_password&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;joypass123&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;api_password&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;joypass123&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mail_to&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mail_from&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;phonehome_automatic&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;default&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;update_channel&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;release&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Again, take care when modifying any of these values because other values may
have to be modified as a result (like an interfaces IP address and its gateway
address).&lt;/p&gt;

&lt;h3 id=&quot;build-coal&quot;&gt;Build COAL&lt;/h3&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;answers.json&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.spec.local&lt;/code&gt; in place, the next step is to build
a COAL image.  This can be done simply by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make usb&lt;/code&gt; - I have a
small script that I use to do this.&lt;/p&gt;

&lt;p&gt;The script will run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make usb&lt;/code&gt; to build the USB image and then follow it up by
creating a symlink &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/vms/coal.img&lt;/code&gt; that points to the latest COAL image built:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do-make&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# stupidly simple script to make COAL and link it to an img file&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;MANTA_NO_AUTH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1

&lt;span class=&quot;nv&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/vms/coal.img

make usb &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit

&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;latest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=(&lt;/span&gt;usb-master-&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.img&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;latest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;latest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[-1]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%/*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-svf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PWD&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$latest&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$img&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that this script can be run any time to build a new COAL image, but it
should be run when the COAL VM is not running:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./do-make
...
sent 2,984,703,731 bytes  received 5,321 bytes  192,561,874.32 bytes/sec
total size is 2,983,956,095  speedup is 1.00
WARNING: Copying in answers.json, remove answer-file from build.spec* to disable.
==&amp;gt; Cleaning up
==&amp;gt; Creating usb-master-20190210T041835Z-gafc88889/
'/home/dave/vms/coal.img' -&amp;gt; '/home/dave/dev/sdc-headnode/usb-master-20190210T041835Z-gafc88889/usb-master-20190210T041835Z-gafc88889-4gb.img'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;p&gt;Every time &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do-make&lt;/code&gt; is run, a new USB image will be created.  I also have a
small script called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clean&lt;/code&gt; that can delete all old builds and keep the latest
X (2 by default):&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clean&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# clean builds from sdc-headnode&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# keep this number of the latest builds&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;keep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2

&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;f &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;boot usb&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
	&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;-&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${#&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[@]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;len &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; keep&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
		&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;len -&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; keep&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
		&lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[@]&lt;/span&gt;:0:len&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;else
		continue
	fi

	for &lt;/span&gt;d &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[@]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
		&lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;continue
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;removing &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;done
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setup-virtual-networks&quot;&gt;Setup Virtual Networks&lt;/h3&gt;

&lt;p&gt;COAL requires 2 networks to be setup: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;external&lt;/code&gt;.  To create these
networks, double-click the “QEMU/KV” section of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virt-manager&lt;/code&gt; GUI:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/virt-manager-double-click.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/virt-manager-double-click.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will open an overview page.  From there click the “Virtual Networks” tab
and create 2 networks as follows.&lt;/p&gt;

&lt;p&gt;Note that you may already have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt; network created; this is ok and can
be left alone as we won’t be using it for COAL.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;external&lt;/code&gt; network with the following settings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Network: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.88.88.0/24&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;DHCP range: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;disabled&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Forwarding: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NAT&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/network-external.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/network-external.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin&lt;/code&gt; network with no IP configuration whatsoever:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/network-admin.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/network-admin.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;create-the-vm&quot;&gt;Create the VM&lt;/h3&gt;

&lt;p&gt;With the 2 virtual networks, the VM can now be created.  To create the VM,
click the “new” button in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virt-manager&lt;/code&gt; to open the wizard and start the
process:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/virt-manager-new-button.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/virt-manager-new-button.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 1: Select “Local install media”.  The architecture should be set to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x86_64&lt;/code&gt; (this should be default):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/create-new-vm-1-5-media.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/create-new-vm-1-5-media.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 2: Specify the location of the USB image created above, and set the OS to
“Generic default”:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/create-new-vm-2-5-img.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/create-new-vm-2-5-img.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 3: Set the memory to 8192 (or the value specified in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.spec.local&lt;/code&gt;)
and the number of CPUs to 4 (or whatever you’d like):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/create-new-vm-3-5-ram-cpu.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/create-new-vm-3-5-ram-cpu.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 4: Enable storage for the VM and create a disk (I personally use 100GiB
just to make sure that running out of storage space isn’t an issue):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/create-new-vm-4-5-storage.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/create-new-vm-4-5-storage.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 5: Name the instance (I chose to call mine COAL), and tick “Customize
configuration before install” - there are still some steps to finish before the
VM is ready to run:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/create-new-vm-5-5-verify.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/create-new-vm-5-5-verify.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;customize-the-vm&quot;&gt;Customize the VM&lt;/h3&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;configure-cpu&quot;&gt;Configure CPU&lt;/h4&gt;

&lt;p&gt;If you’d like to have nested virtualization (assuming your hardware supports
it), set the CPU model to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host-passthrough&lt;/code&gt;.  This option will have to be
written in manually as it will not come up automatically or with autocomplete:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/host-passthrough.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/host-passthrough.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;configure-network&quot;&gt;Configure Network&lt;/h4&gt;

&lt;p&gt;Click the “Add Hardware” button to add a second network device.&lt;/p&gt;

&lt;p&gt;Create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin&lt;/code&gt; NIC by setting the network source to “Virtual Network:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin&lt;/code&gt;”, and set the MAC address to the value used in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;answers.json&lt;/code&gt; as
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin_nic&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/nic-admin.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/nic-admin.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;external&lt;/code&gt; NIC by setting the network source to “Virtual Network:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;external&lt;/code&gt;”, and set the MAC address to the value used in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;answers.json&lt;/code&gt; as
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;external_nic&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/nic-external.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/nic-external.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;configure-usb&quot;&gt;Configure USB&lt;/h4&gt;

&lt;p&gt;The USB image file will be setup as an “IDE CDROM” drive.  Delete this device,
and then click “Add Hardware” to add a new “Storage” device.  Check the “Select
or create custom storage” option and set the following parameters:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Path: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/vms/coal.img&lt;/code&gt; (or path where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do-make&lt;/code&gt; linked the latest image)&lt;/li&gt;
  &lt;li&gt;Device type: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Disk Device&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Bus type: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;USB&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/vm-storage.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/vm-storage.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the newly created USB device, go to the “Boot Options” section and make
sure it is checked to be the only bootable device - this device contains the
SmartOS image itself and will be used to boot the OS:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/vm-boot-options.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/vm-boot-options.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;configure-ide-disk&quot;&gt;Configure IDE Disk&lt;/h4&gt;

&lt;p&gt;I’ve personally noticed that configuring the IDE disk to use the VirtIO Disk
bus has resulted in better performance in the VM.  Click the IDE disk in the
configure window and change the “Disk bus” setting to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VirtIO&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/virtio-disk.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/virtio-disk.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;boot-the-vm&quot;&gt;Boot the VM&lt;/h3&gt;

&lt;p&gt;Click the “Begin Installation” button at the top-left of the window to boot the
VM and start the installation!&lt;/p&gt;

&lt;p&gt;After the machine boots a lot of work will be done to finalize the install.
The VM will reboot on its own during this process and then will provision
every zone needed for COAL to function.  A screen like this should appear on
the console when it has finished installing:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/static/media/2019/virt-coal/setup-complete.png&quot;&gt;&lt;img src=&quot;/static/media/2019/virt-coal/setup-complete.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;logging-in&quot;&gt;Logging in&lt;/h3&gt;

&lt;p&gt;Once the setup has completed, the COAL instance is now ready to be used!  To
login to the machine, you can add a section your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt; file for COAL:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-cfg&quot;&gt;Host coal
	ServerAliveInterval 120
	User root
	Hostname 10.88.88.200
	ForwardAgent yes
	StrictHostKeyChecking no
	UserKnownHostsFile /dev/null
	ControlMaster no
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, with this in place, login simply with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh coal&lt;/code&gt; (the password is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt;
or whatever was set in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;answers.json&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ssh coal
Warning: Permanently added '10.88.88.200' (ECDSA) to the list of known hosts.
Password:
- SmartOS (build: 20190208T131006Z)
[root@headnode (coal) ~]#
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can get DC information with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sdcadm&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[root@headnode (coal) ~]# sdcadm experimental info
Datacenter Company Name: Joyent
Datacenter Name: coal
Datacenter Location: My Laptop

Admin IP: 10.99.99.7
External IP: 10.88.88.200
DNS Domain: joyent.us
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To check that nested virtualization worked as expected and that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bhyve&lt;/code&gt; zones
can be provisioned, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sysinfo&lt;/code&gt; can be checked for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bhyve Capable&lt;/code&gt; property:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[root@headnode (coal) ~]# sysinfo | json 'Bhyve Capable'
true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Health checks can be run to verify that everything is working as expected:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[root@headnode (coal) ~]# sdc-healthcheck
ZONE                                 STATE           AGENT               STATUS
global                               running         -                   online
assets                               running         -                   online
sapi                                 running         -                   online
binder                               running         -                   online
manatee                              running         -                   online
moray                                running         -                   online
amonredis                            running         -                   online
ufds                                 running         -                   online
workflow                             running         -                   online
amon                                 running         -                   online
sdc                                  running         -                   online
papi                                 running         -                   online
napi                                 running         -                   online
rabbitmq                             running         -                   online
imgapi                               running         -                   online
cnapi                                running         -                   online
dhcpd                                running         -                   online
fwapi                                running         -                   online
vmapi                                running         -                   online
ca                                   running         -                   online
mahi                                 running         -                   online
adminui                              running         -                   online
global                               running         ur                  online
global                               running         smartlogin          online
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[root@headnode (coal) ~]# sdcadm health
INSTANCE                              SERVICE          HOSTNAME  ALIAS       HEALTHY
e3512f4b-47d0-42b4-b181-510c44631086  adminui          headnode  adminui0    true
4ba89fe1-739b-4689-b5be-2b106c8bab92  amon             headnode  amon0       true
7ed7e5cf-8867-4e7b-a882-57c2662c0487  amonredis        headnode  amonredis0  true
a4f91949-8427-4926-9933-2f0ffe18c5a5  assets           headnode  assets0     true
bf778a2c-1b65-4899-8b67-1314582bb484  binder           headnode  binder0     true
96a42299-d4da-4423-a1cd-75b0245bb0ed  ca               headnode  ca0         true
98f20bf8-796c-406c-9924-c16e9a40703d  cnapi            headnode  cnapi0      true
e00d35b2-9018-478d-85db-bfe944319a0a  dhcpd            headnode  dhcpd0      true
afaff931-d8b2-4173-94e2-3306dff79179  fwapi            headnode  fwapi0      true
b3ce95a5-a255-4b00-93c9-f3055d8471e4  imgapi           headnode  imgapi0     true
114bd1d3-e174-4585-9ab7-977260237c9d  mahi             headnode  mahi0       true
0e40cd43-4556-401c-85d8-98f766996cf3  manatee          headnode  manatee0    true
465a7ca3-5e17-4740-a0cb-f3f55089a7b0  moray            headnode  moray0      true
142a8178-d17b-43a4-bcf6-36968212041d  napi             headnode  napi0       true
847f96a2-f943-458f-9d71-892d1f273b15  papi             headnode  papi0       true
3d8d8c0a-33c1-4c8c-b95b-4143d829b795  rabbitmq         headnode  rabbitmq0   true
5ea05603-e4f3-4618-83c5-16f876293c39  sapi             headnode  sapi0       true
8071a1a6-f056-4e6d-8eac-e6ac7715f7d6  sdc              headnode  sdc0        true
05924e1d-4948-49d1-8e26-ceef20dc5118  ufds             headnode  ufds0       true
69c8427c-42b0-4c3c-94e8-dcc4509c2fa6  vmapi            headnode  vmapi0      true
15c34920-c423-4f52-87f8-12b6079cf0fa  workflow         headnode  workflow0   true
9ad2f41c-13c4-b541-bd60-0c6230916ed7  global           headnode  global      true
4b04c9ce-8776-482f-8655-4aaa2f56f417  amon-agent       headnode  -           true
40ed0710-f5be-4948-b057-b9b7326790a1  amon-relay       headnode  -           true
13e16c93-2568-4368-ab82-ff2d306d2fb8  cmon-agent       headnode  -           true
6bafb5d9-a931-4dc3-a649-4c71a1e91823  cn-agent         headnode  -           true
07214449-0e9e-431b-951e-27d6c697f527  config-agent     headnode  -           true
732f2d92-e67a-40d6-bfe5-f0edf66b16b0  firewaller       headnode  -           true
e355af90-5bc7-4d2e-8eb4-dd3009090c3f  hagfish-watcher  headnode  -           true
ca2a413b-58fb-4a5f-85ef-25aa7c9e36ab  net-agent        headnode  -           true
8062f7c5-9afe-42fa-ab6a-af28d2d35522  smartlogin       headnode  -           true
f0e74f08-ac1e-4952-8b38-624825d48196  vm-agent         headnode  -           true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And finally, the test suite can be run against the platform (note this will
take a long time, but is useful for testing changes to the platform itself):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[root@headnode (coal) ~]# touch /lib/sdc/.sdc-test-no-production-data
[root@headnode (coal) ~]# /usr/vm/test/runtests
# Running /usr/vm/test/tests/test-50-creates.js
Added &quot;imgapi&quot; image source &quot;https://images.joyent.com/&quot;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;staying-up-to-date&quot;&gt;Staying up-to-date&lt;/h3&gt;

&lt;p&gt;With the COAL VM powered down, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do-make&lt;/code&gt; script can be run at any time to
build a new COAL image with all of the latest agents and platform bits.  After
that finishes and the USB image is linked, simply turn the VM back on to run
the latest version.&lt;/p&gt;

&lt;p&gt;Also, I have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update-sdc&lt;/code&gt; script I use in the below section to keep an
image updated without having to rebuild the entire image.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;development-and-tools&quot;&gt;Development and Tools&lt;/h3&gt;

&lt;p&gt;Everyone seems to have their own methods for working with COAL and SmartOS in
general, myself included.  I have created a bunch of tools along the way that
have helped when developing on/for SmartOS.&lt;/p&gt;

&lt;h4 id=&quot;update-sdc&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update-sdc&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;This script is useful for updating sdc/triton on a COAL instance without having
to rebuild the image.&lt;/p&gt;

&lt;p&gt;All steps are based on the update documentation in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sdcadm&lt;/code&gt; repository:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;https://github.com/joyent/sdcadm/blob/master/docs/update.md&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update-sdc&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; errexit

sdcadm&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;== sdcadm &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; ==&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;command &lt;/span&gt;sdcadm &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

sdcadm self-update &lt;span class=&quot;nt&quot;&gt;--latest&lt;/span&gt;

sdcadm experimental update-gz-tools &lt;span class=&quot;nt&quot;&gt;--latest&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--just-download&lt;/span&gt;
sdcadm experimental update-agents &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--latest&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--just-download&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;

sdcadm dc-maint start

&lt;span class=&quot;nv&quot;&gt;uuid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;updates-imgadm list &lt;span class=&quot;nt&quot;&gt;--latest&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;agentsshar &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; uuid &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$uuid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;f &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; /usbkey/extra/agents/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
	if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ &lt;span class=&quot;nv&quot;&gt;$uuid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
		&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true
		break
	&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi
done
if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$found&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
	&lt;/span&gt;sdcadm experimental update-agents &lt;span class=&quot;nt&quot;&gt;--latest&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--yes&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;sdcadm experimental update-other
sdcadm experimental update-gz-tools &lt;span class=&quot;nt&quot;&gt;--latest&lt;/span&gt;

sdcadm up &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--force-data-path&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; sapi &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; moray &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; binder &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; manatee
sdcadm up sapi &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;
sdcadm up moray &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;
sdcadm up binder &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;
sdcadm up manatee &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;

sdc-healthcheck
sdcadm health

sdcadm dc-maint stop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;pull-latest-platform&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pull-latest-platform&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;This script will pull the latest compiled platform tarball from my build zone.
I will iterate in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smartos-live&lt;/code&gt; repo and often make changes to the
platform that need to be tested.  This script, when ran on COAL, will reach out
to my build zone and pull the latest compiled tarball and install it.  It’s not
the prettiest script, but for what it does it works and it makes development
very easy.&lt;/p&gt;

&lt;p&gt;Swap out the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;latest&lt;/code&gt; variable to fit your environment:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pull-latest-platform&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/var/tmp/platforms'&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;stamp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TZ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;UTC &lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'+%Y%m%dT%H%M%SZ'&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dir&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$stamp&lt;/span&gt;.tgz
&lt;span class=&quot;nv&quot;&gt;latest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dave@10.0.1.29:joyent/smartos-live/output/platform-latest.tgz'&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dir&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dir&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit

echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-- pulling latest from build to &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stamp&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; --&quot;&lt;/span&gt;
scp &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;StrictHostKeyChecking&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;no &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$latest&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit

echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'-- cleaning key --'&lt;/span&gt;
/usbkey/scripts/cleanup-key.sh

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'-- installing --'&lt;/span&gt;
sdcadm platform &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'-- assigning --'&lt;/span&gt;
sdcadm platform assign &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stamp&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

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

&lt;p&gt;Having COAL on my laptop makes it really easy to test and develop on SmartOS
with the latest code.  My personal development cycle is fairly
straight-forward:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Build a COAL image using the above steps.&lt;/li&gt;
  &lt;li&gt;Optionally &lt;a href=&quot;https://wiki.smartos.org/display/DOC/Building+SmartOS+on+SmartOS&quot;&gt;compile a SmartOS
platform&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Boot the COAL image.&lt;/li&gt;
  &lt;li&gt;Optionally install the compiled platform.&lt;/li&gt;
  &lt;li&gt;Do whatever testing I need, then go back to step 1 or 3 depending on what
I’m testing specifically.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Having COAL as easily on Linux as I do on OS X makes it simple to just focus on
the actual development and iterative process involved with that, as opposed to
worrying about getting the underlying system set up.  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virt-manager&lt;/code&gt; and the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virsh&lt;/code&gt; command make it easy to manage the lifecycle of the VM as well,
although normally I only need the ability to start and stop the VM.&lt;/p&gt;
</summary>
		</item>
		
	</channel>
</rss>
