<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Billy Overton</title>
    <description>Personal blog and home page for Billy Overton, programmer and technology consultant
</description>
    <link>https://billyoverton.com/</link>
    <atom:link href="https://billyoverton.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Mon, 26 Sep 2016 00:52:57 -0400</pubDate>
    <lastBuildDate>Mon, 26 Sep 2016 00:52:57 -0400</lastBuildDate>
    <generator>Jekyll v3.0.0</generator>
    
      <item>
        <title>Smart Meter Dashboard: Collecting the Data</title>
        <description>&lt;p&gt;&lt;strong&gt;Previous Post:&lt;/strong&gt; &lt;a href=&quot;/2016/05/30/smart-meter-installing-and-configuring-influxdb.html&quot;&gt;Smart Meter Dashboard: Installing and Configuring InfluxDb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I had a place to store my power usage data, I needed to start actually
collecting it. I already had my radio and software picked out during my initial
testing, but now I needed a more permanent setup. With the idea being to lower
my power usage, I couldn’t just leave my desktop running all the time. On my first
attempt I tried an older Raspberry PI Model B I had laying around, but it couldn’t
keep up with the processor load. While it would catch a few entries, for the most
part it would drop the data.&lt;/p&gt;

&lt;p&gt;A perfect excuse to get a new PI. I went with Raspberry PI 3, although I expect
this will work with a Model 2 B.&lt;/p&gt;

&lt;h3 id=&quot;installing-rtl-sdr&quot;&gt;Installing RTL-SDR&lt;/h3&gt;
&lt;p&gt;I installed the requirements for RTL-SDR based on &lt;a href=&quot;https://learn.adafruit.com/freq-show-raspberry-pi-rtl-sdr-scanner/installation&quot;&gt;Adafruit’s SDR scanner&lt;/a&gt;
 tutorial. I only needed the requirements for rtl-sdr since I’m not using
a python library to interact with the radio directly.&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;sudo apt-get update
sudo apt-get install cmake build-essential libusb-1.0-0-dev git&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~
git clone git://git.osmocom.org/rtl-sdr.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;rtl-sdr
mkdir build
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;build
cmake ../ -DINSTALL_UDEV_RULES&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ON -DDETACH_KERNEL_DRIVER&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ON
make
sudo make install
sudo ldconfig&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;setting-rtl-tcp-to-start-at-boot&quot;&gt;Setting rtl-tcp To Start At Boot&lt;/h3&gt;
&lt;p&gt;Rtlamr uses rtl-tcp to control and read data from the radio. For testing purposes
you can start it on its own terminal by running &lt;code&gt;sudo rtl-tcp&lt;/code&gt;, but I wanted
something that would start automatically on boot. To do this, I created a systemd
unit file at &lt;code&gt;/etc/systemd/system/rtl-tcp.service&lt;/code&gt; that will always restart the
service if it fails.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;[Unit]
Description=Software Defined Radio TCP Server
Wants=network.target
After=network.target

[Service]
ExecStart=/usr/local/bin/rtl_tcp
Restart=always

[Install]
WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once that is created I set it to start on boot with
&lt;code&gt;sudo systemctl enable rtl-tcp.service&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;installing-go-and-rtlamr&quot;&gt;Installing Go and Rtlamr&lt;/h3&gt;
&lt;p&gt;The version of Go in the Rasbian repository was high enough to allow rtlamr to
run, so I used it instead of compiling or installing a later ARM Go version:
&lt;code&gt;sudo apt-get install golang&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once that was installed, I went through the standard Go setup procedure to create
my Go path folder and adding the Go environment variables to my &lt;code&gt;.profile&lt;/code&gt; file.&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;...
&lt;span class=&quot;nv&quot;&gt;GOPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;/go
&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/go/bin:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can reload your &lt;code&gt;.profile&lt;/code&gt; by running &lt;code&gt;. ~/.profile&lt;/code&gt;. With that done, the
installation of Rtlamr was as simple as &lt;code&gt;go get github.com/bemasher/rtlamr&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For simplicity, I copied the binary to a dedicated location as root.&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;sudo mkdir /opt/powermon
sudo cp /home/pi/go/bin/rtlamr /opt/powermon&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;/h3&gt;
&lt;p&gt;To make sure everything was working I ran rtlamr at the console to make sure it
was receiving data. There are quite a few apartments near mine using the same
meter type, so it didn’t take long to see a large number of results coming through.&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;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;sudo systemctl start rtl_tcp.service
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;/opt/powermon/rtlamr
05:10:44.703399 decode.go:79: CenterFreq: 912600155
05:10:44.703907 decode.go:79: SampleRate: 2359296
05:10:44.704002 decode.go:79: DataRate: 32768
05:10:44.704083 decode.go:79: SymbolLength: 72
05:10:44.704161 decode.go:79: PreambleSymbols: 21
05:10:44.704242 decode.go:79: PreambleLength: 3024
05:10:44.704322 decode.go:79: PacketSymbols: 96
05:10:44.704403 decode.go:79: PacketLength: 13824
05:10:44.704481 decode.go:79: Preamble: 111110010101001100000
05:10:44.704564 recv.go:93: GainCount: 29
&amp;lt;DATA&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can filter the results to only include your meter using the &lt;code&gt;--filterid&lt;/code&gt;
switch. My meter had the ID printed on it, but it wouldn’t have been hard to
compare my current meter reading to all of the results to find the ID.&lt;/p&gt;

&lt;h3 id=&quot;influx-python-upload-script&quot;&gt;Influx Python Upload Script&lt;/h3&gt;

&lt;p&gt;The final step of the collection was to send the data to InfluxDB. I decided
to go with a simple Python script to parse then forward that information on to
the database. Rtlmar is capable of outputting its data in JSON format which
made reading the data simple line by line. Python also has a nice Influx client
library (that I was already planning to use on the API side of things), however
the version that is in the Rasbian package is out of date and does not work with
the latest Influx version. The one in pip works just fine.&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;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;sudo apt-get install python-pip
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;sudo pip install influxdb &lt;span class=&quot;c&quot;&gt;# Do not use the python-influxdb package&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The script itself is pretty simple. It starts rtlamr with a filter for my meter’s
ID and a JSON output format. The output is parsed line by line, converted into
a format for Influx, and then sent onward. Below is the current state of the
script (with placeholders for my db info and my meter ID).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;json&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;subprocess&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;influxdb&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InfluxDBClient&lt;/span&gt;


&lt;span class=&quot;c&quot;&gt;# Delay. Useful for now while I try and figure out systemd targets. I&#39;ve had&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# issues where if both powermon and rtlamr start immediately at boot, no data is&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# reported. The delay solves the problem but I don&#39;t like it.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InfluxDBClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;{influx host}&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8086&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&#39;{username}&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&#39;{password}&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&#39;{database}&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Popen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;/opt/powermon/rtlamr&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&#39;-filterid={meter ID}&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&#39;-quiet=true&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&#39;-format=json&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PIPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readline&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;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;message&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;s&quot;&gt;&quot;measurement&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;consumption&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;Time&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;tags&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;s&quot;&gt;&quot;meter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;Message&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;ID&#39;&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;s&quot;&gt;&quot;fields&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;s&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;Message&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;Consumption&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}}]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write_points&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&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;Just like rtl_tcp, I created a systemd unit file to start powermon at boot.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;[Unit]
Description=Python PowerMon Influx Client
Wants=network-online.target rtl_tcp.service
After=network-online.target rtl_tcp.service

[Service]
ExecStart=/opt/powermon/powermon.py
Restart=always

[Install]
WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I then enabled it &lt;code&gt;sudo systemctl enable powermon.service&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;problems&quot;&gt;Problems&lt;/h3&gt;
&lt;p&gt;For now the biggest problem I’m having is the clock on the Raspberry Pi. Any time
I lose power (a very infrequent event), the clock gets out of sync. I’ve tried
some of the recommended fixes, but so far nothing has seemed to work. I don’t
lose any data when this occurs, but the it does throw off the data.&lt;/p&gt;

&lt;p&gt;I’m also not a fan of having the 2 minute delay in the script, but that’s a
relatively minor problem for now.&lt;/p&gt;
</description>
        <pubDate>Sun, 19 Jun 2016 00:00:00 -0400</pubDate>
        <link>https://billyoverton.com/2016/06/19/smart-meter-collecting-the-data.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2016/06/19/smart-meter-collecting-the-data.html</guid>
        
        <category>smart-meter-dashboard</category>
        
        
      </item>
    
      <item>
        <title>Smart Meter Dashboard: Installing InfluxDB</title>
        <description>&lt;p&gt;For this project I knew I didn’t want to store a log of the information from the
meter on the Pi. Through some testing, I determined that my power meter broadcasted
it’s consumption about once every 30 seconds. While there isn’t much data overall
that I wanted to store, I was kind of hesitant to write to a file on the Pi’s SD
card that frequently. Looking around for a simple time series database, I found &lt;a href=&quot;https://influxdata.com/&quot;&gt;InfluxDB&lt;/a&gt;
which seemed perfect for my use case.&lt;/p&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;

&lt;p&gt;After spinning up a new Debian droplet, the installation was pretty simple.&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;&lt;span class=&quot;c&quot;&gt;# Enable the influxDB&lt;/span&gt;
curl -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add -
&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; /etc/os-release
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;deb https://repos.influxdata.com/debian jessie stable&quot;&lt;/span&gt; | sudo tee /etc/apt/sources.list.d/influxdb.list

&lt;span class=&quot;c&quot;&gt;# Install the packages&lt;/span&gt;
sudo apt-get update &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo apt-get install influxdb
sudo service influxdb start&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;creating-a-database&quot;&gt;Creating a Database&lt;/h3&gt;

&lt;p&gt;Creating a database was pretty simple using the provided command line client.&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;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;influx
&lt;span class=&quot;gp&quot;&gt;&amp;gt; &lt;/span&gt;CREATE DATABASE power
&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;enable-ssl&quot;&gt;Enable SSL&lt;/h3&gt;
&lt;p&gt;Since I planned on having authentication to prevent direct database access, I didn’t
want the communication between my local machine and the server to be in clear text.
By default influxDB does all of it’s communication over HTTP, but it does have
support for SSL. To enable it I needed to create a PEM encoded SSL key and certificate.
For my purposes a self-signed certificate was good enough, but for added security
(namely SSL validation) a signed certificate should be used.&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;&lt;span class=&quot;c&quot;&gt;# Create self-signed certificate for influx&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /etc/ssl
openssl genrsa -out key.pem 2048 &lt;span class=&quot;c&quot;&gt;# Generate a private key&lt;/span&gt;
openssl req -new -key key.pem -out cert.csr &lt;span class=&quot;c&quot;&gt;# Create a certificate signing request&lt;/span&gt;
openssl x509 -req -days 365 -in cert.csr -signkey key.pem -out cert.pem &lt;span class=&quot;c&quot;&gt;# Sign the certificate with the key&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Influx uses a combined file for both the private key and the certificate file, so
I had to append them together.&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;cat key.pem &amp;gt; influxDB.pem
cat cert.pem &amp;gt;&amp;gt; influxDB.pem&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once the combined file was created, I enable ssl by editing &lt;code&gt;/etc/influxdb/influxdb.conf&lt;/code&gt;.
I scrolled down to the sections for &lt;code&gt;[admin]&lt;/code&gt; changed the &lt;code&gt;https-enabled&lt;/code&gt; option
to &lt;code&gt;true&lt;/code&gt; and changed the &lt;code&gt;https-certificate&lt;/code&gt; to the path of the newly created
combined PEM file. For me that was &lt;code&gt;https-certificate = &quot;/etc/ssl/influxDB.pem&quot;&lt;/code&gt;.
I did the same in the &lt;code&gt;[http]&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;I tested if this was successful by restarting the influxdb service with
&lt;code&gt;sudo service influxdb restart&lt;/code&gt; and attempted to connect using the influx command
line tool. Since SSL is enabled you need to pass a few more flags in order for
this to work: &lt;code&gt;influx -ssl -unsafeSsl&lt;/code&gt;. Since I used a self-signed certificate, I had to use the &lt;code&gt;-unsafeSsl&lt;/code&gt; flag to disable the clients validation step.&lt;/p&gt;

&lt;h1 id=&quot;enable-authorization-and-authentication&quot;&gt;Enable Authorization and Authentication&lt;/h1&gt;
&lt;p&gt;By default influxDB does not have authorization and authentication enabled.
To enable it you must first create at least one administrator user account. I used
the command line client to create two users: an admin user with all privileges and
a power user that only has permissions to the power database I created earlier.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;influx -ssl -unsafeSsl
&amp;gt; CREATE USER admin WITH PASSWORD &#39;&amp;lt;password&amp;gt;&#39; WITH ALL PRIVILEGES
&amp;gt; CREATE USER power WITH PASSWORD &#39;&amp;lt;password&amp;gt;&#39;
&amp;gt; GRANT [READ,WRITE,ALL] ON power TO power&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once the users were created, I enabled authentication by editing
&lt;code&gt;/etc/influxdb/influxdb.conf&lt;/code&gt; again. In the &lt;code&gt;[http]&lt;/code&gt; section, I changed &lt;code&gt;auth-enabled&lt;/code&gt;
to &lt;code&gt;true&lt;/code&gt;. I restarted the influx service and relaunch the influx command line
client. It should deny all requests to read data till you authenticate with
&lt;code&gt;&amp;gt; auth &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;/code&gt;. Alternatively you can launch with
&lt;code&gt;influx -ssl -unsafeSsl -username &amp;lt;username&amp;gt; -password &amp;lt;password&amp;gt;&lt;/code&gt; to authenticate
before the client launches.&lt;/p&gt;

&lt;h3 id=&quot;next-step&quot;&gt;Next Step&lt;/h3&gt;

&lt;p&gt;Once I had a place to store my power usage information, I needed to setup the
radio to pickup and send the information over to influxDB. That will be the topic
of the next post.&lt;/p&gt;
</description>
        <pubDate>Mon, 30 May 2016 00:00:00 -0400</pubDate>
        <link>https://billyoverton.com/2016/05/30/smart-meter-installing-and-configuring-influxdb.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2016/05/30/smart-meter-installing-and-configuring-influxdb.html</guid>
        
        <category>smart-meter-dashboard</category>
        
        
      </item>
    
      <item>
        <title>Smart Meter Dashboard: Introduction</title>
        <description>&lt;p&gt;While browsing around some older posts on &lt;a href=&quot;http://hackaday.com/2014/02/25/using-sdr-to-read-your-smart-meter/&quot;&gt;Hackaday&lt;/a&gt;, I
came across a post about reading the broadcasted data from smart meters
using a software defined radio (SDR). It got me wondering if my apartment’s
meter broadcasted similar data. I knew that nobody physically checked the meter
each month, so there had to be some kind of remote reporting capability. A few
google searches later I found a timeline for my local power company’s
installation of smart meters in the area, which roughly matched up with the date
of the Hackaday article. On the off chance that the software would work with
with my meter, I ordered a RTL-SDR supported tuner
(a &lt;a href=&quot;http://www.nooelec.com/store/nesdr-nano2-plus.html&quot;&gt;NooElec NESDR Nano 2+&lt;/a&gt;).
A couple days later I had a successful test and a new project to try.&lt;/p&gt;

&lt;p&gt;I’m wanting to make a dashboard to display a few stats to help track (and maybe
  reduce) my home power usage:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Current usage rate (kWh/m)&lt;/li&gt;
  &lt;li&gt;Final estimated bill based on historical rates and usage&lt;/li&gt;
  &lt;li&gt;Current estimated bill since last reading&lt;/li&gt;
  &lt;li&gt;Usage for the last 24 hours (by hour)&lt;/li&gt;
  &lt;li&gt;Usage for the last 30 days (by day)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There will be a follow up post soon as I’ve already done some work on collecting
and recording the data. Posts on the dashboard creation will follow as time allows.&lt;/p&gt;
</description>
        <pubDate>Thu, 05 May 2016 00:00:00 -0400</pubDate>
        <link>https://billyoverton.com/2016/05/05/smart-meter-dashboard-introduction.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2016/05/05/smart-meter-dashboard-introduction.html</guid>
        
        <category>smart-meter-dashboard</category>
        
        
      </item>
    
      <item>
        <title>Horrible, Semi-Anonymous, Secure Communication</title>
        <description>&lt;p&gt;Recently I’ve been thinking about how to make a secure chat program that also
hides who is talking to who. I really don’t have a need for it, but it has been
a fun thought exercise. The main problem I’ve been having is figuring out how to
make an efficient scheme that accomplishes it.&lt;/p&gt;

&lt;p&gt;To handle the secure side of things, using a public key system seemed to make
sense. It allows confirmation of who you’re talking to by comparing the public
key fingerprint they provide to one you confirm in person, while also making it
easy to transmit block level encryption keys securely for messaging. However it
does have the drawback that now it’s obvious who is talking to who. If Alice
uses Bob’s public key to send him a message… it’s obvious that Alice is talking
to Bob. At the very least it reveals that Bob is receiving messages.&lt;/p&gt;

&lt;p&gt;To get around this, I came up with a horribly inefficient “public wall” system
that hides most of the knowledge about who is talking to who, while still allowing
confirmation of who you’re talking to. It’s horribly inefficient however because
of the number of messages that end up on a system with too many users.&lt;/p&gt;

&lt;p&gt;Here is an example of a conversation with four online users &lt;script type=&quot;math/tex&quot;&gt;U:\{A,B,C,D\}&lt;/script&gt;
and a shared wall &lt;script type=&quot;math/tex&quot;&gt;W&lt;/script&gt;. In this case user &lt;script type=&quot;math/tex&quot;&gt;A&lt;/script&gt; wants to talk with user &lt;script type=&quot;math/tex&quot;&gt;C&lt;/script&gt;
without letting the other users know.&lt;/p&gt;

&lt;script type=&quot;math/tex; mode=display&quot;&gt;% &lt;![CDATA[
\begin{eqnarray}
A &amp;\rightarrow&amp; W:\{\mbox{I want to talk}\} \\
B &amp;\rightarrow&amp; A:\{\{R_1\}_{K_B}\}_{K_A} \\
C &amp;\rightarrow&amp; A:\{\{R_2\}_{K_C}\}_{K_A}\\
D &amp;\rightarrow&amp; A:\{\{R_3\}_{K_D}\}_{K_A} \\
A &amp;\rightarrow&amp; W:R_2,\{\{R_4,\mbox{Hello}\}_{K_A}\}_{K_C} \\
C &amp;\rightarrow&amp; W:R_4,\{\{R_5,\mbox{Greetings}\}_{K_C}\}_{K_A}
\end{eqnarray} %]]&gt;&lt;/script&gt;

&lt;p&gt;User &lt;script type=&quot;math/tex&quot;&gt;A&lt;/script&gt; starts by stating publicly it wants to talk to somebody. All other
users respond to this request by sending an encrypted and signed randomly chosen
identifier &lt;script type=&quot;math/tex&quot;&gt;R_x&lt;/script&gt;. The suffix in this case doesn’t show a sequence, just that
the identifier is unique from the others. Once the identifier from the intended
recipient is received &lt;script type=&quot;math/tex&quot;&gt;A&lt;/script&gt; sends their message publicly. The message
is comprised of the unencrypted random identifier, and then a signed and
encrypted message containing a new identifier and the actual message. The recipient
knows the message is for them because of the identifier, and can decrypt and respond
using the identifier it received.&lt;/p&gt;

&lt;h3 id=&quot;problems&quot;&gt;Problems&lt;/h3&gt;
&lt;p&gt;There are quite a few attacks against the system. It’s vulnerable to collusion.
If enough of the users talk to each, it’s possible to discover who is sending
messages to who. In the example above, if &lt;script type=&quot;math/tex&quot;&gt;B&lt;/script&gt; and &lt;script type=&quot;math/tex&quot;&gt;D&lt;/script&gt; both talk and agree
they are not speaking with A, then any messages seen becomes known to be between
&lt;script type=&quot;math/tex&quot;&gt;A&lt;/script&gt; and &lt;script type=&quot;math/tex&quot;&gt;C&lt;/script&gt;. Ideally this should require collusion by &lt;script type=&quot;math/tex&quot;&gt;|U|-2&lt;/script&gt; users
in order to become absolutely certain.&lt;/p&gt;

&lt;p&gt;There are probably other issues related to replay attacks. Using multiple keys
to send the same message, etc. I haven’t quite thought through all the of issues
yet. It’s more of a general idea than something concrete at this point.&lt;/p&gt;
</description>
        <pubDate>Thu, 03 Sep 2015 00:00:00 -0400</pubDate>
        <link>https://billyoverton.com/2015/09/03/horrible-anonymous-secure-communication.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2015/09/03/horrible-anonymous-secure-communication.html</guid>
        
        
      </item>
    
      <item>
        <title>World of Warcraft Analysis Fail</title>
        <description>&lt;script type=&quot;text/javascript&quot; src=&quot;//static.wowhead.com/widgets/power.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;var wowhead_tooltips = { &quot;colorlinks&quot;: true, &quot;iconizelinks&quot;: true, &quot;renamelinks&quot;: true }&lt;/script&gt;

&lt;p&gt;Over the last two weeks I’ve been running a script to download the auction
snapshots for my old World of Warcraft realm Madoran as a follow up to my
&lt;a href=&quot;/2015/08/05/explaining-world-of-warcraft-auction-snapshots.html&quot;&gt;Explaining World of Warcraft Auction Snapshots&lt;/a&gt;
post. Sadly I didn’t get nearly as much data as I wanted, so I’m starting the
whole process over again in the hopes of getting a more consistent “chunk” of
data. In the meantime I thought I would explain a few interesting things I’ve noticed about the snapshot data I did get, and explain why my collection method failed.&lt;/p&gt;

&lt;h3 id=&quot;mistakes-were-made&quot;&gt;Mistakes Were Made&lt;/h3&gt;
&lt;p&gt;One of the early mistakes was my auction downloader script never accounted the
&lt;a href=&quot;https://github.com/GoblinLedger/wowapi/&quot;&gt;wowapi&lt;/a&gt; library failing to get the auction data. When I was working on the library,
I noticed that occasionally a request for an auction file would fail. To counteract
that, the library attempts to download the file multiple times. If it still
fails, it throws an exception. I, embarrassingly, didn’t account for my own exception
so after three days my script crashed. I didn’t notice till five days later, cutting
my available data in half.&lt;/p&gt;

&lt;p&gt;My second mistake was not putting my download script under revision control.
Apparently between starting my script the first time and the crash of 8/6,
I made a change the altered the output I was saving. Once I restarted the script,
it started saving snapshots with the new, different format. This made my parsing
annoying as I had to detect what output the snapshot file was before I was able
to parse it for metadata.&lt;/p&gt;

&lt;p&gt;Finally, when I started parsing for metadata I didn’t account for anything but
&lt;code&gt;item&lt;/code&gt; id number when it came to per item metadata. This lead to my output showing &lt;a href=&quot;http://www.wowhead.com/item=82800/pet-cage&quot;&gt;Pet Cage&lt;/a&gt; as the most common item for almost
every snapshot. While that was true, it missed out on some subtly in the data
that I plan to fix for next time&lt;/p&gt;

&lt;h3 id=&quot;some-data&quot;&gt;Some Data&lt;/h3&gt;
&lt;p&gt;Even with my script checking every five minutes for a new snapshot, it appeared
like snapshots jumped from 11pm to 1am with no snapshot for the 12am hour.
Maybe this is a artifact of my downloader script, but it might be that that they
snapshot generator script on Blizzard’s side resets at midnight. This wasn’t consistent
and only seemed to happen if a snapshot was supposed to be generated near midnight.&lt;/p&gt;

&lt;p&gt;Of course, I had to at least graph something. Here is a graph of the total
auction buyout value over a week. For each snapshot I simply summed the &lt;code&gt;buyout&lt;/code&gt;
values. You can see an interesting spike of data from the 14th through the 15th.
Kind of expected since this was a Friday and Saturday. I would have expected
Sunday to be up there as well. Something to look for once I get a at least
two weeks worth of data.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://files.billyoverton.com/WoWAuctionData/Charts/madoran_totalbuyout_20150811-20150817.png&quot;&gt;&lt;img src=&quot;http://files.billyoverton.com/WoWAuctionData/Charts/madoran_totalbuyout_20150811-20150817_thumb.png&quot; alt=&quot;Madoran Auction Buyout Over Time&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 18 Aug 2015 00:00:00 -0400</pubDate>
        <link>https://billyoverton.com/2015/08/18/world-of-warcraft-analysis-fail.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2015/08/18/world-of-warcraft-analysis-fail.html</guid>
        
        
      </item>
    
      <item>
        <title>Explaining World of Warcraft Auction Snapshots</title>
        <description>&lt;p&gt;In preparation to do some simple analysis on World of Warcraft auction house data,
I thought I would take the time to explain some of the data that Blizzard provides
through their &lt;a href=&quot;https://dev.battle.net&quot;&gt;Battle.Net Community API&lt;/a&gt;…with a touch of
self-promotion by using the &lt;a href=&quot;https://github.com/GoblinLedger/wowapi/&quot;&gt;wowapi python library&lt;/a&gt;
to pull the data in my examples. To use this library, you need an API key from the
Battle.net dev site.&lt;/p&gt;

&lt;p&gt;On a semi-regular hourly basis, Blizzard publishes snapshots of the current state
of each realm’s auction houses. This contains a list of active auctions, pricing
information, items being sold, etc.&lt;/p&gt;

&lt;h3 id=&quot;connected-realms&quot;&gt;Connected Realms&lt;/h3&gt;
&lt;p&gt;When you retrieve data from an auction house, it can contain data for several
realms. In 2013, Blizzard started connecting lower population realms together
in order to support more active communities. These connected realms share a
common auction house, so retrieving a snapshot for one realm will return data for
all realms in that set.&lt;/p&gt;

&lt;p&gt;Which realms are connected can be seen in the realm status API result. The status
contains a lot of information about a realm such as PvP zone status, server
timezone, and population size. For auction houses the main parameters are
&lt;code&gt;slug&lt;/code&gt; which represents a short name for a realm and is useful for other api
calls and &lt;code&gt;connected_realms&lt;/code&gt; which contains the slug for all realms connected
to the one represented by the JSON object. It also contains the slug for that realm.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wowapi&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;api&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wowapi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;BattleNetAPIKey&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;realm_status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;realm_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;auction_houses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;realm&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;realm_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;realms&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# I&#39;m unsure what the internal-record objects are, but they are not valid&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# realms so they can be filtered out of the lists&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;auction_house&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;internal-record&quot;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;realm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;connected_realms&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;auction_house&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sort&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;auction_house&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auction_houses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;auction_houses&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auction_house&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Number of unique auction houses: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auction_houses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auction_house&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auction_houses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auction_house&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;This prints out a grand total of unique Auction Houses and a comma delimited list of
the realms that make up each house.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Number of unique auction houses: 120
aegwynn, bonechewer, daggerspine, gurubashi, hakkar
aerie-peak
agamaggan, archimonde, burning-legion, jaedenar, the-underbog
aggramar, fizzcrank
...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;pulling-a-snapshot&quot;&gt;Pulling a Snapshot&lt;/h3&gt;
&lt;p&gt;Snapshots are published to the API in two parts: an Auction House Status and the
auction house data file (a link to which is provided in the status). For example
&lt;code&gt;api.auction_status(&quot;madoran&quot;)&lt;/code&gt; returns the following status for the Madoran
realm (madoran is the &lt;code&gt;slug&lt;/code&gt; for that realm):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span class=&quot;err&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;s2&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;http://us.battle.net/auction-data/52f853e2b29decd29e027d3a17fe1fba/auctions.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;lastModified&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1438741937000&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;While this data structure can support multiple files, I have yet to see an auction
status that contains more than one file. Each snapshot is comprised of a url
where the actual data can be downloaded from and a &lt;code&gt;lastModified&lt;/code&gt; timestamp field
that contains the milliseconds since &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_time&quot;&gt;Epoch&lt;/a&gt;.
There is a helper function in &lt;code&gt;wowapi.utility&lt;/code&gt; for downloading the additional file
that takes in an auction status and returns a combined data structure with the
auction status and an appended field &lt;code&gt;data&lt;/code&gt; that holds the contents of the files
in &lt;code&gt;url&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;json&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wowapi&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;wowapi.utility&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;retrieve_auctions&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;api&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wowapi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&#39;BattleNetAPIKey&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;auction_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;retrieve_auctions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auction_status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;madoran&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auction_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;separators&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;s&quot;&gt;&#39;,&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&#39;: &#39;&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;Which prints the following (the contents of &lt;code&gt;auctions&lt;/code&gt; is explained in more
detail in the &lt;a href=&quot;#auctions&quot;&gt;following section&lt;/a&gt;):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span class=&quot;err&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;s2&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;http://us.battle.net/auction-data/52f853e2b29decd29e027d3a17fe1fba/auctions.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;lastModified&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1438741937000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;data&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;s2&quot;&gt;&quot;realm&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;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Madoran&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;slug&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;madoran&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;auctions&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;auctions&quot;&lt;/span&gt;&lt;span class=&quot;err&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;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;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;auctions&quot;&gt;Auctions&lt;/h3&gt;
&lt;p&gt;Inside of a snapshot, the &lt;code&gt;auctions&lt;/code&gt; field contains a list of individual auctions
with a lot of data. Here is an example of one auction:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;rand&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;auc&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;841736577&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;timeLeft&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;VERY_LONG&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;bid&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;item&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;109137&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;seed&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;ownerRealm&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Dawnbringer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;context&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;owner&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;CharacterName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;buyout&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;600000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;quantity&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&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;Auctions have a unique identifying number in the &lt;code&gt;auc&lt;/code&gt; field. No information that
I can find guarantees this is unique across Auction Houses or even within a single
Auction House over time, but it does appear to be unique within a snapshot
and for a single auction throughout its lifetime (if it appears in more than one
snapshot).&lt;/p&gt;

&lt;p&gt;The owner of the auction is identified by the &lt;code&gt;owner&lt;/code&gt; and the &lt;code&gt;ownerRealm&lt;/code&gt; fields.
Because users in a connected realm set can share a username if they are on different
realms, both fields are required to uniquely identify an auction owner.&lt;/p&gt;

&lt;p&gt;The item(s) being sold in an auction is identified by the &lt;code&gt;item&lt;/code&gt;, &lt;code&gt;quantity&lt;/code&gt;,
&lt;code&gt;context&lt;/code&gt;, &lt;code&gt;rand&lt;/code&gt;, and &lt;code&gt;seed&lt;/code&gt; fields. The &lt;code&gt;item&lt;/code&gt; field is the item id.
Information about the actual item can be retrieved through another API call with
&lt;code&gt;api.item(itemID)&lt;/code&gt;. The &lt;code&gt;context&lt;/code&gt; provides information about the loot context for a
item (what kind of dungeon it was looted from at what level) and was newly added
in the &lt;a href=&quot;http://us.battle.net/en/forum/topic/14927203367&quot;&gt;6.0.2 Update&lt;/a&gt; to the API.
The &lt;code&gt;rand&lt;/code&gt; field relates to the random enchantment that is applied to the item
being sold . You can see a list of what the numbers mean on
&lt;a href=&quot;http://wow.gamepedia.com/ItemRandomSuffix&quot;&gt;gamepedia&lt;/a&gt;. The &lt;code&gt;quantity&lt;/code&gt; describes the number of
items being sold in this auction.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;seed&lt;/code&gt; field is a tricky one because I’m not sure what it means. Looking
around it seems to match the uniqueID from the in-game API’s item string. Some
explanation on that can be found &lt;a href=&quot;http://wow.gamepedia.com/ItemString#Unique_Ids&quot;&gt;here&lt;/a&gt;.
As far as I can tell it contains no useful information without access to internal
Blizzard tools.&lt;/p&gt;

&lt;p&gt;The “timeLeft” field appears to be intentionally vague. This can take one of four
different string values indicating how long the auction will remain on the auction
house before it expires:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;SHORT&lt;/strong&gt; - &amp;lt; 30 minutes left&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MEDIUM&lt;/strong&gt; - 30 minutes - 2 hours&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;LONG&lt;/strong&gt; - 2 hours - 12 hours&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;VERY_LONG&lt;/strong&gt; - 12 hours - 24 hours&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The money related fields for an auction are &lt;code&gt;bid&lt;/code&gt; and &lt;code&gt;buyout&lt;/code&gt;. The numbers are
given in copper (100 copper in 1 silver, 100 silver in 1 gold, 100 gold in the
platinum I wish they would implement). When a user creates an auction they define
a starting bid value and an optional buyout. If an auction has a buyout users can
bypass the bid process and simply pay the buyout price. If the user doesn’t set
a buyout price, the returned auction data has a buyout of 0.&lt;/p&gt;

&lt;h3 id=&quot;references--further-reading&quot;&gt;References / Further Reading&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://wowwiki.wikia.com/Auctions&quot;&gt;Auction Houses - wowwiki&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wow.gamepedia.com/Connected_Realms&quot;&gt;Connected Realms - wowpedia&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wow.gamepedia.com/ItemString&quot;&gt;ItemString - Gamepedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 05 Aug 2015 00:00:00 -0400</pubDate>
        <link>https://billyoverton.com/2015/08/05/explaining-world-of-warcraft-auction-snapshots.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2015/08/05/explaining-world-of-warcraft-auction-snapshots.html</guid>
        
        
      </item>
    
      <item>
        <title>Setting up Jekyll, Gulp, and Automated Git Deployments</title>
        <description>&lt;p&gt;I have been using Jekyll for a while for my personal site and long-abandoned blog,
but with the latest redesign I decided to play with a more automated workflow for
dependency management, development, and deployments. With a little luck that means
more frequent postings, since I don’t have to go through the hassle of manually
building and deploying my content.&lt;/p&gt;

&lt;p&gt;So far I’ve settled on using a mixture of &lt;a href=&quot;http://gulpjs.com/&quot;&gt;Gulp&lt;/a&gt;,
&lt;a href=&quot;http://bower.io/&quot;&gt;Bower&lt;/a&gt;, and &lt;a href=&quot;http://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; for building
the site and Git for deployment to my server. It’s still a work in progress
that is being tweaked, but it’s finally settling down to where I felt comfortable
writing about it.&lt;/p&gt;

&lt;h3 id=&quot;installing-global-dependencies&quot;&gt;Installing Global Dependencies&lt;/h3&gt;
&lt;p&gt;For my current setup there are a few global dependencies that need to be installed:
node, gulp, bower, compass, and jekyll. After installing node (following the
instructions from their site), the following commands install bower and gulp.&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;npm install -g bower
npm install -g gulp&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I already had a ruby install through homebrew, so installing Jekyll and Compass
is just as easy as &lt;code&gt;gem install jekyll&lt;/code&gt; and &lt;code&gt;gem install compass&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;creating-the-folder-structure&quot;&gt;Creating the Folder Structure&lt;/h3&gt;
&lt;p&gt;Once all of the global dependencies are installed, I created the initial folder
structure using Jekyll’s new command &lt;code&gt;jekyll new personalsite&lt;/code&gt;. This creates
a new folder called &lt;code&gt;personalsite&lt;/code&gt; with the basic folder structure
required by Jekyll. This is where I stopped before, using the normal &lt;code&gt;jekyll build&lt;/code&gt;
and &lt;code&gt;jekyll serve&lt;/code&gt; commands to build and post my site.&lt;/p&gt;

&lt;p&gt;For the new workflow, I made a few changes to the default folder structure. First
I removed the &lt;code&gt;css&lt;/code&gt; folder Jekyll made. Instead I created an &lt;code&gt;assets&lt;/code&gt; folder
with two sub folders: &lt;code&gt;css&lt;/code&gt; and &lt;code&gt;fonts&lt;/code&gt;. These folders are going to be generated
by gulp and bower, so I also added the whole assets folder to my .gitignore file.
That’s the only real change to the default folder structure.&lt;/p&gt;

&lt;h3 id=&quot;setting-up-bower&quot;&gt;Setting up Bower&lt;/h3&gt;
&lt;p&gt;For right now my only two bower requirements for my site are fontawesome and
normalize.scss. I added those dependencies by creating a &lt;code&gt;bower.json&lt;/code&gt; file at
the root of &lt;code&gt;personalsite&lt;/code&gt; with the following contents.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&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;nt&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;personalsite&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;nt&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;authors&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;s2&quot;&gt;&quot;Billy Overton &amp;lt;overton.billy@gmail.com&amp;gt;&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;nt&quot;&gt;&quot;homepage&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;http://billyoverton.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;nt&quot;&gt;&quot;ignore&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;s2&quot;&gt;&quot;**/.*&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;node_modules&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;bower_components&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;test&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;tests&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;nt&quot;&gt;&quot;dependencies&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;nt&quot;&gt;&quot;fontawesome&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;~4.3.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;normalize.scss&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;~3.0.2&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Other than some boilerplate, the main part is the list of dependencies which gives
the name and the version. These dependencies can be installed by running
&lt;code&gt;bower install&lt;/code&gt; at the root of the site. This will create a &lt;code&gt;bower_components&lt;/code&gt;
folder which contains the files for each of the dependencies.&lt;/p&gt;

&lt;h3 id=&quot;setting-up-nodenpm&quot;&gt;Setting up Node/NPM&lt;/h3&gt;
&lt;p&gt;To manage the Node dependencies, I created a &lt;code&gt;package.json&lt;/code&gt; file. This mostly has
the dependencies for gulp to manipulate css and integrate with browserSync
and compass.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&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;nt&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;BillyOvertonBlog&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;nt&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;description&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;Personal Blog&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;nt&quot;&gt;&quot;main&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;gulpfile.js&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;nt&quot;&gt;&quot;author&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;Billy Overton&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;nt&quot;&gt;&quot;devDependencies&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;nt&quot;&gt;&quot;browser-sync&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;^2.7.12&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;nt&quot;&gt;&quot;gulp&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;^3.9.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;gulp-bower&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;0.0.10&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;nt&quot;&gt;&quot;gulp-compass&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;^2.1.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;gulp-minify-css&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;^1.2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;gulp-notify&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;^2.2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;gulp-ruby-sass&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;^1.0.5&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This sets up everything so gulp can compile sass files, minify them, and place them
in the &lt;code&gt;assets&lt;/code&gt; folder so Jekyll can pick it up during the build. The dependencies
can be installed with &lt;code&gt;npm install&lt;/code&gt; from the root of the site folder.&lt;/p&gt;

&lt;h3 id=&quot;setting-up-gulp&quot;&gt;Setting up Gulp&lt;/h3&gt;
&lt;p&gt;The most complicated part of this setup is the &lt;code&gt;gulp.js&lt;/code&gt; file. The full file for
this can be found &lt;a href=&quot;https://gist.github.com/billyoverton/13eb7d8e27339de8dc25&quot;&gt;here&lt;/a&gt;.
Below is a breakdown of the parts.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&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;s1&quot;&gt;&#39;gulp&#39;&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;cp&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;s1&quot;&gt;&#39;child_process&#39;&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;minifyCss&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;s1&quot;&gt;&#39;gulp-minify-css&#39;&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;notify&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;s2&quot;&gt;&quot;gulp-notify&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sass&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;s1&quot;&gt;&#39;gulp-ruby-sass&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;err&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;bower&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;s1&quot;&gt;&#39;gulp-bower&#39;&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;browserSync&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;s1&quot;&gt;&#39;browser-sync&#39;&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;The first part imports the requirements we installed with our &lt;code&gt;package.json&lt;/code&gt; file.
The only one not from the requirements file is &lt;code&gt;child_process&lt;/code&gt; which is used later
for running the Jekyll build commands.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&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;err&quot;&gt; &lt;/span&gt;    &lt;span class=&quot;na&quot;&gt;sassPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;./_sass&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;    &lt;span class=&quot;na&quot;&gt;bowerDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;./bower_components&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;assetDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;./assets&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;outputDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;./_site&#39;&lt;/span&gt;&lt;span class=&quot;err&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;messages&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;na&quot;&gt;jekyllBuild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;&amp;lt;span style=&quot;color: grey&quot;&amp;gt;Running:&amp;lt;/span&amp;gt; $ jekyll build&#39;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;bower&#39;&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;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bowerDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;err&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;This sets up some paths used in the later tasks, plus a message to indicate
when a Jekyll build is running (for browserSync). The &lt;code&gt;outputDirectory&lt;/code&gt; matches
the build directory for Jekyll. It’s used so instead of having to trigger a
build every time a file changes (like a css file), I can directly place the css
into the output directory and stream the changes through browserSync.&lt;/p&gt;

&lt;p&gt;The bower task configures the gulp-bower plugin by passing it the config.bowerDir.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;icons&#39;&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;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bowerDir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;/fontawesome/fonts/**.*&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assetDir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;/fonts&#39;&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;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;outputDir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;/assets/fonts&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;span class=&quot;err&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;This is the gulp task for moving the fontawesome font files from the bower directory
to both the asset directory (so jekyll will pick it up during a build) and to
the output directory’s assets folder. I don’t really use the second part, but
it matched what I was doing with the css task so I left it in.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;css&#39;&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;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sassPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;/main.scss&#39;&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;err&quot;&gt; &lt;/span&gt;            &lt;span class=&quot;na&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;compressed&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;            &lt;span class=&quot;na&quot;&gt;loadPath&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;err&quot;&gt; &lt;/span&gt;                &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sassPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bowerDir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;/normalize.scss/&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bowerDir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;/fontawesome/scss&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;compass&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;err&quot;&gt; &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;minifyCss&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;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assetDir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;/css&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;outputDir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;/assets/css&#39;&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;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;browserSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;&lt;span class=&quot;err&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;The css task compiles the main scss file from which I import all other files,
adds the paths for the bower scss files, minifies it, outputs it to the build assets
directory and the final assets directory, then triggers a browserSync stream
to cause a reload.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;jekyll-build&#39;&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;s1&quot;&gt;&#39;css&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;icons&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;bower&#39;&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;done&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;browserSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;notify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jekyllBuild&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;nx&quot;&gt;cp&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;s1&quot;&gt;&#39;jekyll&#39;&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;s1&quot;&gt;&#39;build&#39;&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;stdio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;inherit&#39;&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;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;close&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;done&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;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;jekyll-rebuild&#39;&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;s1&quot;&gt;&#39;jekyll-build&#39;&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;browserSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reload&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;These two tasks handle the integration between gulp and Jekyll. The &lt;code&gt;jekyll-build&lt;/code&gt;
command has dependencies on the &lt;code&gt;css&lt;/code&gt;, &lt;code&gt;icons&lt;/code&gt;, and &lt;code&gt;bower&lt;/code&gt; tasks so those are
completed beforehand. The first part sends a notification that there is a build
occurring to browserSync. The second runs the &lt;code&gt;jekyll build&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jekyll-rebuild&lt;/code&gt; is the actual rebuild command for development, it depends on
&lt;code&gt;jekyll-build&lt;/code&gt; and runs a browserSync reload when the build is complete.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;build&#39;&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;s1&quot;&gt;&#39;bower&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;icons&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;css&#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;jekyll-build&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;serve&#39;&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;s1&quot;&gt;&#39;build&#39;&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;browserSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;server&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;baseDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./_site&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;// Start a watch for rebuilds&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;_sass/*.scss&#39;&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;s1&quot;&gt;&#39;css&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;index.html&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;_layouts/*.html&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;_includes/*&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;_posts/*&#39;&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;s1&quot;&gt;&#39;jekyll-rebuild&#39;&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;gulp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;default&#39;&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;s1&quot;&gt;&#39;serve&#39;&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;The rest of the file defines the entry points into the system. The &lt;code&gt;build&lt;/code&gt; task
runs the other tasks to create an initial build. This is the task I use during the
deployment step on my server.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;serve&lt;/code&gt; task is what I use during development. In addition to running an initial
build, it starts browserSync against the output directory and sets up watch commands
on the files so browserSync can keep the browser up to date with any changes. Changes
to the scss files triggers the &lt;code&gt;css&lt;/code&gt; task which streams changes to browserSync. Changes
to html files or post files trigger a full &lt;code&gt;jekyll-rebuild&lt;/code&gt;, which will run a new
build and reload the browser.&lt;/p&gt;

&lt;h3 id=&quot;configure-jekyll&quot;&gt;Configure Jekyll&lt;/h3&gt;
&lt;p&gt;Because of how Jekyll processes files, the gulp, bower, and npm files will end
up being sent to the output directory &lt;code&gt;_site&lt;/code&gt;. To avoid this, I added the following
to my &lt;code&gt;_config.yml&lt;/code&gt; file&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;s&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gulpfile.js&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;package.json&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;node_modules&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bower.json&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bower_components&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;using-for-development-and-writing&quot;&gt;Using for Development and Writing&lt;/h3&gt;
&lt;p&gt;Once all that is setup, developing or writing for my site can be handled by running
&lt;code&gt;gulp serve&lt;/code&gt;. This compiles the scss files, builds the jekyll site,
and loads the output in a browser window with browserSync.&lt;/p&gt;

&lt;p&gt;If it is a fresh checkout, the &lt;code&gt;gulp serve&lt;/code&gt; command needs to be preceded by&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;npm install
bower install
gulp serve&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;adding-the-site-to-git&quot;&gt;Adding the Site to Git&lt;/h3&gt;
&lt;p&gt;For my automated deployment, I went with a git work flow. The first thing I did
was put the site code under revision control by running &lt;code&gt;git init&lt;/code&gt; from the root
of the &lt;code&gt;personalsite&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Before adding and committing the first set of files, I made sure my &lt;code&gt;.gitignore&lt;/code&gt;
file ignores everything that is either auto-generated or doesn’t need to be added
for the build processes.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;_site
.sass-cache
node_modules
assets
bower_components
.DS_Store&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then I commited the files with a normal git workflow.&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;git add &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
git add .gitignore
git commit -m &lt;span class=&quot;s2&quot;&gt;&quot;Initial Import&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;configuring-the-server&quot;&gt;Configuring the Server&lt;/h3&gt;
&lt;p&gt;So far all this is local to my workstation. On my remote server I initiated a bare
git repository to act as the “deploy” base.&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;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~
mkdir personalsite.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;personalsite.git
git init --bare&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To support automated building and deploying, I also installed all of the global
dependencies I installed on the local machine.&lt;/p&gt;

&lt;p&gt;Finally I added a post-receive git hook by creating the file &lt;code&gt;~/personalsite.git/hooks/post-receive&lt;/code&gt; and setting it as executable &lt;code&gt;chmod +x ~/personalsite.git/hooks/post-receive&lt;/code&gt; This
file will be executed every time there is a push to this repository. In my case,
I use this script to create a temporary checkout, build the site, and then move it
to the directory being served by my web server.&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;&lt;span class=&quot;nv&quot;&gt;GIT_REPO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;/personal-site.git
&lt;span class=&quot;nv&quot;&gt;TMP_GIT_CLONE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/billyoverton_blog
&lt;span class=&quot;nv&quot;&gt;PUBLIC_WWW&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/var/www/billyoverton.com/

&lt;span class=&quot;c&quot;&gt;# Create a temporary checkout&lt;/span&gt;
git clone &lt;span class=&quot;nv&quot;&gt;$GIT_REPO&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$TMP_GIT_CLONE&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$TMP_GIT_CLONE&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Build the site and rsync it to the public html folder&lt;/span&gt;
npm install
bower install
gulp build
rsync -a --delete _site/ &lt;span class=&quot;nv&quot;&gt;$PUBLIC_WWW&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Remove the temporary checkout&lt;/span&gt;
rm -Rf &lt;span class=&quot;nv&quot;&gt;$TMP_GIT_CLONE&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;configuring-git-deployments&quot;&gt;Configuring Git Deployments&lt;/h3&gt;
&lt;p&gt;Back on my local machine, I added the repo on my server as a remote named &lt;code&gt;deploy&lt;/code&gt;.
I’m using ssh to add the remote, so there is no need for any additional server
configuration beyond normal remote access (and installing git)&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;git remote add deploy username@remotehost.com:~/personal-site.git&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With that done, the only thing required to deploy my site is to push my changes
to the remote server with &lt;code&gt;git push deploy master&lt;/code&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 27 Jul 2015 00:00:00 -0400</pubDate>
        <link>https://billyoverton.com/2015/07/27/jekyll-gulp-and-automated-deployments.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2015/07/27/jekyll-gulp-and-automated-deployments.html</guid>
        
        
      </item>
    
      <item>
        <title>Automating Backup Downloads With WinSCP</title>
        <description>&lt;h3 id=&quot;on-the-server&quot;&gt;On the Server&lt;/h3&gt;
&lt;p&gt;The first thing I did was create a user that handles nothing else but the copying of backups. While I could have used an account that already exists, I decided to create an account that I could restrict as much as possible.&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;addusers -s /usr/sbin/nologin backup_user&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code&gt;-s /usr/sbin/nologin&lt;/code&gt; option changes the default shell so that this user does not have shell access and creates a little extra security. Since it was not already there on my Debian install, I added &lt;code&gt;/usr/sbin/nologin&lt;/code&gt; to the &lt;code&gt;/etc/shells&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;For my purposes, the backup_user was only used for copying backups from my server to my Windows desktop. As such, I decided to limit it to only using ssh for sftp. To do this, I added the following lines to the &lt;code&gt;\etc\ssh\sshd_config&lt;/code&gt; file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Subsystem sftp internal-sftp
Match user backup_user
    ChrootDirectory %h
    X11Forwarding no
    AllowTcpFowarding no
    ForceCommand internal-sftp
Match&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I also commented out all other lines that referenced Subsystem sftp.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ChrootDirectory %h&lt;/code&gt; option locks the user to their home directory. Because of the way SSH’s chroot works, the directory it uses must by wholly owned by root, and can only be writable by root. The command below takes care of that for my backup_user’s home directory.&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;chown root:root /home/backup_user&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;on-the-clientdesktop&quot;&gt;On the Client/Desktop&lt;/h3&gt;

&lt;p&gt;First I created a SSH key without a password for the backup_user. This makes it so I can run this automatically in the background without user intervention. This key without a password is the main reason I placed so many limitations on the backup_user’s account and ssh access.&lt;/p&gt;

&lt;p&gt;I also created a &lt;a href=&quot;http://winscp.net/eng/docs/scripting&quot;&gt;WinSCP script&lt;/a&gt; for transferring backups from the server that used the above ssh key. I saved it as &lt;code&gt;C:\backup.txt&lt;/code&gt; to make the command line entry easier.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;option batch abort
option confirm off
option echo off
open sftp://backup_user@example.com -privatekey=&quot;C:\backup_key.ppk&quot;
synchronize local -criteria=none &quot;&quot;
exit&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The script can be ran with WinScp with the command-line parameter &lt;code&gt;/script=&quot;C:\backup.txt&quot;&lt;/code&gt; to automatically copy documents from the remote directory to the local one. I created a Scheduled Task to run the above once a week.&lt;/p&gt;
</description>
        <pubDate>Wed, 02 Oct 2013 00:00:00 -0400</pubDate>
        <link>https://billyoverton.com/2013/10/02/automating-backup-downloads-with-winscp.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2013/10/02/automating-backup-downloads-with-winscp.html</guid>
        
        
      </item>
    
      <item>
        <title>Windows PowerShell and SmartAVI CATSwitch</title>
        <description>&lt;p&gt;I was working on some room automation stuff last year when I found myself in need of a command line tool to control a &lt;a href=&quot;http://www.smartavi.com/categories/video-switches/cat5-switches/catswitch.htm&quot;&gt;SmartAVI CATSwitch&lt;/a&gt; video switcher. Thankfully they posted the details for their RS-232 protocol at the end of their manual, so I was able to throw together a quick and dirty script for connecting inputs and outputs on the switch. I thought it would be interesting to share what I put together, since it might help someone else.&lt;/p&gt;

&lt;p&gt;I was playing around with PowerShell at the time, so that is what the script is written in. It takes two strings as inputs corresponding to the physical ports on the video switcher. For the model I was working with valid inputs were “01” – “16” for both the input and the output string.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1]
&lt;span class=&quot;nv&quot;&gt;$input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;0]

&lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;//F00M&#39;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt; +&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$output&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt; +&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;I&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt; +&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$input&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$errorCode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0
&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$character&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt;.ToCharArray&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$errorCode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$errorCode&lt;/span&gt; -bxor &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&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;nv&quot;&gt;$character&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt; +&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$errorCode&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$command&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;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;

&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$port&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;= new-Object System.IO.Ports.SerialPort COM1,9600,None,8,one
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$port&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.open()
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$port&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.Write(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$port&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.close()
exit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
        <pubDate>Mon, 21 May 2012 00:00:00 -0400</pubDate>
        <link>https://billyoverton.com/2012/05/21/windows-powershell-and-smartavi-catswitch.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2012/05/21/windows-powershell-and-smartavi-catswitch.html</guid>
        
        
      </item>
    
      <item>
        <title>Graphical Sequences with Python</title>
        <description>&lt;p&gt;I got bored, so I quickly put together a function in python to determine if a given degree sequence is graphical. It uses the Erdős–Gallai theorem to do the checking. I know it isn’t the most difficult function in the world to write, but I find it useful.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isGraphicalSequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# sort the list in reverse order&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# Ensures it is a non-negative sequence&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;      
  &lt;span class=&quot;c&quot;&gt;# Check to ensure there are an even number of odd degrees&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;      
  &lt;span class=&quot;c&quot;&gt;# Erdos-Gallai theorem&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sumOfDegree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)])&lt;/span&gt;          
    &lt;span class=&quot;n&quot;&gt;partialSum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;partialSum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partialSum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sumOfDegree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partialSum&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;bp&quot;&gt;False&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Update: 2012-01-23&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After actually going to class, I did another implementation that uses the Havel-Hakimi algorithm instead. Both work, but I thought I would share this one too. Plus this one is recursive, and who doesn’t love recursion?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isGraphicalSequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&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;sequence&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&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;bp&quot;&gt;True&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&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;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&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;bp&quot;&gt;False&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&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;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isGraphicalSequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
</description>
        <pubDate>Sun, 22 Jan 2012 00:00:00 -0500</pubDate>
        <link>https://billyoverton.com/2012/01/22/graphical-sequences-with-python.html</link>
        <guid isPermaLink="true">https://billyoverton.com/2012/01/22/graphical-sequences-with-python.html</guid>
        
        
      </item>
    
  </channel>
</rss>
