<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>The blog of Vaughan Hilts</title>
 <link href="http://vaughanhilts.me/atom.xml" rel="self"/>
 <link href="http://vaughanhilts.me"/>
 <updated>2023-09-22T03:49:19+00:00</updated>
 <id>http://vaughanhilts.me</id>
 <author>
   <name>Vaughan Hilts</name>
   <email></email>
 </author>

 
 <entry>
   <title>Installing and running HorizonXI on Linux</title>
   <link href="http://vaughanhilts.me/2022/06/19/installing-horizon-xi-linux.html"/>
   <updated>2022-06-19T21:17:00+00:00</updated>
   <id>http://vaughanhilts.me/2022/06/19/installing-horizon-xi-linux</id>
   <content type="html">&lt;p&gt;The following is for installing &lt;a href=&quot;https://horizonxi.com/&quot;&gt;HorizonXI&lt;/a&gt;, a FFXI private server on Linux. Specifically, I am installing with the following Arch Linux System:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:wine/x86_64-windows $ neofetch
                   -`                    touma@setsuna 
                  .o+`                   ------------- 
                 `ooo/                   OS: Arch Linux x86_64 
                `+oooo:                  Model: B450 AORUS PRO WIFI 
               `+oooooo:                 Kernel: 5.12.9-arch1-1 
               -+oooooo+:                Uptime: 6 days, 19 hours, 29 mins 
             `/:-:++oooo+:               Packages: 1672 (pacman) 
            `/++++/+++++++:              Shell: zsh 5.8 
           `/++++++++++++++:             Resolution: 2560x1440 
          `/+++ooooooooooooo/`           DE: GNOME 40.2 
         ./ooosssso++osssssso+`          WM: Mutter 
        .oossssso-````/ossssss+`         WM Theme: EvoPop-Azure 
       -osssssso.      :ssssssso.        Theme: Materia-light-compact [GTK2/3] 
      :osssssss/        osssso+++.       Icons: Numix [GTK2/3] 
     /ossssssss/        +ssssooo/-       Terminal: gnome-terminal 
   `/ossssso+/:-        -:/+osssso+-     CPU: AMD Ryzen 7 3800X (16) @ 3.900GHz 
  `+sso+:-`                 `.-/+oso:    GPU: NVIDIA GeForce GTX 1080 
 `++:.                           `-/+/   Memory: 5913MiB / 32116MiB 
 .`                                 `/
                                                                 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;install-horizonxi---wine-staging-non-steam-deck-steam-deck-below&quot;&gt;Install HorizonXI - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine-staging&lt;/code&gt; (non steam-deck; steam deck below)&lt;/h2&gt;

&lt;h3 id=&quot;prepare-a-version-of-wine-with-the-proper-patches&quot;&gt;Prepare a version of Wine with the proper patches&lt;/h3&gt;

&lt;p&gt;**tldr; install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine-staging&lt;/code&gt; if you want something simple (such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yay wine-staging&lt;/code&gt;) and you’re good to go.&lt;/p&gt;

&lt;p&gt;You need a version of WINE that won’t crash when accepting the EULA, presumably like most XI installs. There are a couple options here.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;“Easy, recommended”&lt;/strong&gt;: Use a variant of WINE that has the patch integrated into it already, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine-staging&lt;/code&gt; (&lt;a href=&quot;https://github.com/wine-staging/wine-staging/blob/534f6ae34e89615fa424ee3e3002b1b3d419a8ba/patches/patchinstall.sh#L4979&quot;&gt;here&lt;/a&gt;). If you are on Arch Linux, you can do this using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman -S wine-staging&lt;/code&gt; (or any other helper you use). You can find &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine-staging&lt;/code&gt; in some other repos as well, such as the Ubuntu ones. You can find more on the &lt;a href=&quot;https://wiki.winehq.org/Download&quot;&gt;WINE install page&lt;/a&gt;. There are other versions that include that patch in their definition – any of them will do.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Easy, works in a pinch”&lt;/strong&gt;: You can download a patched &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;imm32.dll&lt;/code&gt; from the web such as &lt;a href=&quot;https://github.com/bluffnix/ffxi-wine/tree/master/linux&quot;&gt;https://github.com/bluffnix/ffxi-wine/tree/master/linux&lt;/a&gt; and replace your system library with it. You can find some directions on the web to do this – I would recommend you &lt;strong&gt;don’t do this&lt;/strong&gt; because every time you update the operating system and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine&lt;/code&gt; package it’s going to get replaced with a new binary. However, I wanted to write this here since it’s shown on the web a lot as a drag and drop solution from a lot of users.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Hard”&lt;/strong&gt;: You can compile a version of WINE that has the proper fix. The patch in question &lt;a href=&quot;https://gitlab.com/farmboy0/wine/-/commit/54aea128e91a6b03bff05e79d9a09bea572ce99a&quot;&gt;is this&lt;/a&gt;. If you are an advanced user, you can do this if you can’t replace your system wine. If you do this, make sure you compile WINE with 64 bit support since you will need it. If you need help with this, leave a comment but for most users this shouldn’t be needed and should only be done if you can’t use the other options.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the time of writing, this worked with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:tidus $ wine --version
wine-7.22 (Staging)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note: A lot of places on the Internet tell you to use a specific prefix architecture for Final Fantasy XI; this does not work for many private servers – so please follow the directions very closely. If in doubt, follow step by step and start with a fresh prefix.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prepare a new prefix for HorizonXI using the following command:&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;WINEPREFIX=~/.wine-horizonxi-64 winecfg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check that “Windows 7” is selected as the version.&lt;/p&gt;

&lt;p&gt;Moving along, let’s run the installer inside of WINE:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;WINEPREFIX=~/.wine-horizonxi-64 wine &quot;~/Downloads/HorizonXI-Launcher-1.0.1.Setup.exe&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/horizonxi/launcher_installing.png&quot; alt=&quot;image-20210619214000116&quot; /&gt;&lt;/p&gt;

&lt;p&gt;From this point, you can click “Install HorizonXI” and things will begin working:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;An install directory, you can leave that as a default but it defaults to your virtual “Users” drive. I left it there since there is no harm (virtualized drive).&lt;/li&gt;
  &lt;li&gt;You &lt;strong&gt;do not need to login&lt;/strong&gt; to install the game from what I can tell.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it as far as we know right now.&lt;/p&gt;

&lt;h2 id=&quot;install-horizonxi---linux-desktop-using-lutris-non-steam-deck-steam-deck-below&quot;&gt;Install HorizonXI - Linux Desktop using Lutris (non steam-deck; steam deck below)&lt;/h2&gt;

&lt;p&gt;Lutris is meant to be an all-in-one installer, however there are additional steps required at present to make it work. If you want a quick solution that will work use the process listed above. Otherwise follow the instructions below.
Once new Lutris runners are shipped with Lutris i’ll update the script and this guide. Should be early next year for a new runner.&lt;/p&gt;

&lt;h4 id=&quot;requirements&quot;&gt;Requirements&lt;/h4&gt;
&lt;p&gt;You need to have wine-staging installed.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;ProtonUp-Qt and runner “lutris-GE-Proton7-42-x86_64” installed for lutris.&lt;/p&gt;

    &lt;p&gt;Install ProtonUp-Qt on your distribution and open it up.&lt;/p&gt;
    &lt;ol&gt;
      &lt;li&gt;At the top make sure Lutris is selected.&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Then hit “Add Version”&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/assets/horizonxi/protonup-qt_01.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;Select “Wine-GE” for compatability tool.&lt;/li&gt;
      &lt;li&gt;Select “GE Proton 7-42” for version.&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Hit install and once it’s complete you’re done with ProtonUp-Qt.&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/assets/horizonxi/protonup-qt_02.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/sarca571ca/horizonxi-lutris/archive/refs/heads/master.zip&quot;&gt;HorizonXI Lutris Script&lt;/a&gt;
Downloads the script from &lt;a href=&quot;https://github.com/sarca571ca/horizonxi-lutris&quot;&gt;sarca571ca/horizonxi-lutris&lt;/a&gt; repo. Be sure to extract the YAML files inside the archive.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;installation&quot;&gt;Installation&lt;/h4&gt;
&lt;ol&gt;
  &lt;li&gt;Open Lutris and hit the (+)plus in the top left.&lt;/li&gt;
  &lt;li&gt;Select install from YAML file, select the &lt;strong&gt;Horizon-XI.yaml&lt;/strong&gt; file, and follow the steps in the installer.&lt;/li&gt;
  &lt;li&gt;Once completed hit &lt;strong&gt;Close&lt;/strong&gt; not Launch.&lt;/li&gt;
  &lt;li&gt;Now your free to launch HorizonXI you will get a launch prompt asking for either HorizonXI or the 4GB Patch. Select HorizonXI and install like normal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note: You might get an error about missing the prereqs.zip, this can be ignored as lutris installed all pre-reqs automatically for you.
If you experience the “black void” while changing areas you can lower your textures some in the HorizonXI Launcher. You can also use the 4GB patch i’ve included.&lt;/p&gt;

&lt;h4 id=&quot;4gb-patch&quot;&gt;4GB Patch&lt;/h4&gt;
&lt;p&gt;Check the FAQ section or click &lt;a href=&quot;#4gb-patch-1&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;windower-4&quot;&gt;Windower 4&lt;/h4&gt;
&lt;p&gt;If you want to install Windower follow the README.md provided in the archive you downloaded earlier. Unless otherwise requested by Vaughan I won’t clog this guide up with that install process.&lt;/p&gt;

&lt;h4 id=&quot;version&quot;&gt;Version&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Updated September 22, 2023
    &lt;ul&gt;
      &lt;li&gt;Added new requirement for ProtonUp-Qt&lt;/li&gt;
      &lt;li&gt;Updated install process for a smoother install.&lt;/li&gt;
      &lt;li&gt;Supports Horizon Launcher v1.2.1&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Initial guide December 22, 2022&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Guide by: Ex1L3(Asri) in the HorizonXI discord, feel free to ask question etc.&lt;/p&gt;

&lt;h2 id=&quot;install-horizonxi---steam-play-steam-deck--other-systems&quot;&gt;Install HorizonXI - Steam Play (Steam Deck / other systems)&lt;/h2&gt;

&lt;p&gt;There is an video that goes with this guide if you would prefer: https://www.youtube.com/watch?v=4pWbxU025Ak&lt;/p&gt;

&lt;p&gt;If you are new to Proton or Linux, it may be valuable.&lt;/p&gt;

&lt;p&gt;The following is for Steam Deck users:&lt;/p&gt;

&lt;h3 id=&quot;automatic-installation&quot;&gt;Automatic installation&lt;/h3&gt;

&lt;p&gt;Download &lt;a href=&quot;https://github.com/trentondyck/horizon_scripts&quot;&gt;Trent’s script&lt;/a&gt; and execute in konsole.&lt;/p&gt;

&lt;p&gt;Follow the prompts instructions, and report any bugs in the Steam Deck Thread tagging @trent with a snippet including the konsole logs.&lt;/p&gt;

&lt;p&gt;For those who click through without reading the basic idea is to install the base game with v1.0.1, then when that is fully completed rerun update-horizon.sh and it will update the installer for you to the latest.&lt;/p&gt;

&lt;h3 id=&quot;manual-installation&quot;&gt;Manual installation&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Boot your Steam Deck into “Desktop Mode”&lt;/li&gt;
  &lt;li&gt;Install ProtonQT from Discover (&lt;a href=&quot;https://davidotek.github.io/protonup-qt/&quot;&gt;link&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Open up “Firefox” and “Steam”&lt;/li&gt;
  &lt;li&gt;Download the installer from the website. It will end up in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/Downloads&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Open a terminal and do the following:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note: At the time of writing, the installer from the website may not work due to some breaking changes. You may need to install from https://github.com/HorizonFFXI/HorizonXI-Launcher-Binaries/releases/tag/v1.0.1 first, and then upgrade later. The install process seems broken on Linux on the newer launcher&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir ~/horizon-xi
cp &quot;/home/deck/Downloads/HorizonXI-Launcher-1.0.1.Setup.exe&quot; ~/horizon-xi/installer.exe
cd ~/horizon-xi
7z x installer.exe
7z x HorizonXI_Launcher-1.0.1-full.nupkg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;OK, that’s done.&lt;/p&gt;

&lt;p&gt;Now:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Launch ProtonQT-Up&lt;/li&gt;
  &lt;li&gt;Install “GE-Proton7-42”&lt;/li&gt;
  &lt;li&gt;Restart Steam / deck if you can’t restart Steam from desktop&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/horizonxi/proton.png&quot; alt=&quot;image-20210619214000116&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Now, open “Steam” and add a ‘Non-Steam Game’ and navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/horizon-xi/lib/net45/HorizonXI-Launcher.exe&lt;/code&gt; for the executable (you may have to change “.desktop” at the bottom to all application types)&lt;/li&gt;
  &lt;li&gt;Right click the new entry, hit Properties &amp;gt; Compatibility&lt;/li&gt;
  &lt;li&gt;Change to the new version of Proton GE you just installed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Launch the game!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/horizonxi/compat.png&quot; alt=&quot;image-20210619214000116&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Begin installing. You should pick C:\Program Files when prompted for an install path. You should not pick anything else. You can move &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compatdata&lt;/code&gt; to an SD card later if needed.&lt;/p&gt;

&lt;p&gt;The launcher has some bugs. Continue down to FAQ down below to find any problems you might have. You may want to read them all before clicking install.&lt;/p&gt;

&lt;p&gt;When install is &lt;em&gt;complete&lt;/em&gt; you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo find /home -name &quot;HorizonXI.zip&quot; -type f | sed 's/ /\\ /g' | xargs -i rm {}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… to clean up the ZIP to get some space back. You may want to save a copy if you want to install somewhere else in the future.&lt;/p&gt;

&lt;h3 id=&quot;gamepad&quot;&gt;Gamepad&lt;/h3&gt;

&lt;p&gt;The gamepad needs configuring to work. In game mode:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open the launcher open the Gamepad Configuration&lt;/li&gt;
  &lt;li&gt;Enable XInput&lt;/li&gt;
  &lt;li&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In desktop mode:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open Dolphin to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/home/deck/.local/share/Steam/steamapps/compatdata/&amp;lt;prefix_id&amp;gt;/pfx/drive_c/users/&amp;lt;user&amp;gt;/AppData/Roaming/HorizonXI-Launcher/&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protontricks&lt;/code&gt; can help find the ID)&lt;/li&gt;
  &lt;li&gt;Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.json&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Make the following edits to the config:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;padmode000&quot;: {
    &quot;name&quot;: &quot;Gamepad Settings Controls&quot;,
    &quot;key&quot;: &quot;padmode000&quot;,
    &quot;value&quot;: [
        1,
        1,
        0,
        0,
        1,
        1
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;padsin000&quot;: {
    &quot;name&quot;: &quot;Button Mappings&quot;,
    &quot;key&quot;: &quot;padsin000&quot;,
    &quot;value&quot;: [
        8,
        9,
        13,
        12,
        10,
        0,
        1,
        3,
        2,
        15,
        -1,
        -1,
        14,
        -33,
        -33,
        32,
        32,
        -36,
        -36,
        35,
        35,
        6,
        7,
        5,
        4,
        11,
        -1
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Gamepad should now work in game mode. Credit goes to Sabriel@ for the gamepad directions.&lt;/p&gt;

&lt;h2 id=&quot;faq-for-linux&quot;&gt;FAQ for Linux&lt;/h2&gt;

&lt;h3 id=&quot;the-launcher-keeps-crashing-while-trying-to-install-the-game&quot;&gt;The launcher keeps crashing while trying to install the game&lt;/h3&gt;

&lt;p&gt;… and it’s wiping all my progress!&lt;/p&gt;

&lt;p&gt;Mandatory warning from the HorizonXI staff:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Please note:&lt;/strong&gt; We will not offer support for users that bypass the launcher with this setup, it’s a work around for users having memory issues due to having less than 16gb ram on PC.**&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Still with me? OK, next.&lt;/p&gt;

&lt;p&gt;There is a memory leak in the launcher as of launch day. The launcher does not save progress. The staff are working on fixing it but in the meantime, you can follow the below steps to get it working:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;magnet:?xt=urn:btih:4eecae8431428820347314bc002492e210f29612&amp;amp;dn=HorizonXI.zip&amp;amp;tr=udp%3a%2f%2fopentracker.i2p.rocks%3a6969%2fannounce&amp;amp;tr=https%3a%2f%2ftracker.nanoha.org%3a443%2fannounce&amp;amp;tr=https%3a%2f%2ftracker.lilithraws.org%3a443%2fannounce&amp;amp;tr=udp%3a%2f%2ftracker.opentrackr.org%3a1337%2fannounce&amp;amp;tr=udp%3a%2f%2ftracker.openbittorrent.com%3a6969%2fannounce&amp;amp;tr=https%3a%2f%2fopentracker.i2p.rocks%3a443%2fannounce&amp;amp;tr=udp%3a%2f%2ftracker1.bt.moack.co.kr%3a80%2fannounce&amp;amp;tr=udp%3a%2f%2ftracker.torrent.eu.org%3a451%2fannounce&amp;amp;tr=udp%3a%2f%2ftracker.tiny-vps.com%3a6969%2fannounce&amp;amp;tr=udp%3a%2f%2fpublic.tracker.vraphim.com%3a6969%2fannounce&amp;amp;tr=udp%3a%2f%2fp4p.arenabg.com%3a1337%2fannounce&amp;amp;tr=udp%3a%2f%2fopen.stealth.si%3a80%2fannounce&amp;amp;tr=udp%3a%2f%2fopen.demonii.com%3a1337%2fannounce&amp;amp;tr=udp%3a%2f%2fmovies.zsw.ca%3a6969%2fannounce&amp;amp;tr=udp%3a%2f%2fipv4.tracker.harry.lu%3a80%2fannounce&amp;amp;tr=udp%3a%2f%2fexplodie.org%3a6969%2fannounce&amp;amp;tr=udp%3a%2f%2fexodus.desync.com%3a6969%2fannounce&amp;amp;tr=udp%3a%2f%2f9.rarbg.com%3a2810%2fannounce&amp;amp;tr=udp%3a%2f%2ftracker.opentrackr.org%3a1337&amp;amp;tr=udp%3a%2f%2fexplodie.org%3a6969
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Launch the installation once&lt;/li&gt;
  &lt;li&gt;Let it begin downloading some of the files&lt;/li&gt;
  &lt;li&gt;Kill the launcher&lt;/li&gt;
  &lt;li&gt;Grab the magnet with your favourite torrent client – you can use a PC for this and transfer the file to the deck or just install something like Transmission / Deluge / qtBitTorrent on your Deck to use.&lt;/li&gt;
  &lt;li&gt;Wait for the download to finish. It won’t crash :)&lt;/li&gt;
  &lt;li&gt;Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dolphin&lt;/code&gt; (file manager) and navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/home/deck/.local/share/Steam/steamapps/compatdata/2237253119/pfx/drive_c/Program Files/HorizonXI/Downloads/&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;The above path is an example – your randomly generated number after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compatdata&lt;/code&gt; is probably different and the install path depends on what you picked.&lt;/li&gt;
  &lt;li&gt;Place the ZIP in this folder&lt;/li&gt;
  &lt;li&gt;Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dolphin&lt;/code&gt; (file manager) and navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/home/deck/.local/share/Steam/steamapps/compatdata/2237253119/pfx/users/&amp;lt;user&amp;gt;/AppData/Roaming/HorizonXI-Launcher/config.json&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.json&lt;/code&gt; and modify the file:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;		&quot;baseGame&quot;: {
			&quot;downloaded&quot;: false,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;should be replaced with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;		&quot;baseGame&quot;: {
			&quot;downloaded&quot;: true,
            
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you open the launcher, it should now finish installing the game.&lt;/p&gt;

&lt;h3 id=&quot;how-can-i-update-the-launcher&quot;&gt;How can I update the launcher?&lt;/h3&gt;

&lt;p&gt;If you followed the guide, do the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Find the launcher version you want to update to from https://github.com/HorizonFFXI/HorizonXI-Launcher-Binaries/releases&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Run the following commands in the terminal one-by-one in Desktop mode again. This is just like the initial install:&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cp &quot;/home/deck/Downloads/HorizonXI-Launcher-1.1.12.Setup.exe&quot; ~/horizon-xi/installer.exe
cd ~/horizon-xi
7z x installer.exe
7z x HorizonXI_Launcher-1.1.12-full.nupkg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Make sure to replace the version number in the file paths to match the version of the launcher you just installed.&lt;/p&gt;

&lt;p&gt;That’s it.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Launch the game, it should be updated.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;my-game-is-asking-me-to-install-again-what-happened&quot;&gt;My game is asking me to install again. What happened?&lt;/h3&gt;

&lt;p&gt;This is typically because something has happened to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storage.json&lt;/code&gt;. If you just want to fix this, do the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Reboot your Steam Deck and do NOT launch the game at all.&lt;/li&gt;
  &lt;li&gt;Boot into desktop mode&lt;/li&gt;
  &lt;li&gt;Head to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/home/deck/.local/share/Steam/steamapps/compatdata/&amp;lt;PREFIX_ID&amp;gt;/pfx/users/&amp;lt;user&amp;gt;/AppData/Roaming/HorizonXI-Launcher/storage.json&lt;/code&gt; on the deck via Dolphin or some other file manager. Just like all other Proton installed software, the prefix ID will be random. You can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protontricks&lt;/code&gt; to find it or just sort by “recently modified” or something else to try and find the folder.&lt;/li&gt;
  &lt;li&gt;Open the file. Inside of this, you will find a bunch of JSON with several sections. The following section should be present.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;		&quot;installPath&quot;: {
			&quot;name&quot;: &quot;installPath&quot;,
			&quot;description&quot;: &quot;Location of HorizonXI Game install.&quot;,
			&quot;path&quot;: &quot;C:\\Program Files\\HorizonXI\\Game&quot;
		},
		&quot;downloadPath&quot;: {
			&quot;name&quot;: &quot;downloadPath&quot;,
			&quot;description&quot;: &quot;Location of HorizonXI zip download.&quot;,
			&quot;path&quot;: &quot;C:\\Program Files\\HorizonXI\\Downloads&quot;
		}
	},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you have followed the guide, you should have a copy of the game at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\\Program Files\\HorizonXI&lt;/code&gt;. Some folks may have also installed it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\\&lt;/code&gt;. If you are not sure where it is, go back to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drive_c&lt;/code&gt; inside of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pfx&lt;/code&gt; folder (up a few directories from this config file) and find the location. The path will be whatever it is under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drive_c&lt;/code&gt;, so for example if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drive_c/HorizonXI&lt;/code&gt; exists, then your path is probably &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\\Program Files&lt;/code&gt;. The double slash is intentional, it’s called escaping.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Modify the paths to point to the copy of the HXI game you have located. If you can’t find it, then that means your install is either lost or you cannot locate it. You will need to reinstall.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;In addition, there is a section of the config file that looks like this:&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;		&quot;currentVersion&quot;: 3,
		&quot;latestVersion&quot;: 3,
		&quot;baseGame&quot;: {
			&quot;downloaded&quot;: true,
			&quot;extracted&quot;: true
		},
		&quot;updater&quot;: {
			&quot;downloaded&quot;: 3,
			&quot;extracted&quot;: 3
		},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can modify the values to match this. If you don’t know if your old install is fully patched or not, I would recommend replacing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;currentVersion&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; to redownload any DATs needed.&lt;/p&gt;

&lt;h3 id=&quot;launching-gamepad-configuration-prevents-my-game-from-launching-anymore&quot;&gt;Launching gamepad configuration prevents my game from launching anymore&lt;/h3&gt;

&lt;p&gt;Sorry about that. It looks like a bug. Windows users are reporting the same.&lt;/p&gt;

&lt;p&gt;You have two choices:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Re-install and don’t click Gamepad configuration – the bug should be sorted “soon”&lt;/li&gt;
  &lt;li&gt;If you need gamepad support (Deck / using gamepad out of the box), you can follow this guide: https://www.youtube.com/watch?v=0UYdFoaVnOE&amp;amp;lc=UgywlUbnFvFWxBUOzW54AaABAg. It’s not supported by the team,
but has been confirmed to work on the deck.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A patch is supposed to come soon for gamepad players.&lt;/p&gt;

&lt;h3 id=&quot;i-cant-see-buttons-on-the-ui&quot;&gt;I can’t see buttons on the UI&lt;/h3&gt;

&lt;p&gt;The launcher has a fixed size. You can open the Steam keyboard and use tab to move around controls you can’t see, dock your Steam Deck to a montior / TV for more space, or use KDE window management features to move it around (google: “kde move window with mouse”).&lt;/p&gt;

&lt;h3 id=&quot;the-launcher-is-showing-all-black&quot;&gt;The launcher is showing all black&lt;/h3&gt;

&lt;p&gt;DXVK can cause this on some older cards. Disable it.&lt;/p&gt;

&lt;h3 id=&quot;im-getting-told-i-cant-run-it-as-admin&quot;&gt;I’m getting told I can’t run it as admin&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/horizonxi/admin_e.png&quot; alt=&quot;admin&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You’re probably trying to run the installer as-is from the website. Don’t do that; follow the directions above closely and make sure the item you added in Steam is the extracted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HorizonLauncher&lt;/code&gt; and not the setup.&lt;/p&gt;

&lt;h3 id=&quot;4gb-patch-1&quot;&gt;4GB Patch&lt;/h3&gt;
&lt;p&gt;Allows the game to use 4gb of RAM instead of the default 2gb. The disclamer in the discord says VRAM but Thorny(the Aurthor of the patch) says it increases RAM allowance of the executable.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;If you are using the Lutris install script then:
    &lt;blockquote&gt;
      &lt;p&gt;Launch HorizonXI in Lutris seclect 4GB Patch option and hit ok.&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;p&gt;If using the base wine install then:&lt;br /&gt;
	&amp;gt; Download the Patch &lt;a href=&quot;https://drive.google.com/uc?export=download&amp;amp;id=1MKuPC6iI3s6vuoi1jEsgO2z7Kanf9OKE&quot;&gt;here&lt;/a&gt; and extract the archive.&lt;br /&gt;
	&amp;gt; Run the patcher inside your prefix&lt;/p&gt;
    &lt;blockquote&gt;
      &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WINEPREFIX=~/.wine-horizonxi-64 wine &quot;~/Downloads/LargeAddressAwarePatcher/LargeAddressAwarePatcher.exe&quot;&lt;/code&gt;&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Navigate to C:\PATH\TO\HorizonXI\bootloader\horizon-loader.exe&lt;/li&gt;
  &lt;li&gt;Hit Patch, OK, and close the Patcher.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;where-can-i-get-artwork-for-my-install&quot;&gt;Where can I get artwork for my install?&lt;/h3&gt;

&lt;p&gt;You can find some at &lt;a href=&quot;/assets/horizonxi/assets.zip&quot;&gt;assets&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These are offical art assets cut for the Deck. Thanks to trent@ and Aku@.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Finding all the chest messages in "Trails from Azure"</title>
   <link href="http://vaughanhilts.me/2021/10/26/trails-from-azure-chest-messages.html"/>
   <updated>2021-10-26T21:17:00+00:00</updated>
   <id>http://vaughanhilts.me/2021/10/26/trails-from-azure-chest-messages</id>
   <content type="html">&lt;p&gt;There is a fun tradition from back in &lt;em&gt;Trails in the Sky&lt;/em&gt; for Trails in the Chest that involves hiding fun messages inside of the treasure chests in some of the Kiskei games. &lt;a href=&quot;https://kiseki.fandom.com/wiki/Trails_in_the_Chest,_Part_2&quot;&gt;You can find some of these chest messages here&lt;/a&gt;, such as the &lt;em&gt;Trails in the Chest&lt;/em&gt; series but no comprehensive list seems to exist anywhere. It turns out they are not too hard to extract from the game, so I thought it would be a fun evening project to extra the ones from &lt;em&gt;Trails to Azure&lt;/em&gt; since I just finished playing it and it was &lt;em&gt;fantastic&lt;/em&gt;! I’ll write about that later. For now, let’s move on to getting those chest messages!&lt;/p&gt;

&lt;p&gt;First, let’s begin with just finding the &lt;em&gt;Trails in the Chest&lt;/em&gt; messages since they’re easier to find as they have well known bounds and text.&lt;/p&gt;

&lt;p&gt;Let’s start with the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I ran &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strings&lt;/code&gt; on the game scene files to create a dump from all the strings I could find. This is pretty easy to do since the files are inside of a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; directory and they’re not compressed. Something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find . | xargs strings &amp;gt; ~/workspace/dump&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;From there, we could do all sorts of transformations on this data  A quick peek in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;less ~/workspace/dump&lt;/code&gt; shows us the following (mild spoilers from Azure):&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#5CCongratulations on reaching the end.
You've got a long road ahead of you still,
but I know you can do it.#0C
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is one of the messages from the game. We can see that it has some codes between the text. These are probably font colour op-codes since it is shared with some things that aren’t chest messages as well and they appear in a different font in game. For example:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://external-preview.redd.it/ey2dPLaumoUlwyhr0B7JlIzkslEF0k3gLQ2DTKR14kM.jpg?auto=webp&amp;amp;s=fe2c60a0e470d982924a43cf39b2f5b006ce9705&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Skimming through the file reveals that some other non-chest messages inside of the file. However, for now there is no need to worry about that since we’re just looking for the “Trails in the Chest” messages. They have some characteristics that make them easy to find:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;They start with [1/xx] etc, etc, one for each party of the story&lt;/li&gt;
  &lt;li&gt;There is a fixed number of them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this, we can just use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;awk&lt;/code&gt; to find them in the dump: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*cat ~/workspace/dump | awk '/#5C\[.\*\/.\*\]/,/#0C/'*&lt;/code&gt;. This gives us all the messages of which you can find a sample of them below:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#5C[55/61] In Bose, cramped between two of the most popular
shops on the block, was a tiny, tiny building. Last year,
it had been in a terrible state. Cobwebs once adorned the
windows, and insect droppings were commonplace.#0C
#5C[1/61] You remember reading the teaser in Trails in the Sky the 3rd
for 'Trails in the Chest, Pt. II,' but you didn't think it'd ever come.
Yet suddenly, you have a craving for more Trails...in the Chest.#0C
#5C[6/61] The day of their wedding, she, beautifully pristine
to a distressing degree in his eyes, had marched down
the aisle at a stiff pace. When he lifted her veil, he'd
seen no joy in her expression.#0C
#5C[44/61] 'Oh, SHUT UP!' Genevieve hopped just enough to
grip it and pulled it downward. Both had their hands on
the chest now, and neither one appeared to have any
intention of letting go. And then, to Genevieve's shock...#0C
#5C[11/61] True love! Something out of fairy tales, yes, but
Cyril's heart always did pang with longing while reading
them. He was a romantic at heart, and now here he sat,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We could do some cleanup to make this easier to read but it’s some simple regular expressions that we don’t need to cover here.&lt;/p&gt;

&lt;p&gt;Now, how do we find &lt;em&gt;all&lt;/em&gt; the chest messages? This is a bit trickier and we need to observe the following things about the string dump:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The chest messages can span at most 3 lines&lt;/li&gt;
  &lt;li&gt;The chest messages tend to adjacent to each other in the string dump (since they are located close together)&lt;/li&gt;
  &lt;li&gt;They always have the same font colour in the game&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this, we can write a short program to try and get the data out of our strings file:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/home/touma/Downloads/ao/dump&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msgs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pageBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pageCount&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;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pages&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;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lines&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#5C&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&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;nx&quot;&gt;pageCount&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;nx&quot;&gt;pageBuffer&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;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&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;nx&quot;&gt;pageCount&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;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pageCount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&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;// Give up on this message, lost cause and probably &quot;garbage&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;pageCount&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;nx&quot;&gt;pageBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#0C&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&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;// End of the line, we can include this line and then start over&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pageBuffer&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;pageBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#0C&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#5C&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;pages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pageBuffer&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;pageCount&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;nx&quot;&gt;pageBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&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;pageCount&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;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pageBuffer&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;pageBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#5C&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&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;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;msg&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;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

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

&lt;p&gt;This gives us pretty much a perfect listing with some manual cleaning needed to remove some false positives.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/azure/chest.md&quot;&gt;The full output of this can be found here.&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Playing Playstation remotely over Wireguard</title>
   <link href="http://vaughanhilts.me/2021/10/26/playstation-remote-play-wireguard-vpn.html"/>
   <updated>2021-10-26T21:17:00+00:00</updated>
   <id>http://vaughanhilts.me/2021/10/26/playstation-remote-play-wireguard-vpn</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;tldr; if you want to play over a VPN, consider something like &lt;em&gt;Chiaki&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve been going out more lately – especially now that COVID in Canada has been subsiding and things are returning to some sense of normalcy over the past few months. I’ve also been playing some games like &lt;em&gt;Trails of Cold Steel IV&lt;/em&gt; that are quite long and have been wishing I could take them on the go. Looking for solutions, there are a few to play over the Internet:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;PCs: You can use the remote play application from Sony, but unfortunately it only works under Windows on desktops&lt;/li&gt;
  &lt;li&gt;Mobile phones: You can use the official apps from the store but they lack good gamepad support outside of the Dualshock series of controllers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I run Android and use a stereoscopic controller for mobile. I use Arch Linux for my desktop operating system. This makes both of the above solutions problematic. The above solutions also have some other problems for both clients:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Sony limits the bandwidth you can get from over the Internet through their relay&lt;/li&gt;
  &lt;li&gt;Their relay introduces some latency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We then come up with the following needs list:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Supports whatever resolution I want&lt;/li&gt;
  &lt;li&gt;Should be able to play without relying on Sony’s server as much as possible&lt;/li&gt;
  &lt;li&gt;Should support whatever game-pad I have&lt;/li&gt;
  &lt;li&gt;Should work under Linux without trouble&lt;/li&gt;
  &lt;li&gt;Ideally, it would support my already existing Wireguard install&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;running-official-apps-over-a-vpn&quot;&gt;Running official apps over a VPN&lt;/h1&gt;

&lt;p&gt;The first obvious thing to do is try the applications that Sony provides over a VPN and to see if we make some tweaks to them to get them working for our needs. Unfortunately, this does not work well at all with Wireguard and other Layer 3+ VPNs. The reason is mostly that they use multicast to try and find devices over local networks. You need &lt;em&gt;Layer 2&lt;/em&gt; networks to do this.&lt;/p&gt;

&lt;p&gt;I found this out after doing some sniffing around and reading this good [https://github.com/williampiat3/ImprovingPSRemotePlay&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/williampiat3/ImprovingPSRemotePlay&quot;&gt;&lt;/a&gt;. In my case, I didn’t want to setup a Layer 2 VPN or change my existing networking topology just to accommodate this. However, it does not easily support Linux nor does it meet some of our requirements.&lt;/p&gt;

&lt;h1 id=&quot;running-aftermarket-over-a-vpn&quot;&gt;Running aftermarket over a VPN&lt;/h1&gt;

&lt;p&gt;The thing that ended up working for me is using two other applications with more support than the Sony applications that also happen to support Layer 3 VPNs due to the nature of allowing direct IP connection:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Chiaki&lt;/li&gt;
  &lt;li&gt;PSPlay for Android&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can setup direct connections for both of these and I can attest they work perfect under Wireguard. I setup some static addresses via DHCP reservations inside of my router and then I can use those to connect when routed through my VPN and it all works well: controller support + good resolution support.&lt;/p&gt;

&lt;p&gt;It is worth noting that Chiaki didn’t seem to fully support my gamepad like PSPlay did, so that’s why I ran with it for Android. This is at the time of writing – perhaps in the future it will look a bit better.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Installing and running WingsXI on Linux</title>
   <link href="http://vaughanhilts.me/2021/06/19/installing-and-running-wings-xi-on-linux.html"/>
   <updated>2021-06-19T21:17:00+00:00</updated>
   <id>http://vaughanhilts.me/2021/06/19/installing-and-running-wings-xi-on-linux</id>
   <content type="html">&lt;p&gt;The following is for installing &lt;a href=&quot;https://wingsxi.com/&quot;&gt;WingsXI&lt;/a&gt;, a WoTG FFXI private server on Linux. Specifically I am installing with the following Arch Linux System:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:wine/x86_64-windows $ neofetch
                   -`                    touma@setsuna 
                  .o+`                   ------------- 
                 `ooo/                   OS: Arch Linux x86_64 
                `+oooo:                  Model: B450 AORUS PRO WIFI 
               `+oooooo:                 Kernel: 5.12.9-arch1-1 
               -+oooooo+:                Uptime: 6 days, 19 hours, 29 mins 
             `/:-:++oooo+:               Packages: 1672 (pacman) 
            `/++++/+++++++:              Shell: zsh 5.8 
           `/++++++++++++++:             Resolution: 2560x1440 
          `/+++ooooooooooooo/`           DE: GNOME 40.2 
         ./ooosssso++osssssso+`          WM: Mutter 
        .oossssso-````/ossssss+`         WM Theme: EvoPop-Azure 
       -osssssso.      :ssssssso.        Theme: Materia-light-compact [GTK2/3] 
      :osssssss/        osssso+++.       Icons: Numix [GTK2/3] 
     /ossssssss/        +ssssooo/-       Terminal: gnome-terminal 
   `/ossssso+/:-        -:/+osssso+-     CPU: AMD Ryzen 7 3800X (16) @ 3.900GHz 
  `+sso+:-`                 `.-/+oso:    GPU: NVIDIA GeForce GTX 1080 
 `++:.                           `-/+/   Memory: 5913MiB / 32116MiB 
 .`                                 `/
                                                                 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There a few guides on the Internet that explain how to get this working as things are today but none of them cover WingsXI specifically which has a few quirks, so this guide will run through it. You can skip to each section if you want to know about specific parts of WingsXI or just installing Final Fantasy XI on Linux in general. All the commands here are given for Arch based distributions but you can find commands (such as replacing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yay&lt;/code&gt; with something else such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt-get&lt;/code&gt; for your system if you are using something else)&lt;/p&gt;

&lt;h2 id=&quot;downloading-wingsxi&quot;&gt;Downloading WingsXI&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;You can visit the WingsXI Discord from their site to get the latest binary. At the time of writing, this &lt;a href=&quot;https://cdn.discordapp.com/attachments/787567400429944843/848723709086662666/Install_Wings_v3.torrent&quot;&gt;is this file&lt;/a&gt; – however you should check Discord and check out the #first-time-setup to ensure you’re getting the latest version. It’s a torrent – so ensure you have some sort of torrent software to grab it. I use Deluge.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wingsxi.com/wings/index.php?page=signup&quot;&gt;Sign up for an account&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Activate your account via the e-mail that you provided&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;prepare-a-version-of-wine-with-the-proper-patches&quot;&gt;Prepare a version of Wine with the proper patches&lt;/h2&gt;

&lt;p&gt;You need a version of WINE that won’t crash when accepting the EULA. There are a couple options here.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;“Easy, recommended”&lt;/strong&gt;: Use a variant of WINE that has the patch integrated into it already, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine-staging&lt;/code&gt; (&lt;a href=&quot;https://github.com/wine-staging/wine-staging/blob/534f6ae34e89615fa424ee3e3002b1b3d419a8ba/patches/patchinstall.sh#L4979&quot;&gt;here&lt;/a&gt;). If you are on Arch Linux, you can do this using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman -S wine-staging&lt;/code&gt; (or any other helper you use). You can find &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine-staging&lt;/code&gt; in some other repos as well, such as the Ubuntu ones. You can find more on the &lt;a href=&quot;https://wiki.winehq.org/Download&quot;&gt;WINE install page&lt;/a&gt;. There are other versions that include that patch in their definition – any of them will do.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Easy, works in a pinch”&lt;/strong&gt;: You can download a patched &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;imm32.dll&lt;/code&gt; from the web such as &lt;a href=&quot;https://github.com/bluffnix/ffxi-wine/tree/master/linux&quot;&gt;https://github.com/bluffnix/ffxi-wine/tree/master/linux&lt;/a&gt; and replace your system library with it. You can find some directions on the web to do this – I would recommend you &lt;strong&gt;don’t do this&lt;/strong&gt; because every time you update the operating system and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine&lt;/code&gt; package it’s going to get replaced with a new binary. However, I wanted to write this here since it’s shown on the web a lot as a drag and drop solution from a lot of users.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“Hard”&lt;/strong&gt;: You can compile a version of WINE that has the proper fix. The patch in question &lt;a href=&quot;https://gitlab.com/farmboy0/wine/-/commit/54aea128e91a6b03bff05e79d9a09bea572ce99a&quot;&gt;is this&lt;/a&gt;. If you are an advanced user, you can do this if you can’t replace your system wine. If you do this, make sure you compile WINE with 64 bit support since you will need it. If you need help with this, leave a comment but for most users this shouldn’t be needed and should only be done if you can’t use the other options.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the time of writing, this worked with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:tidus $ wine --version
wine-6.10 (Staging)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;You must wait until the download of Wine and WingsXI to continue on from this point.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;preparing-a-prefix-for-wingsxi&quot;&gt;Preparing a prefix for WingsXI&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Note: A lot of places on the Internet tell you to use a 32-bit prefix for Final Fantasy XI; this does not work for WingsXI so please follow the directions very closely. If in doubt, follow step by step and start with a fresh prefix.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prepare a new prefix for WingsXI using the following command:&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;WINEPREFIX=~/.wine-wingsxi-64 winecfg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you get prompted for installing Gecko, you can accept without trouble.&lt;/p&gt;

&lt;p&gt;This will generate a new prefix. You should check:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;That the configuration window shows up&lt;/li&gt;
  &lt;li&gt;Windows 7 is selected as the version&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Moving along, let’s run the installer inside of WINE:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;WINEPREFIX=~/.wine-wingsxi-64 wine ~/Downloads/Install\ Wings\ v3/Installer.exe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/wingsxi/image-20210619214000116.png&quot; alt=&quot;image-20210619214000116&quot; /&gt;&lt;/p&gt;

&lt;p&gt;From this point, you can click through the prompts and you should get:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;An install directory, you can leave that as a default and the rest of the guide will assume you did. It will be a Windows path that is relative to your prefix.&lt;/li&gt;
  &lt;li&gt;A bunch of prompts that will install various Visual Studio redistributable packages. Let that run.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It should complete without trouble. Next, unfortunately WingsXI bundled with an installer that does not setup the path to the boot command by default. We can fix this with a quick &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sed&lt;/code&gt; replacement, so go ahead and run this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sed -i 's/C:\\Users\\alexs\\Desktop\\Installer Package\\Ashita\\ffxi-bootmod\\pol.exe/C:\\WingsXI\\Ashita\\ffxi-bootmod\\wingsloader.exe/g' &quot;~/.wine-wingsxi-64/drive_c/WingsXI/Ashita/config/boot/New Configuration 1.xml&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(If the above does not work, you can edit the file manually as well)&lt;/p&gt;

&lt;h2 id=&quot;running-wingsxi&quot;&gt;Running WingsXI&lt;/h2&gt;

&lt;p&gt;To run the game, you can use the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd ~/.wine-wingsxi-64/drive_c/WingsXI/Ashita/
WINEPREFIX=~/.wine-wingsxi-64 wine ~/.wine-wingsxi-64/drive_c/WingsXI/Ashita/injector.exe &quot;New Configuration 1.xml&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should get a login screen that looks something like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:WingsXI/Ashita $ 19/21 21:48:47] DarkStar Boot Loader (c) 2015 DarkStar Team
[06/19/21 21:48:47] Git Repo   : https://github.com/DarkstarProject/darkstar
[06/19/21 21:48:47] Modified for use with the Wings Project (c) 2021 Wings
[06/19/21 21:48:47] Version: 1.02
[06/19/21 21:48:47] Website    : https://www.wingsxi.com
[06/19/21 21:48:47] Git Repo   : https://gitlab.com/ffxiwings/wings
[06/19/21 21:48:47] ==========================================================
[06/19/21 21:48:47] Checking for updates...
[06/19/21 21:48:48] Already using the latest version.
[06/19/21 21:48:48] Connected to server!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From the login:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Press “1” for login&lt;/li&gt;
  &lt;li&gt;Type your username from the registration site&lt;/li&gt;
  &lt;li&gt;Type your password from the registration site&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should login. If you are having trouble, consult the following common issue list:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;The game crashes before I can see anything.&lt;/strong&gt; You are probably running a 32 bit prefix or something else that is not configured wrong. Open a bug on WINE or attach a crash report here so I can help you.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The game crashes after I accept the EULA.&lt;/strong&gt; You don’t have the X11DRV patch or it has stopped working. Try the WINE version listed here, make sure you’re using staging, or ensure you’re running your patched compiled version.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The login boot loader keeps repeating the menu over and over and I can’t login.&lt;/strong&gt; There exists a bug in WINE at the time of writing that prevents you from using the bootloader IO console. You can work around this by editing the boot command from WingsXI with your own command. If you have modified &lt;strong&gt;nothing else&lt;/strong&gt; in the XML configuration, you can simply open the file “~/.wine-wingsxi-64/drive_c/WingsXI/Ashita/config/boot/New Configuration 1.xml”&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt; in your favourite text editor and under the &lt;/code&gt;boot_command&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt; tag you can add the following arguments &lt;/code&gt;–user USERNAME –pass PASSWORD` to the command.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;When I tab out of the game, I can’t move / my macro palette keeps coming up.&lt;/strong&gt; This is due to your ALT key being stuck as being read. You can address this in a couple ways but the simplest way to do this is run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winecfg&lt;/code&gt; per the initial command at the start of the guide again (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WINEPREFIX=~/.wine-wingsxi-64 winecfg&lt;/code&gt; and turn on “Virtual Desktop” to get it’s own window frame). Alternatively, when tabbing back in simply press “Alt” again and it should work again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Assuming a successful login, you should be able to login with a character and get going without any trouble now. You should have access to all Ashita plugins like you should under Windows as well.&lt;/p&gt;

&lt;p&gt;You can create a shell script to run this command if you want / make a desktop shortcut out of it.&lt;/p&gt;

&lt;h2 id=&quot;correcting-gamma&quot;&gt;Correcting gamma&lt;/h2&gt;

&lt;p&gt;There exists an issue in XI that for some users when you launch the game it will request a gamma shift to play the opening movie but this gamma shift becomes permanent while the game is running. To fix this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;If you are running GNOME or some other DE, you can simply reload the shell after launching to revert the change. For example, for GNOME you can do Alt+F2 and then type “R” and Enter. KDE, etc have similar commands you can look up.&lt;/li&gt;
  &lt;li&gt;You can change some registry settings to &lt;a href=&quot;https://www.reddit.com/r/wine_gaming/comments/73a5cw/disallow_gamma_changes_from_wine_games/&quot;&gt;shut this off&lt;/a&gt;. Since changing the registry can be dicey, I won’t provide a one liner for this but you can find information online once you understand you have to change.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You’ll know the gamma has changed when you see it.&lt;/p&gt;

&lt;h2 id=&quot;configuring-xi--running-the-ashita-gui&quot;&gt;Configuring XI / Running the Ashita GUI&lt;/h2&gt;

&lt;p&gt;The Ashita GUI itself will not run (or I could get it to run) under a 64 (auto) prefix. It does, however, work, in a 32 bit prefix with one caveat: the game won’t launch from the launcher due to some other stubbed behaviour of fetching values from the registry.&lt;/p&gt;

&lt;p&gt;I would recommend you open the configuration file at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.wine-wingsxi-64/drive_c/WingsXI/Ashita/config/boot/New Configuration 1.xml&lt;/code&gt; and simply modify it yourself. The syntax is very straightforward and you can edit things like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default.txt&lt;/code&gt; with a simple text editor to get most of the control that that the GUI provides.&lt;/p&gt;

&lt;p&gt;However, it IS possible to run Ashita in a 32 bit prefix if you want to, configure things there, and then copy the config to your 32 bit prefix. To do this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine-staging&lt;/code&gt; if you didn’t already&lt;/li&gt;
  &lt;li&gt;Create a 32-bit prefix such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WINEPREFIX=~/.wine-wingsxi-32 WINEARCH=win32 winecfg&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Install WingsXI per the directions above&lt;/li&gt;
  &lt;li&gt;Install .NET 4.0 and 4.5.2 into the prefix: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winetricks dotnet40 dotnet45 WINEPREFIX=~/.wine-wingsxi-32 WINEARCH=win32&lt;/code&gt; (you may need to install winetricks if it was not included in your wine package such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman -S winetricks&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;You can now run Ashita &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WINEPREFIX=~/.wine-wingsxi-32 wine ~/.wine-wingsxi-32/drive_c/WingsXI/Ashita/Ashita.exe&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Make your config changes and then save them out to the other prefix&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You may be able to run Ashita from the old install from a the 32-bit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wineserver&lt;/code&gt; but I’ve not tried it. Editing config files is something you only have to do once, so I did mine by hand. I would seriously recommend just doing that.&lt;/p&gt;

&lt;h2 id=&quot;addressing-performance&quot;&gt;Addressing performance&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The following section is true of Windows as well but it not documented well on the web so I will document it here.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Performance in FFXI is fine in 30FPS mode and even in 60FPS for most setups. However, in cities with a lot of people in them performance can suffer at times due to the single threaded nature of the game and using DX8 which WINE support for it crummy.&lt;/p&gt;

&lt;p&gt;You can do a few things to make this a lot better:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Turn off shadow using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/localsettings shadows off&lt;/code&gt; in game.&lt;/li&gt;
  &lt;li&gt;Run the game in 30FPS mode using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/fps 2&lt;/code&gt; if you can’t maintain 60FPS&lt;/li&gt;
  &lt;li&gt;Installing a wrapper to convert D3D8 calls into D3D9 or Vulkan calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are many things that can do this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;dgVoodo&lt;/li&gt;
  &lt;li&gt;Ashita’s proxy&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/crosire/d3d8to9/releases&quot;&gt;crosire&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I use &lt;em&gt;crosire’s&lt;/em&gt; proxy. You can install it by:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Downloading the latest DLL from the release page&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Copying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d3d8.dll&lt;/code&gt; it into the various spots:&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.wine-wingsxi-64/drive_c/WingsXI/Ashita/ffxi-bootmod&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.wine-wingsxi-64/drive_c/WingsXI/SquareEnix/FINAL FANTASY XI&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.wine-wingsxi-64/drive_c/WingsXI/SquareEnix/PlayOnlineViewer&lt;/code&gt;&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winecfg&lt;/code&gt; to use the native override&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;
        &lt;p&gt;Run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WINEPREFIX=~/.wine-wingsxi-64 winecfg&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Set the override in the library tab&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/assets/wingsxi/image-20210619221721174.png&quot; alt=&quot;image-20210619221721174&quot; /&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Run the game per normal&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The process is very similar for all the other proxies. If one does not work well for you, you can try others. Some users have had luck with layering proxies to translate into Vulkan (for lower CPU draw call overhead, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dxvk&lt;/code&gt;) ultimately but I get a smooth frame rate with a single one, so I’ve not had the need. If you have steps for this, leave a comment and I can include them.&lt;/p&gt;

&lt;h3 id=&quot;make-ffxi-beautiful-2021&quot;&gt;“Make FFXI beautiful 2021”&lt;/h3&gt;

&lt;p&gt;The following are a couple notes you may find useful. I will update them as time goes on into full out guides if there is interest:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;https://www.reddit.com/r/linux_gaming/comments/b2hi3g/reshade_working_in_wine_43/&lt;/li&gt;
  &lt;li&gt;https://www.youtube.com/watch?v=ADjRYUdSyXA&lt;/li&gt;
  &lt;li&gt;https://nocturnalsouls.net/getting-setup/high-definition-dats/&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
  &lt;li&gt;The path of least resistance for WingsXI for HD mod replacements is DAT replacement directly. You can snapshot your prefix folder to get easy rollback – or use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brtfs&lt;/code&gt; snapshot if you want, that makes this trivial to roll back for updates (something WIndows users can’t do)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;did-i-miss-something&quot;&gt;Did I miss something?&lt;/h2&gt;

&lt;p&gt;If you can’t get it working, you can find me on the Wings Discord or you can leave a comment below. I’ve tried to cover everything you would have to do and will flesh out things like HD Mods as I have time to type it out but in the meantime, contributions are welcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#windurst&lt;/strong&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Investigating how my local home router is resolving hostnames automatically</title>
   <link href="http://vaughanhilts.me/2020/04/20/how-does-my-router-resolve-hostnames-on-my-local-network.html"/>
   <updated>2020-04-20T21:17:00+00:00</updated>
   <id>http://vaughanhilts.me/2020/04/20/how-does-my-router-resolve-hostnames-on-my-local-network</id>
   <content type="html">&lt;p&gt;I have a boring standard home router, though it’s a bit on the expensive side (Or it was when I got it many years back). It runs AsusWRT and it’s the RT-N66U from Asus.&lt;/p&gt;

&lt;p&gt;It has a neat feature that automatically resolves hostnames on my local network that I never really thought about. I can do something like:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ping promathia
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… and get a response back from a machine on my network that has the name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;promathia&lt;/code&gt;. A lot of home routers don’t actually work this way and most of them just forward all DNS requests to get their upstream provider. Of course, you could always add these entries to a host file but you would have to manage that static mapping everywhere and that’s kind of annoying.&lt;/p&gt;

&lt;p&gt;I use this feature on a weekly basis but the thing that bothered me was that I could never set another DNS server in my router configuration page or this feature would break. I’d have been wanting to try out Cloudflare’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.1.1.1&lt;/code&gt; or Google’s resolver because benchmarking showed they were faster in some cases. Unfortunately, this would break the hostname resolution over the entire network when I had tried it. That’s when I had realized I had no idea how any of it worked. Given the above change as well, it was clear this was not something like Netbios, Bonjour, or Avahi. Something else was going on.&lt;/p&gt;

&lt;p&gt;Using various tools such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dig&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nslookup&lt;/code&gt;, you could verify that the resolution was going to the default gateway to get the answers. The question remaining now was “how”?&lt;/p&gt;

&lt;p&gt;I first actually looked to see if there was something in the DHCP specification to do this, since it seemed logical. I made a bunch of queries to Google including things like “DHCP add hostname” but I could not find anything about the specification doing this. I did find that many implementations did this though, such as Microsoft’s &lt;a href=&quot;https://serverfault.com/a/70922/191979&quot;&gt;DHCP&lt;/a&gt; but I am running mostly Linux systems and I am certainly not running that on the router as far as I could tell. (Are there routers out there that run this?)&lt;/p&gt;

&lt;p&gt;I got some other complicated answers like setting up DDNS and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; with some &lt;a href=&quot;https://wiki.debian.org/DDNS&quot;&gt;keys&lt;/a&gt;. I remember doing neither of those things and they looked a lot more complicated than some home router setup.&lt;/p&gt;

&lt;p&gt;I supposed the first thing to figure out was to understand what was running on the router itself. Luckily, AsusWRT supports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;telenet&lt;/code&gt; (which is not super secure, but for this purpose is fine) and I could go into the machine and check it out. I knew of a few DNS packages, so I figured I would go check for those first (some of the answers on Superuser helped me round up some of the items that would be likely)&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;admin@RT-N66U:/tmp/home/root# ps | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;dns
  357 nobody    1212 S    dnsmasq &lt;span class=&quot;nt&quot;&gt;--log-async&lt;/span&gt;
20032 admin     1620 S    &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;dns
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This reveals that we are running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; for our DNS server and DHCP. So, then the question left remaining was: how is this handled by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt;? It turns out if you read the documentation you can find out this happens by default. You can even add a &lt;a href=&quot;http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html&quot;&gt;domain&lt;/a&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--expand-hosts&lt;/code&gt; and friends) to have the hostnames expanded. However, I don’t have those settings form what I could tell. The question remaining became &lt;em&gt;how does this work&lt;/em&gt;? I had some ideas but I would need to read some source code to know for sure.&lt;/p&gt;

&lt;p&gt;It turns out the key and simplicity is in how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; does both DNS and DHCP.&lt;/p&gt;

&lt;h2 id=&quot;figuring-out-how-dnsmasq-would-get-the-hostname-and-add-it-to-dns&quot;&gt;Figuring out how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; would get the hostname and add it to DNS&lt;/h2&gt;

&lt;p&gt;First of all, let’s take a step back and figure out how a hostname would even get to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; in the first place. It is clear that some point you would need to send it and that cannot happen without some kind of network traffic or statically configuring. I certainly did not do the latter and that would defeat the purpose of an automatic process. So then, what else could do it? A multi-cast DNS system for sure, but I had none of those either.&lt;/p&gt;

&lt;p&gt;The answer lies then in the process that happens on every boot of an Internet connected system and the thing that happens when you need to configure your NIC to get access (typically, you could be statically configuring but I only have a handful of those and those work too – more on that later) That would be DHCP.&lt;/p&gt;

&lt;p&gt;You send your hostname as part of the DHCP process, specifically it’s &lt;a href=&quot;https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml&quot;&gt;client option 12&lt;/a&gt; and allows you to send this as part of the process. By the way, client options are just pieces of metadata information that are sent as part of the process. I read quite a bit about it – but there are better explanations online. You’re better off reading those. Now, let’s remember that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; is a DHCP server and DNS server; that means it has the ability to read out these options. It can also serve DNS query responses.&lt;/p&gt;

&lt;p&gt;The next part is understanding the fact that the DHCP protocol does not specify any sort of specification about DNS updates but like the Microsoft DHCP server, you would be free to implement something on top as long as it didn’t violate the specification. In this case, adding DNS entries based on the option 12 was looking like a good bet. From here, we had to look at some source code to figure out if that’s exactly how it worked though since information on this via the web is kind of vague and you can’t get an exact answer. I found a good mirror on &lt;a href=&quot;https://github.com/dnsmasq/dnsmasq&quot;&gt;Github here&lt;/a&gt; and checked it out that’s a bit older but would serve well for the purpose of viewing how things work.&lt;/p&gt;

&lt;p&gt;When getting a lease from DHCP (from a client) you can find that the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lease_update_dns&lt;/code&gt; (&lt;a href=&quot;https://github.com/dnsmasq/dnsmasq/blob/ce5732e84fc46d7f99c152f736cfb4ef5ec98a01/src/lease.c#L458&quot;&gt;link&lt;/a&gt;) is called and has something like this in the code:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lease&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fqdn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	    &lt;span class=&quot;n&quot;&gt;cache_add_dhcp_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lease&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fqdn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lease&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lease&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expires&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;option_bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OPT_DHCP_FQDN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lease&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	    &lt;span class=&quot;n&quot;&gt;cache_add_dhcp_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lease&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lease&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lease&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expires&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, in other words we get the hostname from the lease and add it to some cache. You can dig through the code some more and find that many of the functions are looking through the DHCP cache, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;check_for_local_domain&lt;/code&gt; (&lt;a href=&quot;https://github.com/dnsmasq/dnsmasq/blob/ce5732e84fc46d7f99c152f736cfb4ef5ec98a01/src/rfc1035.c#L1262&quot;&gt;link&lt;/a&gt;). This gives you the answer you need – and that is that it is directly taking those leases that you generated and maintaining the cache from those. Then, the DNS server is using the items in that cache to resolve things.&lt;/p&gt;

&lt;p&gt;The last important to thing to note is that – unless a client has configured otherwise – DHCP will provide a DNS server to the client to use. You don’t have to use this one to connect to the Internet, though most clients will. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; is a DNS server – so you when I am told to contact my default gateway for DNS, that would be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; under the hood. This then later forwards to the ISP upstream later.&lt;/p&gt;

&lt;p&gt;That’s basically it; there are other interesting things in the implementation (such as how it implements round robin – which is through the cache get mutating the list internally) but they aren’t required to understand how my all in one home router was operating – it was running a local copy of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; that does most of this heavy lifting already.&lt;/p&gt;

&lt;p&gt;Incidentally, for the things with a static IP (things like my NAS, virtual machine server and others) the reason their hostname resolution works is because I use DHCP reservations on the router instead of on a static IP client. If I had done it on a client, then the hostname would have never have been set as part of the DHCP request (no request would have been sent if I had manually configured the interface all together). Since the static mapping is setup server side, the client will still make a DHCP request per normal and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnsmasq&lt;/code&gt; will take care of giving it the same IP each time. Win win. &lt;a href=&quot;https://serverfault.com/questions/544619/static-ip-vs-dhcp-reservation&quot;&gt;There’s other advantages&lt;/a&gt; to doing it this way as well.&lt;/p&gt;

&lt;p&gt;So, then why did changing the domain server break things? Simple: it was handing out a different DNS server from the local one as part of DHCP. You can verify this easily on Linux at least just looking at your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resolv.conf&lt;/code&gt; briefly:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:/tmp/test &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; /etc/resolv.conf
&lt;span class=&quot;c&quot;&gt;# Generated by resolvconf&lt;/span&gt;
nameserver 192.168.1.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;vs.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:/tmp/test &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; /etc/resolv.conf
&lt;span class=&quot;c&quot;&gt;# Generated by resolvconf&lt;/span&gt;
nameserver 1.1.1.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Mystery solved. Maybe someone will have the same question as me in the future and this will bring some answers to them a bit faster.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Installing OpenMediaVault without a network connection at time of install</title>
   <link href="http://vaughanhilts.me/2019/04/20/installing-openmedia-vault-without-a-network-connection-at-time-of-install.html"/>
   <updated>2019-04-20T21:17:00+00:00</updated>
   <id>http://vaughanhilts.me/2019/04/20/installing-openmedia-vault-without-a-network-connection-at-time-of-install</id>
   <content type="html">&lt;p&gt;My current media server is running unRAID. While I have some gripes about it (that I won’t get into here) it has been running rock solid for quite some time and has serviced all my needs, especially with the Docker container support. I have a backup server in my home as well that I sometimes use for mirroring data, which was running Debian for a while. I wanted to replace it with a flash drive OS and remove the 2TB drive being used as a host OS drive, since I wanted to use it for something else.&lt;/p&gt;

&lt;p&gt;Since it was mostly just a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsnapshot&lt;/code&gt; drone + HDD enclosure for the backup drives, I figured something simpler that could be installed to a flash drive with &lt;strong&gt;some persistence&lt;/strong&gt; would do the trick.&lt;/p&gt;

&lt;p&gt;The only issue is that my workbench (the backup server has no monitor or keyboard near it) where I service my machines (it has a small monitor + KB mouse combo) had no network cable there yet since I had moved. I didn’t really want to install that one at the time since it would be a pain and I was moving soon anyway. With no WiFi card and understanding it would hopefully pick up network config later when I plugged it back in headless later, I decided to try and install it without being connected to the network since it was supposed to be supported.&lt;/p&gt;

&lt;p&gt;Well, that’s what the Internet claimed. I wouldn’t be writing here today though if it was so simple. For the record, life is easier if you just install while connected to a network. But it’s not too bad to fix the issues you come up with if you can’t, this post is hoping to get people on the same page about that.&lt;/p&gt;

&lt;h1 id=&quot;installing-the-system&quot;&gt;Installing the system&lt;/h1&gt;

&lt;p&gt;This is pretty straight-forward. You can install it with the &lt;a href=&quot;https://openmediavault.readthedocs.io/en/latest/installation/&quot;&gt;directions from the site&lt;/a&gt;. There are a few changes that I will list below…&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;The network detection is going to fail.&lt;/strong&gt; This is to be expected. When it tries detecting networks and tries to do DHCP, you can just cancel it. It will warn you that nothing is configured. That’s OK.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The network sources for the Debian repos will not be configured properly.&lt;/strong&gt; It will warn you to let you know. This will cause issues later, so we will take care of that later.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;You won’t get hostname validation.&lt;/strong&gt; So make sure the hostname is unique.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you’re like me, you’re going getting through the install, reboot and login. Things will appear to be working well, locally with no network. You will then proceed to login via the prompt and verify things look good.&lt;/p&gt;

&lt;p&gt;Then, you unplug from the bench and plug into where it’s going to live. You load up your workstation and try and hit the host name in your browser, for example like so (where the hostname I picked was &lt;em&gt;lalafell&lt;/em&gt;) and you would get something like…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.redd.it/wuiwo6tk5hwz.jpg&quot; alt=&quot;&amp;lt;https://i.redd.it/wuiwo6tk5hwz.jpg&amp;gt;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(This is pulled from the web – it would the hostname of your machine in the error)&lt;/p&gt;

&lt;p&gt;And if you try and ping it, you would get…&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;setsuna@setsuna ~]&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ping lalafell
ping: lalafell: Name or service not known
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It turns out that it won’t auto detect the new network cable you plugged in and you have to set it up… ugh.&lt;/p&gt;

&lt;h1 id=&quot;resolving-network-connectivity&quot;&gt;Resolving network connectivity&lt;/h1&gt;

&lt;p&gt;You can solve this using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;omv-firstaid&lt;/code&gt;. If you have a monitor and cable, you can just login and run that command and be good to go. Of course, that was a bit trickier without lugging a bunch of crap to my workstation. You can run it headless, just do the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Turn on your machine and wait a few minutes to make sure it’s good to go.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Type your username in and hit enter. Then type your password in and hit enter. Do this carefully to ensure you get it right, especially since you can’t see feedback (no monitor)&lt;/li&gt;
  &lt;li&gt;Type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;omv-firstaid&lt;/code&gt; and hit enter.&lt;/li&gt;
  &lt;li&gt;Hit “Enter” again after about 5 seconds. The default option is for network connections.&lt;/li&gt;
  &lt;li&gt;Hit “Enter” again. It’s selecting an interface.&lt;/li&gt;
  &lt;li&gt;Hit “Enter” again. It’ll begin configuring.&lt;/li&gt;
  &lt;li&gt;Wait 1 minute.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then, you can ping the machine and you will get:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;setsuna@setsuna ~]&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ping lalafell
PING lalafell &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;lalafell&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 56&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;84&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; bytes of data.
64 bytes from lalafell: &lt;span class=&quot;nv&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 &lt;span class=&quot;nv&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;64 &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1.84 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’re good to go. You can do the rest from your workstation.&lt;/p&gt;

&lt;p&gt;I figured this out by installing in a VM and then just walking through it in the VM and then reproducing the steps inside of the machine. A bit reckless but for a machine with nothing on it yet this was fine. And it worked out.&lt;/p&gt;

&lt;h1 id=&quot;fix-the-broken-sources-from-the-install-process&quot;&gt;Fix the broken sources from the install process&lt;/h1&gt;

&lt;p&gt;By default, the source list was not installed right given the current installer I used at the time of writing when done offline. &lt;a href=&quot;https://forum.openmediavault.org/index.php/Thread/5981-Problems-with-sources-list/&quot;&gt;You can follow this guide to to fix that&lt;/a&gt;. This is pretty easy to figure out when you know this is the problem, but how to figure out this is the issue?&lt;/p&gt;

&lt;p&gt;You might get something like this…&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Failed to execute &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin; export LANG=C; export DEBIAN_FRONTEND=noninteractive; apt-get --yes --allow-downgrades --allow-change-held-packages --fix-missing --allow-unauthenticated --reinstall install openmediavault-flashmemory 2&amp;gt;&amp;amp;1'&lt;/span&gt; with &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;code &lt;span class=&quot;s1&quot;&gt;'100'&lt;/span&gt;: Reading package lists...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;when trying to install the flash memory plugin like I did. You’re going to need to do the above if you get this.  The following &lt;a href=&quot;https://github.com/OpenMediaVault-Plugin-Developers/openmediavault-flashmemory/issues/20&quot;&gt;Github issue is also relevant&lt;/a&gt;. It took me a few queries to get this – so hopefully this saved you some time.&lt;/p&gt;

&lt;h1 id=&quot;checking-everything-else-out&quot;&gt;Checking everything else out&lt;/h1&gt;

&lt;p&gt;Be sure to run a system update since I had some updates to get. Not sure if this was due to the lack of network during install or what, but there were some.&lt;/p&gt;

&lt;p&gt;Make sure to check network connectivity is as you wanted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That’s all I had to do. Smooth overall; just had a couple road bumps. I hope this saves someone some time.&lt;/strong&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Replacing the fans on a Zotac GTX 970 (Dual Fan Model)</title>
   <link href="http://vaughanhilts.me/2019/03/21/replacing-the-fans-on-a-zotac-gtx-970-dual-fan-model.html"/>
   <updated>2019-03-21T21:17:00+00:00</updated>
   <id>http://vaughanhilts.me/2019/03/21/replacing-the-fans-on-a-zotac-gtx-970-dual-fan-model</id>
   <content type="html">&lt;p&gt;My Zotac GTX 970 is 3.5 years old or so. Or was at the time of writing this post. About three weeks ago, the fans from it started making a whining noise. Some might call it almost a squeak. Or it sounded like perhaps it needed to be lubed. But life was busy and a little fan noise or “coil whine” never killed a card… immediately… right?&lt;/p&gt;

&lt;p&gt;Well, they died about two weeks later. Other issues I had leading into those two weeks (for those coming from Google):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I had a faint chemical odour being emitted from my PC case. Turns out this was most likely from the fans&lt;/li&gt;
  &lt;li&gt;The fans would start and stop at random on the GPU. And then the whining would go away&lt;/li&gt;
  &lt;li&gt;You would hear “clicking” noises coming from the GPU&lt;/li&gt;
  &lt;li&gt;I would try and play games like &lt;em&gt;Move or Die&lt;/em&gt; or &lt;em&gt;Warframe&lt;/em&gt; with friends and the temperatures would get stupid high. I would then eventually lose display after a few minutes of gameplay. This often happened around the 100 degree mark. &lt;a href=&quot;https://nvidia.custhelp.com/app/answers/detail/a_id/2752/~/nvidia-gpu-maximum-operating-temperature-and-overheating&quot;&gt;Nvidia cites around 105 being the max&lt;/a&gt; – so it sounds about right.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, I had to figure out what was wrong. To make matters worse: it died completely with the 4th symptom during a few days I booked off at home to get some stuff done at home + with the intent at least to play some games!&lt;/p&gt;

&lt;h1 id=&quot;diagnosing-the-fans-vs-the-fan-controller&quot;&gt;Diagnosing the fans vs. the fan controller&lt;/h1&gt;

&lt;p&gt;I wasn’t sure if the fans were dead or not. I mean, they didn’t work but it could have been &lt;em&gt;a dead fan controller&lt;/em&gt;. Luckily, it looks like the GPU Fan Controllers just use standard case fan headers so I tested a case fan from the computer in the video card header.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/970repair/header.jpg&quot; alt=&quot;header&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can see the header above.&lt;/p&gt;

&lt;p&gt;I gave the card some power and the fans began to turn on and rotate. Looks like we just had some dead fans.&lt;/p&gt;

&lt;p&gt;After checking the specs of the fans and trying to find a comparable part, &lt;a href=&quot;https://www.amazon.ca/gp/product/B071GMPX1M/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;I settled on these&lt;/a&gt;. Amazon estimated it would take two days to get them to me.&lt;/p&gt;

&lt;h1 id=&quot;getting-me-through-the-days&quot;&gt;Getting me through the days&lt;/h1&gt;

&lt;p&gt;I still wanted to play while I was waiting on my new fans, though. Of course, not in a reckless way but if I could get something working…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/970repair/fan.png&quot; alt=&quot;fan&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Believe it or not, this was enough to cool the card to play games. It would drop the idle temperatures from 75 to the mid 50s which is not great but was more than serviceable – and light to mid gaming worked well, if a bit toasty overall.&lt;/p&gt;

&lt;p&gt;Of course, this was temporary. :D&lt;/p&gt;

&lt;h1 id=&quot;installing-the-new-fans&quot;&gt;Installing the new fans&lt;/h1&gt;

&lt;p&gt;Sorry, I don’t have packaging photos. Forgot to take some. Here’s the best one I have:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/970repair/fan.jpg&quot; alt=&quot;fan&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now, onto the steps of what I did. &lt;a href=&quot;https://www.youtube.com/watch?v=BOb4aqcMy5U&quot;&gt;I more or less followed this guide&lt;/a&gt;.  However, I will outline some issues / things I had to do with mine that the video didn’t cover.&lt;/p&gt;

&lt;h2 id=&quot;remove-the-splitting-connector&quot;&gt;Remove the splitting connector&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/970repair/adapter.jpg&quot; alt=&quot;adapter&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Mine came with this adapter holding the two together. You don’t need this since this GPU has two pins – and it’s just going to get in the way. You can remove it.&lt;/p&gt;

&lt;h2 id=&quot;clean-out-the-dust&quot;&gt;Clean out the dust&lt;/h2&gt;

&lt;p&gt;Mine had a ton. You might want to consider removing some of this since you’re here. I doubt this is strictly needed but I doubt it would hurt, either.&lt;/p&gt;

&lt;h2 id=&quot;make-sure-the-fans-spin-right-before-assembling-make-sure-wires-wont-touch-the-blades&quot;&gt;Make sure the fans spin right before assembling; make sure wires won’t touch the blades&lt;/h2&gt;

&lt;p&gt;It sounds obvious but I had this problem when I initially installed them. I hadn’t retained the wires under the clip perfectly so I had a small problem where the fan blade was hitting up against the wires sometimes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/970repair/wires.jpg&quot; alt=&quot;wires&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Make sure the wires are down tight and you rotate the fan without trouble.&lt;/p&gt;

&lt;h2 id=&quot;pay-attention-to-how--the-casing-came-off&quot;&gt;Pay attention to how  the casing came off&lt;/h2&gt;

&lt;p&gt;I didn’t and it took a few minutes to figure out the orientation of putting it back on.&lt;/p&gt;

&lt;h1 id=&quot;done&quot;&gt;Done!&lt;/h1&gt;

&lt;p&gt;Success!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/970repair/working.jpg&quot; alt=&quot;working&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Who knows if it’s done 100% right? But it works well. I probably should give some other stuff in the case some TLC as well.&lt;/p&gt;

&lt;p&gt;The idle temperatures are honestly a bit on the warmer side. 39 or so. Writing this post without much else going (just driving a 1440p display x2) we’re looking at:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/970repair/temps.png&quot; alt=&quot;temps&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve seen better. But I had seen much worse just last week!&lt;/p&gt;

&lt;p&gt;In some games, load causes it to go up to about 80, sometimes  85. That’s a bit toastier than I think would be ideal – but honestly, I plan on replacing the card in the next couple of years anyway so as long as it serves me right till then. ;)&lt;/p&gt;

&lt;p&gt;Hope this helps someone!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Writing a fast (mostly) Binox solver</title>
   <link href="http://vaughanhilts.me/blog/2019/03/07/writing-a-binox-solver.html"/>
   <updated>2019-03-07T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2019/03/07/writing-a-binox-solver</id>
   <content type="html">&lt;p&gt;We’re going to look at solving &lt;a href=&quot;https://krazydad.com/binox/&quot;&gt;Binox&lt;/a&gt; puzzles in this post today. The game has also been known to go under the popular name &lt;em&gt;Tic-tac Logic&lt;/em&gt; if you are familiar with that.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/hilts-vaughan/binox-interactive-solver&quot;&gt;If you just want to try it, you can find that here.&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;what-is-the-game&quot;&gt;What is the game?&lt;/h1&gt;

&lt;p&gt;Binox is a binary game with a board looking like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/f5c075e2-f192-4163-b90b-b352743a794e/example.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The objective is to fill the entire board with either “X” or “O” given some rule scheme – which varies in difficulty. The rules are as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;No &lt;strong&gt;row or column&lt;/strong&gt; may have more than three characters that are the same in a row. For example, this is illegal:&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/f5c075e2-f192-4163-b90b-b352743a794e/illegal_row.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;… since there is 3 of the same character in a row. However, something like ` XX00XO` is legal&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;No &lt;strong&gt;row or column&lt;/strong&gt; may have an unequal amount of characters. This means the above image would also be illegal as well.&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Corollary&lt;/em&gt;: The puzzles width and height must be even in length.&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Proof:&lt;/em&gt; Suppose some board exists where &lt;em&gt;n&lt;/em&gt;, the length of the board is odd. Let &lt;em&gt;x&lt;/em&gt; be the number of characters assigned “X” in a complete board. Let &lt;em&gt;y&lt;/em&gt; be the number of characters assigned “O” in a complete board. Given the restriction &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x = y&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x + y = n&lt;/code&gt; then consider the following cases,&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; is odd, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt; is odd. The result of two odd numbers added &lt;a href=&quot;https://math.stackexchange.com/questions/1456447/prove-that-the-sum-of-two-odd-numbers-is-an-even-number&quot;&gt;together is always even&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; is even, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt; is even. The result of two even numbers &lt;a href=&quot;https://math.stackexchange.com/questions/2740499/the-sum-of-two-odd-numbers-is-even&quot;&gt;added together is always even&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;Any other combination implies breaking the constraint &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x = y&lt;/code&gt; since a number cannot be even &lt;strong&gt;and&lt;/strong&gt; odd at the same time.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Each &lt;strong&gt;row and column&lt;/strong&gt; in the entire puzzle must be unique. This means you cannot repeat the same row or column anywhere.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these restrictions, solving the puzzle becomes a bit more than just throwing random “X” and “O”s at the grid. Let’s look at an algorithm that can solve this.&lt;/p&gt;

&lt;h1 id=&quot;the-simplest-thing-that-can-solve-this&quot;&gt;The simplest thing that can solve this&lt;/h1&gt;

&lt;p&gt;I tried a few things that were “clever” and “complicated” such as generating permutations of rows and comparing to other possibilities for other rows. We won’t go over those – since it turns out the best solution I found is one of the simpler ones! You can read about general strategy on the web but the example I’m going to step through below is a general approach I came up with.&lt;/p&gt;

&lt;p&gt;The algorithm is as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Let &lt;em&gt;Q&lt;/em&gt; be the set of indices on the grid that still need to be found (that is, they are neither “X” or “O” yet; often denoted as blanks). Initialize this to all possibilities.&lt;/li&gt;
  &lt;li&gt;Find an entry, any entry, that when you would place a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;  there (but not both!  think… XOR) the following criteria is true:
    &lt;ol&gt;
      &lt;li&gt;The column and row associated with this entry does not contain a streak of 3&lt;/li&gt;
      &lt;li&gt;Modifying this entry does not make it impossible in the future for other to-be-determined entries in that row or column to respect the rules. The main one to worry about is the quota surrounding equality. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; is the row or column length, then by placing on this entry a specific token, the number of “X”s or “O”s must not exceed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n/2&lt;/code&gt; since it would then be impossible for other to meet the criteria.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;Remove this entry from the set, since it is now placed&lt;/li&gt;
  &lt;li&gt;Continue this process until all entries are placed&lt;/li&gt;
  &lt;li&gt;If you at some point cannot find such an entry in the set, the puzzle has no solution.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s break down why this is the case.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Why XOR for choices?&lt;/strong&gt; This one is pretty simple – if you have two choices and you can only make one of them without breaking the rules at any given step, then that choice is obvious. It’s the ideal scenario.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Why the count guard?&lt;/strong&gt; This is also pretty simple – if you let a row or column exceed the length divided by two – the others cannot meet the criteria of being a valid “slice” as explained above&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Wouldn’t we run out of things with only a single choice?&lt;/strong&gt; As you place more entries, other entries become more obvious as to what they &lt;em&gt;must be&lt;/em&gt; since the decisions of other entries from the set are now dictating their possibilities. Each choice made this way only enables &lt;em&gt;more&lt;/em&gt; information for future moves – preventing you from ever barring off future choices for other moves.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;automating-it-all&quot;&gt;Automating it all&lt;/h2&gt;

&lt;p&gt;Of course, this is easy to describe so we can encode it inside of an application. I won’t go over all the implementation details but you can describe the entire main algorithm like so, in Javascript:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PuzzleSolutionSolver&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;solve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;board&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;activeBoardPointer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;board&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pointsToSolveFor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;activeBoardPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getIndiciePairsThatAreNotFilledIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iterationsBeforeGivingUp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pointsToSolveFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;originalIterationsBeforeGivingUp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iterationsBeforeGivingUp&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pointsToSolveFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;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;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pointToSolveFor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pointsToSolveFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;theoryWithOne&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_isTheorySafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;activeBoardPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pointToSolveFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;theoryWithZero&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_isTheorySafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;activeBoardPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pointToSolveFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;theoryWithOne&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;theoryWithZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tokenToProceedWith&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;theoryWithOne&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;activeBoardPointer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;activeBoardPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;withPointChangedTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;pointToSolveFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;tokenToProceedWith&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Let it cycle around the list a few times. This could be dangerous in some cases since&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// you might let things spin for a long time but this should only happen on VERY large boards. So it's not a huge deal&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;iterationsBeforeGivingUp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;originalIterationsBeforeGivingUp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Both were doable, so we cannot make a choice since we are unsured yet&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// so we place it back on the queue in hopes that something other mutation&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;pointsToSolveFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pointToSolveFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;iterationsBeforeGivingUp&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;p&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;iterationsBeforeGivingUp&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;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Reached the max iteration count. Could not converge on a solution. Giving up...&lt;/span&gt;&lt;span class=&quot;dl&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;activeBoardPointer&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;// helper functions&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;_isTheorySafe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;board&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;token&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;board&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;board&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;withPointChangedTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;board&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getSlicesForPoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;horizontalSlice&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slices&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;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;verticalSlice&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slices&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;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isMaintainingSliceQuotaIntegrity&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;nx&quot;&gt;horizontalSlice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isExceedingQuota&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;verticalSlice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isExceedingQuota&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isMaintainingRunIntegrity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;horizontalSlice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNotSlidingWindowLargerThanThree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;verticalSlice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNotSlidingWindowLargerThanThree&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;isMaintainingRunIntegrity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isMaintainingSliceQuotaIntegrity&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;/div&gt;&lt;/div&gt;

&lt;p&gt;You could even cut some of this down a bit as well. You can dig into the actual implementation of some of these rules in the &lt;a href=&quot;https://github.com/hilts-vaughan/binox-solver&quot;&gt;full implementation on my Github&lt;/a&gt;. It’s a short read – the entire thing (with all the tests, which is most of the code) clocks in at less than 1000 lines of code. It should be easy to digest.&lt;/p&gt;

&lt;p&gt;Let’s first examine the puzzle posed above.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;X&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;-&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;-&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;-&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;-&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;-&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;O&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;O&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;-&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Using the above rules, we can then run the program and find:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  console.log src/PuzzleSolutionSolver.js:26
    Going to proceed to change 0 | 2 with 0

  console.log src/PuzzleSolutionSolver.js:26
    Going to proceed to change 1 | 2 with 0

  console.log src/PuzzleSolutionSolver.js:26
    Going to proceed to change 1 | 3 with X

  console.log src/PuzzleSolutionSolver.js:26
    Going to proceed to change 2 | 1 with 0

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

&lt;p&gt;If we step through these picks, we can see the rationale.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;If you were to add a “X” in that spot, there would be more X’s than allowed (since you could never possibly 4 O’s there).  Therefore, the only logical placement is to put a “O” there.&lt;/li&gt;
  &lt;li&gt;The same rationale for a row below – you can fill it in immediately.&lt;/li&gt;
  &lt;li&gt;This has to be an “X” since otherwise, you would have 3 “O”s in a row. This is because the item to the left was filled in from the previous iteration, as we knew what it &lt;em&gt;had to be&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;You can’t have a streak of 3 – no prior info is needed since those “X”s  are static and already placed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;… and there are more iterations. The number of choices grows smaller with each pick so the queue grows smaller until it reaches zero. There are more boards it has been tested on; you can check them out in the tests. I have some plans to add more tests from the PDFs provided. However, I tried to do a couple “cURLS” to get the PDFs and stopped being able to access the author’s site from home. Huh.&lt;/p&gt;

&lt;p&gt;I’ve probably been blocked. Not sure why.&lt;/p&gt;

&lt;h1 id=&quot;further-optimization&quot;&gt;Further Optimization&lt;/h1&gt;

&lt;p&gt;Some heuristics could be developed to pick the points to prevent cycling through the list to find a valid one. For example, in the case of “exceeding quota” in a specific column and “forcing” a single token such as in example #1 and #2 above, we could have easily filled in the entire column. The solver began to do this but once it reached another point it could solve it just did that one first instead. The current implementation just uses a dequeue and pushes things to the back if i t can’t find something it can place immediately.&lt;/p&gt;

&lt;p&gt;There’s probably other speed improvements to be made too: like not writing this in Javascript. But the solver runs so fast, already even with larger boards that I’m not that motivated to do much else. It was a fun afternoon project – now it’s time to say goodbye for now.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Swapping from macOS and Linux, work to home... things I miss from each platform</title>
   <link href="http://vaughanhilts.me/blog/2019/03/07/things-i-miss-from-using-mac-os-for-work-and-things-i-wish-i-had-better-using-mac-os.html"/>
   <updated>2019-03-07T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2019/03/07/things-i-miss-from-using-mac-os-for-work-and-things-i-wish-i-had-better-using-mac-os</id>
   <content type="html">&lt;p&gt;I work as a Software Developer doing mostly front-end work but I do some back-end work as well. Where I work right now, we mostly develop using Macbook.  Up until recently, there were a few people using some Linux machines to get their work done but the standard issue machine is a Macbook. Even if I could swap to something else, I wouldn’t and here’s why:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I want to be on the same platform as my peers so when there is a problem I can receive help in the best way and give them the best help as well.&lt;/li&gt;
  &lt;li&gt;Development tools are more or less platform agnostic but rarely is anything free. If we were split 50/50, that would be one thing. But being one of the only outliers? That’s painful&lt;/li&gt;
  &lt;li&gt;Hardware and IT support is going to be a lot better with a standard stock macOS install&lt;/li&gt;
  &lt;li&gt;Macbook hardware has bad support for it unless you are going for older hardware – and that’s just a no no when you are trying to make the make use of everything you have.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That being said,  it’s not like I like macOS. Even though &lt;a href=&quot;https://www.google.com/search?q=macos+bcoming+more+unstable&amp;amp;oq=macos+bcoming+more+unstable&amp;amp;aqs=chrome..69i57.2591j0j7&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&quot;&gt;some people&lt;/a&gt; are reporting software quality problems more and more (and I have noticed some things) there are a lot of things I like about the macOS environment. I figured I’d name a few here and hope that by putting it down, I even might be able to improve my workspace in both.&lt;/p&gt;

&lt;h1 id=&quot;things-i-have-in-my-arch-linux-setup-i-wish-i-had-there&quot;&gt;Things I have in my Arch Linux setup I wish I had there&lt;/h1&gt;

&lt;h2 id=&quot;tiling-window-manager&quot;&gt;Tiling Window Manager&lt;/h2&gt;

&lt;p&gt;I have a tiling window manager here. I don’t have to use a clunky terminal with it’s own keybindings like iTerm on macOS.  I use i3 and I won’t try and sell you on the benefits, but I will say is I never have to reach for my mouse to resize random windows and everything is just fullscreen and driven by a keyboard by default. For some non-work workflows, this is a bit clunky (looking at you – Steam) so I have GNOME for some other stuff. It’s not my favourite but for getting work done, I can’t beat the i3 setup.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/8f56a3de-7eee-4d9f-b7d9-7ee875cab677/tiling.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=j1I63wGcvU4&quot;&gt;There’s a nice guide for getting started here on that&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;my-software-just-upgrades-without-much-trouble&quot;&gt;My software just upgrades without much trouble&lt;/h2&gt;

&lt;p&gt;I run a Pacman upgrade every once in a while and then reboot when I need to. Nothing nags me. Nothing is in the way of trying to prevent me from doing what I need to. macOS has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew&lt;/code&gt; and the AppStore but it’s not enough. There is a bunch of stuff that just does not work and hangs. &lt;a href=&quot;https://github.com/Homebrew/homebrew-core/issues/23441&quot;&gt;I was a victim of something like this earlier.&lt;/a&gt; And there are more. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew&lt;/code&gt; is also moving towards being a binary package manager where it can. This is not so bad, but this can be a real hassle sometimes. For example, consider &lt;a href=&quot;http://vaughanhilts.me/blog/2017/02/06/openssl-with-sslv3-on-arch-linux-for-dot-net-core.html&quot;&gt;the time I had to recompile something w/ SSLv3 for something&lt;/a&gt; I had to support, Arch made this a joke to do but macOS… well that would have been an ordeal.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew&lt;/code&gt; loves to choke sometimes as well on random things. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman&lt;/code&gt;, well I’ve had issues but you can usually find the solutions on the front page since they’re expected.&lt;/p&gt;

&lt;h2 id=&quot;native-docker&quot;&gt;Native Docker&lt;/h2&gt;

&lt;p&gt;Holy crap. This is such a big deal and I didn’t even realize why until I really figured it out. &lt;a href=&quot;https://www.reddit.com/r/docker/comments/7b0g4v/docker_for_mac_speed_on_high_sierra/&quot;&gt;People have been complaining about it for a bit&lt;/a&gt; but until I tried using it on macOS for other stuff, I didn’t realize what a difference there was. That combined with the fact that I can poke things inside of Linux land without going through a ton of hoops. That’s a miracle. I get performance without running on top of a giant hypervisor that’s sluggish and clunky.&lt;/p&gt;

&lt;p&gt;That’s not to say it’s unusable – but when I learned Docker from scratch, I did it on the Linux host for a reason. There was no competition.&lt;/p&gt;

&lt;h2 id=&quot;nothing-gets-in-my-way&quot;&gt;Nothing gets in my way&lt;/h2&gt;

&lt;p&gt;No iCloud pop-ups. No notifications to reboot. No jarring software prompts. No force Windows Updates. I update on the same schedule weekly, on my own time and I run it manually. If there is something urgent, I do it again. I do my server @ the same time and control the schedule so I can control downtime as needed.&lt;/p&gt;

&lt;h2 id=&quot;i-can-use-the-same-tools-to-adminster-my-server-as-a-workstation&quot;&gt;I can use the same tools to adminster my server as a workstation&lt;/h2&gt;

&lt;p&gt;This is self explanatory. I have a home server and I love being able to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt; and use all the things I am familiar with to modify it. macOS has a ton of these tools as well but often they don’t work quite the same.&lt;/p&gt;

&lt;h2 id=&quot;being-able-to-choose--when-to-adopt-new-things&quot;&gt;Being able to choose  when to adopt new things&lt;/h2&gt;

&lt;p&gt;USB-C is awesome.&lt;/p&gt;

&lt;p&gt;I am also not ready to move everything over to it. I think Apple thinks I’m ready, though. Considering they removed my HDMI. This has been covered a ton by the press but seriously: it’s annoying.&lt;/p&gt;

&lt;p&gt;Suffice to say, I have some older hardware and I don’t mind. It’s mature and most things are working now.&lt;/p&gt;

&lt;h1 id=&quot;things-i-miss-coming-home-from-my-macos-machine&quot;&gt;Things I miss coming home from my macOS machine&lt;/h1&gt;

&lt;h2 id=&quot;performance&quot;&gt;Performance&lt;/h2&gt;

&lt;p&gt;There’s not inherently slow about Linux. In a lot of stuff, it’s even faster and works better on a &lt;em&gt;raw level&lt;/em&gt;… for example if we’re talking &lt;a href=&quot;https://www.phoronix.com/scan.php?page=article&amp;amp;item=dota2-mac-vulkan&amp;amp;num=2&quot;&gt;Vulkan support, there’s no contest.&lt;/a&gt; And for other stuff like some parallel computing, some of the schedulers are on another level. Or some of the machine learning stuff going on. However, general &lt;em&gt;compute performance&lt;/em&gt; is slower. i3 is just laggier sometimes on a similar specced machine. I get random stalls sometimes as things hiccup. The desktop experience just is not as polished. It’s not like things are unusable – not by a kilometer. However, things are just generally more sluggish.&lt;/p&gt;

&lt;h2 id=&quot;software-support-for-some-mainstream-things&quot;&gt;Software Support for “some mainstream things”&lt;/h2&gt;

&lt;p&gt;Office? Google Suite has replaced a lot of the need for that stuff for me. Typing documents is a basic need for me and I’m not strapped for having a ton formatting options.&lt;/p&gt;

&lt;p&gt;Photoshop?&lt;/p&gt;

&lt;p&gt;The experience is better here. This is still a sore spot. I wish I had these. I might have to get a VM passthrough going or something to get better results over here in Linux land. I’m using Pinta for basic editing over here and I’ve tried GIMP but it’s not the same. Once you’ve learned Photoshop skills, it’s pretty hard to retrain for something as simple as “OS loyalty”. I am sure the job can get done in other spots but I don’t know want to relearn when it’s not the primary objective of my workstation.&lt;/p&gt;

&lt;h2 id=&quot;hardware-support&quot;&gt;Hardware Support&lt;/h2&gt;

&lt;p&gt;People keep saying that Linux desktop is plug and play. We either live in a different world or some of them are more optimistic than I. I’ve plugged a lot of things in and they don’t work as well as I would like. I still can’t find a nice way to adjust scrolling speed in Linux for Chrome and other apps to be faster to my liking. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xpad&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xboxdrv&lt;/code&gt; often have competing goals and clobber each other. My options for mice and keyboards are a bit more limited; I pick according to what is going to work in my  system.&lt;/p&gt;

&lt;p&gt;##Searching for a problem? You can narrow it down – it’s a macOS thing probably&lt;/p&gt;

&lt;p&gt;Running an Arch Linux distro + a ton of other stuff that is non-standard, I get a shit ton of problems I have to sort out myself. Origin in WINE not running? It does not play nice with tiling window managers. Switch to GNOME for now. &lt;a href=&quot;http://vaughanhilts.me/blog/2018/02/16/steam-hanging-on-clicking-login-wine-staging.html&quot;&gt;Steam hanging for some random reason?&lt;/a&gt; Break out the debugger.&lt;/p&gt;

&lt;p&gt;When looking for macOS stuff, there’s usually only a handful of hits that apply to most systems. No guesswork for involved. As I get better at debugging, I can pinpoint problems faster but there’s less annoyance in this case.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Installing Final Fantasy XI and dual boxing on the Nasomi Private Server (Linux)</title>
   <link href="http://vaughanhilts.me/blog/2018/10/27/install-final-fantasy-xi-nasomi-server-and-dual-box.html"/>
   <updated>2018-10-27T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2018/10/27/install-final-fantasy-xi-nasomi-server-and-dual-box</id>
   <content type="html">&lt;p&gt;I recently wanted to give the Nasomi XI Private Server a try as I had played a lot of Final Fantasy XI when I was younger and was feeling a bit nostalgic. Since the population is a bit smaller than it was then but still very respectable (1300 players during prime time) there are quite a few dual-boxers. These are people who play more than one character at the same time. For those not familiar, Final Fantasy XI is a game that is very heavy on co-operation and a lot of tasks require at least two players and often a lot more. Most people do this dual boxing because..&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It is allowed here and encouraged where it was not on the retail servers.&lt;/li&gt;
  &lt;li&gt;It makes a lot more content more accessible to you without needing to rely on others for EVERYTHING.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The only problem was my platform of choice these days is a Linux x86 PC where as I had played on a PS2 during the early 2000s era of Final Fantasy XI. Nasomi is not supported on the PS2 – so that just left getting the game running on Linux or running it in Windows.&lt;/p&gt;

&lt;p&gt;**Spoilers: ** It runs inside of Linux very nicely – we just need to put in a bit of effort to do so.&lt;/p&gt;

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

&lt;p&gt;Let’s get started by just downloading the official installer for Windows from &lt;a href=&quot;https://na.nasomi.com/download.php&quot;&gt;here&lt;/a&gt;. You can pick whatever method you want – there is no difference in the contents.&lt;/p&gt;

&lt;p&gt;Next,  you’re going to want to unzip the package somewhere. You can use a GUI tool or the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unzip&lt;/code&gt; command for this but it does not matter much. if you don’t have WINE or have no idea what it is, you can read about it more &lt;a href=&quot;https://en.wikipedia.org/wiki/Wine_(software)&quot;&gt;here&lt;/a&gt;. We’re going to make use of it – there’s a trick, though… the official wiki recommends some weird hacks to get it running and we will still need to do this but it applies them to the installed version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine&lt;/code&gt; on your machine since the wiki suggests butchering your system install of WINE.&lt;/p&gt;

&lt;p&gt;There’s a couple snags I ran into and I will list them here:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It asks you to override a DLL to play – and this is going to get overwritten every time you have to an update, or at least it would be on &lt;em&gt;Arch Linux&lt;/em&gt; which is my OS of choice for playing games.&lt;/li&gt;
  &lt;li&gt;It does not account for the fact that there is an &lt;a href=&quot;https://bugs.winehq.org/show_bug.cgi?id=45279&quot;&gt;open bug&lt;/a&gt; in newer versions of WINE that prevent Final Fantasy XI from being playable. There are a few things that can be wrong – but if you have a Nvidia card like me you are likely to run into this at the time of writing if you are running a rolling release. This might not be everyone but there are enough of us that someone is going to have a bad time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/bf9bf6a4-6426-4653-a7b1-5988b1104afb/artifact.png&quot; alt=&quot;this is what happens when you are using the latest version without the patch&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It does mention &lt;em&gt;Ashita&lt;/em&gt; won’t work but it does not mention how to get dual boxing support.  I’ve had not found a way to get Ashita v2 working yet reliably but there are ways of getting dual-boxing working.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thus, there are two things we can do to get around this and have a much better experience.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;We will grab a local copy of WINE and use this for our FFXI – and do the DLLs overrides in a local copy&lt;/li&gt;
  &lt;li&gt;We will then be able to apply the patch as well on top for this, allowing us to apply any sort of bug fixes we need to get the same running (see: #2)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s get started. I’ll assume you have copied the installer into a folder, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/nasomi&lt;/code&gt; and we are working inside of there.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Grab the WINE source code (or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine-staging&lt;/code&gt;) if you prefer that and clone it with&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/wine-mirror/wine
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Go into the source directory (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd wine&lt;/code&gt;) and then download the patch from before that we need, apply it and commit it. **If you are using Wine 3.19 or a later trunk, you may need to use this path instead https://bugs.winehq.org/attachment.cgi?id=62646&amp;amp;action=diff&amp;amp;context=patch&amp;amp;collapsed=&amp;amp;headers=1&amp;amp;format=raw as the below patch may not apply clean&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget &lt;span class=&quot;s2&quot;&gt;&quot;https://bugs.winehq.org/attachment.cgi?id=62460&amp;amp;action=diff&amp;amp;context=patch&amp;amp;collapsed=&amp;amp;headers=1&amp;amp;format=raw&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; ffxi.patch
git apply ffxi.patch
git commit &lt;span class=&quot;nt&quot;&gt;-am&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Applied FFXI patch for NVIDIA cards&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We’re going to compile WINE. Inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine&lt;/code&gt; directory (you can check you are in the right directory by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt; and making sure it reports as found) run…&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./configure
make &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; 2 &lt;span class=&quot;c&quot;&gt;# You can make this the number of processors you have&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;As it’s compiling, move onto the next step.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now, grab the DLL override. The wiki has a copy of it &lt;a href=&quot;http://nabutso.com:4438/FFXI/imm32.dll.so&quot;&gt;here&lt;/a&gt; however, I will provide a copy of the same DLL &lt;a href=&quot;/assets/bf9bf6a4-6426-4653-a7b1-5988b1104afb/imm32.dll.so&quot;&gt;here&lt;/a&gt; as well on  my own server in case it ever goes offline, since the  link is to another player’s server. For example, you can just do this to get the file (or use the URL from my server if that is ever needed):&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget http://nabutso.com:4438/FFXI/imm32.dll.so 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We need to replace the DLL now inside of the WINE folder. We can do this with a simple copy command:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cp imm32.dll.so dlls/imm32/imm32.dll.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;from inside the WINE directory. This should give you the ability to run without problems now.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We are ready to begin installing the game. There’s a setup EXE or batch file (depends on the version of the game) and you can run it by doing the following:&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;WINEPREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/ffxi-custom-first &lt;span class=&quot;nv&quot;&gt;WINEARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;win32 ./wine/wine &lt;span class=&quot;s2&quot;&gt;&quot;./installer.exe&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;A couple things to note above:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;You should replace the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WINEPREFIX&lt;/code&gt; without whatever you want – in my case, I have two separate prefixes for both players so I can have completely different settings and I have the diskspace to support it. And you should change the installer EXE to whatever the name of the setup installer is of the version at the time of running.&lt;/li&gt;
      &lt;li&gt;FFXI is a 32 bit game so we are going to be running in 32 bit mode.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You should get the installer with some music. Just install with the defaults and move on. This took about 5 minutes for me on an SSD – time will vary.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The game is installed – so it’s time to run it. By default, the settings are a bit weird so it might be worth just configuring them quickly. You can do by running the following command:&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;WINEPREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/ffxi-custom &lt;span class=&quot;nv&quot;&gt;WINEARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;win32 ./wine/wine &lt;span class=&quot;s2&quot;&gt;&quot;/home/touma/ffxi-custom/drive_c/Program Files/NasomiXI/SquareEnix/FINAL FANTASY XI/ToolsUS/FINAL FANTASY XI Config.exe&quot;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… and you can change some things like the resolution, bump settings, texture resolution etc. When are you done, save your changes and we can move onto playing the game.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You can run the following command to play:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;WINEPREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/ffxi-custom &lt;span class=&quot;nv&quot;&gt;WINEARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;win32 ./wine/wine &lt;span class=&quot;s2&quot;&gt;&quot;/home/touma/ffxi-custom/drive_c/Program Files/NasomiXI/SquareEnix/Ashita/ffxi-bootmod/boot.exe&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and then you are good to go. The game should launch. If you want to dual box, you would do the same thing as you just did but with another copy of WINE – checked out from the source code again. This will give you two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WINESERVER&lt;/code&gt;s and prevent the crashing on startup you would get from trying to launch two clients at once under normal circumstances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;None of this will have Ashita running, though since that does not work in v2 with Nasomi&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/bf9bf6a4-6426-4653-a7b1-5988b1104afb/ffxi_nasomi.png&quot; alt=&quot;this is what happens when you are using the latest version without the patch&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;other-things-you-may-want-to-know&quot;&gt;Other things you may want to know&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;FFXI benefits from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;esync&lt;/code&gt; patches – so if your CPU is a bit on the weaker side like mine you may want to get a WINE Build with them included.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Create launch scripts.&lt;/strong&gt; It sounds obvious but don’t forget you can create simple bash scripts to wrap some of the commands for launching the game. I have a script for each of my characters so I can run whatever one I want to login to.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Periodically update WINE.&lt;/strong&gt;  There are performance benefits you can get from updating your copy (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt;) from the mirror from time to time. You may want to do this from time to time.&lt;/li&gt;
  &lt;li&gt;The patch from above may stop working at some point – you may need to reapply it from time to time with a new one. Or it might not be needed at all. You can pick a stable WINE tag if you want to avoid problems. For example,  if you are using 3.19 as a base you will notice there is a &lt;a href=&quot;https://bugs.winehq.org/show_bug.cgi?id=45279&quot;&gt;different patch here&lt;/a&gt; for that.&lt;/li&gt;
  &lt;li&gt;This has only been tested on the below configuration, I have not tested on anything  else:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:~ &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;neofetch
                   -&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;                    touma@setsuna 
                  .o+&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;                   &lt;span class=&quot;nt&quot;&gt;-------------&lt;/span&gt; 
                 &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;ooo/                   OS: Arch Linux x86_64 
                &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;+oooo:                  Kernel: 4.18.16-arch1-1-ARCH 
               &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;+oooooo:                 Uptime: 10 days, 6 hours, 34 minutes 
               -+oooooo+:                Packages: 1393 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;pacman&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, 4 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;dpkg&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 
             &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/:-:++oooo+:               Shell: zsh 5.6.2 
            &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/++++/+++++++:              Resolution: 2560x1440 
           &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/++++++++++++++:             DE: GNOME 3.30.1 
          &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/+++ooooooooooooo/&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;           WM: i3 
         ./ooosssso++osssssso+&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;          Theme: Paper &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;GTK2/3] 
        .oossssso-&lt;span class=&quot;sb&quot;&gt;````&lt;/span&gt;/ossssss+&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;         Icons: Numix &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;GTK2/3] 
       &lt;span class=&quot;nt&quot;&gt;-osssssso&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;      :ssssssso.        Terminal: terminator 
      :osssssss/        osssso+++.       CPU: Intel i5-2500 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;4&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; @ 3.700GHz 
     /ossssssss/        +ssssooo/-       GPU: NVIDIA GeForce GTX 970 
   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/ossssso+/:-        -:/+osssso+-     Memory: 7723MiB / 16002MiB 
  &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;+sso+:-&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;                 &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;.-/+oso:
 &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;++:.                           &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;-/+/                           
 .&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;                                 &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/

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

&lt;p&gt;The rest you can figure out from the Nasomi page and is standard stuff. This ought to work for any server or set of people who cannot run Ashita or Windower as well, such as macOS users but your steps may vary.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Using Huginn for profit and fun; finding price errors on the Internet</title>
   <link href="http://vaughanhilts.me/blog/2018/04/26/using-huggins-for-fun-and-profit.html"/>
   <updated>2018-04-26T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2018/04/26/using-huggins-for-fun-and-profit</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/assets/3b805ee5-3552-4a64-8c78-75f6ec8dcf7a/1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Those are not faked (read: &lt;em&gt;photoshopped&lt;/em&gt;) – that is how much I paid for those items sometime in 2014. Those are really good deals for those items,  especially in Canadian Dollars. Most of those retailed for about over $100 CAD over here.&lt;/p&gt;

&lt;p&gt;These are all known as &lt;em&gt;price error&lt;/em&gt; items as the merchant did not intend to sell them for this much. However, sometimes logistics software screws up and there’s a community of people who want to scoop up these things.&lt;/p&gt;

&lt;p&gt;They actually come up quite a bit:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;https://www.theguardian.com/money/2014/dec/14/amazon-glitch-prices-penny-repricerexpress&lt;/li&gt;
  &lt;li&gt;https://www.google.ca/search?ei=su3kWpLWFKTCjwTJ8JuoBg&amp;amp;q=price+error+redflagdeals&amp;amp;oq=price+error+redflagdeals&amp;amp;gs_l=psy-ab.3…2939.4442.0.4541.0.0.0.0.0.0.0.0..0.0….0…1c.1.64.psy-ab..0.0.0….0.6Tp0J06Cgms&lt;/li&gt;
  &lt;li&gt;https://www.telegraph.co.uk/finance/personalfinance/money-saving-tips/11288449/I-spot-and-exploit-pricing-errors-for-a-living.html&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;.. at least a few times a week in most cases. Of course, not all items are of interest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The process of ordering something that was priced in error&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To get in on this, you need to…&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Notice and find out about the error. Usually communities like RedFlagDeals or SlickDeals have sub-forums where people tell each other about these things. There are also services that notify people (more on this later)&lt;/li&gt;
  &lt;li&gt;You need to order and act quick.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You need a quick reaction time as these are often fixed within an hour, sometimes even less than that. There’s other factors as well that affect the quality. In Canada, if you can do in an in-store  reservation at that price and then go in to get it the same day – you have better odds than having it shipped, since orders are sometimes canceled on-line but fulfillment rates are high in store.&lt;/p&gt;

&lt;p&gt;Since short of reading every thread frequently is tedious, we need automation. Some tools are available already off the shelf to do this which we will dive into first to motivate building something new.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The manual process of finding some of these&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generally, there are a few ways of doing this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Subscribe to items on &lt;a href=&quot;http://ca.lightningdrops.com/&quot;&gt;LightningDrops&lt;/a&gt; and have them notify you.&lt;/li&gt;
  &lt;li&gt;Check communities such as &lt;a href=&quot;http://forums.redflagdeals.com/hot-deals-f9/&quot;&gt;Redflagdeals&lt;/a&gt; and then monitor threads&lt;/li&gt;
  &lt;li&gt;Keep track of certain items on the individual vendor sites&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No single strategy is going to get you 100% of the way there and some services provide automated ways of doing this already for you to increase your chances. I was a frequent user of method #2 for a while but it takes up a lot of time, since often they are the best sources of some of the more obscure deals and involve reading pretty much every thread. Wouldn’t it be nice if we could just get a notification when someone posts something of interest?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://slickdeals.net/deal-alerts/&quot;&gt;Slickdeals&lt;/a&gt; has something to do this and so does &lt;a href=&quot;https://www.redflagdeals.com/alerts/&quot;&gt;RedFlagDeals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve used them. They both have some problems, though:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;They’re a bit slow – it can sometimes take up to 15 minutes to get the e-mail and that’s a bit too slow in some cases (despite saying “instant” on their pages for “Notification Speed”)&lt;/li&gt;
  &lt;li&gt;They deliver through their own mechanism, which means e-mail in most cases and perhaps not what we want. Or their application. Or IFTT’s application.&lt;/li&gt;
  &lt;li&gt;They don’t support complicated queries or Regular Expressions, which as a developer, I know is pretty important in some cases. ;) We’ll see some example thread titles later that show why this is the case, but image things like &lt;em&gt;HOOOOT&lt;/em&gt; or &lt;em&gt;HOTTT!!&lt;/em&gt; which are things that won’t be picked up by a basic string matches but something humans might type, with exaggerated letters.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We know the inflexibility problem in this case is because the “data source” and the notification system (and querying of the data) are coupled to each other. We have no way of querying the data ourselves, the communities themselves provide one-stop shops.&lt;/p&gt;

&lt;p&gt;Our solution? To decouple the stream of data from the notifications and allow us to create more customized ways of filtering on the data. &lt;a href=&quot;https://ifttt.com/discover&quot;&gt;IFTT&lt;/a&gt; is an inspiration for Huginn and kind of solves this problem. IFTT actually has a widget for &lt;a href=&quot;https://ifttt.com/applets/rUrQkihN-notify-me-of-new-deals-from-slickdeals&quot;&gt;Slickdeals here&lt;/a&gt; but it’s not very customizable. It’s likely you could create your own using IFTT with some work but you won’t be able to get #3 for free that easily and you will have trouble getting 2. IFTT is quite fast, thought.&lt;/p&gt;

&lt;p&gt;If you don’t have your own infrastructure, it’s not a bad way to go. But let’s look at alternatives using &lt;em&gt;Huginn&lt;/em&gt; to do this. I’m not going to cover the installation, so check out their &lt;a href=&quot;https://github.com/huginn/huginn/blob/master/doc/manual/installation.md&quot;&gt;install guide&lt;/a&gt; (I recommend Docker if you can use iti) or my install guide using &lt;a href=&quot;http://vaughanhilts.me/blog/2018/04/26/setting-up-huggins-on-unraid-for-automation.html&quot;&gt;unRAID&lt;/a&gt; if you want to follow along. Otherwise, time to get started.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://github.com/huginn/huginn&quot;&gt;If you don’t know what Huginn is you can read more about it here.&lt;/a&gt; It’s essentially a system that allows you to pull data from various sources, aggregate it into events, query it, and then act on it. That sort of vague, right? But it’s kind of exactly what we need…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;setting-up-a-plan&quot;&gt;Setting up a plan&lt;/h1&gt;

&lt;p&gt;This is our general plan of attack:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Monitor the RSS feed of a particular forum and collect  &lt;strong&gt;new posts only&lt;/strong&gt; since our last check&lt;/li&gt;
  &lt;li&gt;Aggregate them all into a shared pool&lt;/li&gt;
  &lt;li&gt;Run some regular expressions against each entry to filter down to the ones we’re interested in as they come in&lt;/li&gt;
  &lt;li&gt;Dispatch to a notification daemon and have it notify me in real time if there’s a match&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our notification stack is going to be &lt;a href=&quot;https://www.pushbullet.com/&quot;&gt;Pushbullet&lt;/a&gt; for a few reasons:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I already have an account&lt;/li&gt;
  &lt;li&gt;It can mirror between phone and desktop, so I’m going to get it quick no matter where I am.&lt;/li&gt;
  &lt;li&gt;It supports link types with one click opening of links.&lt;/li&gt;
  &lt;li&gt;Huginn has a native agent for it installed by default.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We’ll pull our data from boring Atom RSS feeds – reliable, updated fairly quick and standardized. Huginn also supports web scraping for more speed (since RSS feeds can sometimes lag behind) and for sites that do not provide federated access to their data. We won’t touch this here but it could be pretty easy to implement and swap into.&lt;/p&gt;

&lt;p&gt;And in the end, our goal is to look something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/3b805ee5-3552-4a64-8c78-75f6ec8dcf7a/2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;in response to something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/3b805ee5-3552-4a64-8c78-75f6ec8dcf7a/3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s the plan. Let’s figure out how to execute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A motivation for Huginn&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is all just some basic HTTP requests and data extraction! I can write something working in a couple hours, I don’t need Huginn!&lt;/p&gt;

  &lt;p&gt;Some Developer before attempting this, probably.  (2018)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you had this reaction, then read the requirements below. Explicit and implicit requirements are dissected and include what complications might arise:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;You need to make sure you only pull new posts&lt;/strong&gt; – that means you need some kind of in-memory storage at the very minimum and need to write some code to track the &lt;em&gt;ID&lt;/em&gt; and only serve up in new ones into a pool. If you want fault tolerance (if your app crashes, you would lose all events) then you might even need something like &lt;em&gt;Redis&lt;/em&gt; running in persistent mode. Things just got a bit hairier.&lt;/li&gt;
  &lt;li&gt;**If you want to do more than one type of alert, say, SlickDeals afterwards ** … then you need generalized event types. If you need more than one type of notification backend, you need to implement that.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;You need to implement some kind of reliable scheduler,  visualizer if you want them&lt;/strong&gt; This can be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cron&lt;/code&gt; but now you have to manage &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cron&lt;/code&gt; jobs.&lt;/li&gt;
  &lt;li&gt;You need logging of events for debugging.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;You need to integrate with a notification service&lt;/strong&gt; – this one is bit easier. Most languages have something to do this. For example. here’s one for &lt;a href=&quot;https://www.npmjs.com/package/pushbullet&quot;&gt;Node&lt;/a&gt;. But you also have to write our own fault tolerance.&lt;/li&gt;
  &lt;li&gt;If you want to use this data for other things, you need to make sure you create a generalized abstraction over top to query the data for other purposes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I mean, it’s not that you &lt;em&gt;can’t&lt;/em&gt; write all that but it’s a matter of if you should or need to. Setting this all up can easily take a few hours if you’ve never done it before and even an experienced developer is going to take a bit – and then you &lt;em&gt;have to deploy it&lt;/em&gt;. So, that means some kind of deployment technology needed.&lt;/p&gt;

&lt;p&gt;Maybe read on first and then come back and see if this is still appealing.&lt;/p&gt;

&lt;h2 id=&quot;getting-the-data-into-our-stream&quot;&gt;Getting the data into our stream&lt;/h2&gt;

&lt;p&gt;Huginn uses things called &lt;em&gt;events&lt;/em&gt; to pool data into a queue that can be processed by other agents. As a first step, let’s take a look at using this &lt;a href=&quot;http://forums.redflagdeals.com/feed/forum/9&quot;&gt;RSS Feed&lt;/a&gt;  to get out information.&lt;/p&gt;

&lt;p&gt;We’ll create a new RSS Agent and set it up like so:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/3b805ee5-3552-4a64-8c78-75f6ec8dcf7a/4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A few explanations in order:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: This is just a way of grouping agents together in Huginn. We’re using the default one for now but it would be a good idea to group them later on so you know how they all interact with each other.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Keep events&lt;/strong&gt;: We’ve picked 3 days but even less is fine. We’re just using this for triggers which are near real-time, remember. However, if we had other plans for this data more would be in order.&lt;/li&gt;
  &lt;li&gt;**Schedule **: 1 minute might be a bit eager, but remember we’d rather generate a bit of extra traffic than miss a deal.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Expected days&lt;/strong&gt;: You can read more on the official docs –  but this is how Huginn will notify us of broken agents. i.e: we expect data to come in here at least somewhat frequent or something is not right.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that saved, go ahead and run it and you should generate some activities in the events stream:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/3b805ee5-3552-4a64-8c78-75f6ec8dcf7a/5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Perfect, we have something that now runs and gets the data and serves it up for us. Let’s get a filter in front of that now.&lt;/p&gt;

&lt;h1 id=&quot;filtering-the-data-using-regular-expressions&quot;&gt;Filtering the data using regular expressions&lt;/h1&gt;

&lt;p&gt;We now have our own copy of the data using RSS. It could be through scraping the HTML using the scraper agent, too, though. It does not matter – what does is that we now have &lt;em&gt;events&lt;/em&gt;. We don’t want to send every &lt;em&gt;Hot Deal&lt;/em&gt; to our devices since that’s just going to result in too many posts. Probably at least three dozen per day, minimum and we don’t want to have to keep checking these.&lt;/p&gt;

&lt;p&gt;First, &lt;a href=&quot;https://www.google.ca/search?q=price+error+redflagdeals&amp;amp;oq=price+error+&amp;amp;aqs=chrome.0.69i59j69i60j69i57j0l2j69i61.1261j0j7&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&quot;&gt;let’s do a little bit of research using Google to figure out what we can&lt;/a&gt; expect.&lt;/p&gt;

&lt;p&gt;I’ll save you the trouble if you don’t want to search yourself through pages of data and let you know what I came up with:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The &lt;a href=&quot;https://forums.redflagdeals.com/amazon-ca-dead-price-error-beyerdynamic-aventho-wireless-103-65-2177380/&quot;&gt;title often contains&lt;/a&gt;: &lt;em&gt;price error&lt;/em&gt;, &lt;em&gt;price mistake&lt;/em&gt; or just the word &lt;em&gt;error&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;The title often contains the word &lt;em&gt;dead&lt;/em&gt; if the &lt;a href=&quot;https://forums.redflagdeals.com/amazon-ca-oculus-rift-price-error-dead-price-has-been-fixed-2189410/&quot;&gt;deal is dead&lt;/a&gt;. Or &lt;em&gt;expired&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://forums.redflagdeals.com/staples-hot-google-pixel-buds-29-99-2161090/9/&quot;&gt;People sometimes use&lt;/a&gt; “HOT” as well when a really good deal is up – sometimes this is not a price error at first but people discover it is later.&lt;/li&gt;
  &lt;li&gt;People sometimes exaggerate these words as hinted about before – so just searching for “HOT” as a literal is is likely to miss things, since it may be &lt;em&gt;!!HOOOOT!!!&lt;/em&gt; or some variant.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s get a corpus of data going and then try writing some Regular Expressions to match the examples we want. Using a basic script, we can get some of it out:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cheerio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;cheerio&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./file.xml&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cheerio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&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;xmlMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;// Get all the title tags&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$titles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$titles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$titles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;each&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;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;titleNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$titleNode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$titleNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(There’s probably a way to do this in Shell as well – but this got me the results in just a few minutes, so good enough)&lt;/p&gt;

&lt;p&gt;Our next step is then to write a regular expression that can match as many of the items in the corpus as we can without tripping too many false negatives. Consider the following regular expression below as an example:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/3b805ee5-3552-4a64-8c78-75f6ec8dcf7a/6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-perl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;price&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;nv&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mistake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;*o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;*t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gmi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It covers a few of the cases here without triggering the false positives on the items above. There’s a few items in the list I might personally be interested in (the pre-order for that video card…) but let’s keep our task focused so that we don’t have scope creep.&lt;/p&gt;

&lt;p&gt;With this basic regular expression (in practice, I use a slightly more complicated one but this is pretty good) we now have a good basis to filter against. In practice, we could tweak this is a bit more but it gets us a lot of value with low effort (this cruddy regular expression only took 4 minutes to write – yay!)&lt;/p&gt;

&lt;p&gt;Creating a new &lt;em&gt;Trigger Agent&lt;/em&gt; with the following configuration would give us what we want:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/3b805ee5-3552-4a64-8c78-75f6ec8dcf7a/7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(&lt;em&gt;Trigger Agents&lt;/em&gt; allow us to filter data and then generate other events based on these. You can think of the raw data as the &lt;em&gt;base fact&lt;/em&gt; and then this is a refinement on those facts. Specifically, it generates additional events we are interested in real time information for. We could still use the raw data for other things since it does not transform it but rather makes a new event for consumption – for example, a daily digest of all the &lt;em&gt;Hot Deals&lt;/em&gt; for the day at the end of a day.)&lt;/p&gt;

&lt;p&gt;You can use the “Dry Run” functionality to inject some test data to verify it works – but our corpus data should at least give us some confidence. If you wanted to take this to another level, you could have a small toy app that had two test fixtures – valid and invalid and have a script that runs the regex against each test case when modifying it to make sure you don’t have any that are invalid. For now, my regular expression has been running so I have no need to modify it…&lt;/p&gt;

&lt;p&gt;Time to get that info into the cloud.&lt;/p&gt;

&lt;h1 id=&quot;notifying-yourself-when-it-happens&quot;&gt;Notifying yourself when it happens&lt;/h1&gt;

&lt;p&gt;The last part is the easiest part – we just need to get those events we generated into our &lt;em&gt;Pushbullet&lt;/em&gt; devices. We can go ahead and create &lt;em&gt;Pushbullet Agent&lt;/em&gt; and make sure you get an &lt;a href=&quot;https://www.pushbullet.com/#settings&quot;&gt;API key from them&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can configure it similar to below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/3b805ee5-3552-4a64-8c78-75f6ec8dcf7a/8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;.. and you do need to fill in your API key. After that, you should have everything you need.  Since this is a simple dumb relay system, it’s also why I’m comfortable introducing a cloud dependency here. It could easily be swapped for anything else since it lives at the end of the flow.&lt;/p&gt;

&lt;h1 id=&quot;profit&quot;&gt;Profit???&lt;/h1&gt;

&lt;p&gt;That’s it! With that, we should now have real-time updates to our devices like we showed above. It all works but you don’t have to take my word for it – you can create a &lt;em&gt;manual agent&lt;/em&gt; and then trigger some events to watch the entire thing work together. You could also try finding a deal and posting it as well and that would also trigger your new test.&lt;/p&gt;

&lt;p&gt;With this, we now have completely automated the process of getting notified of price errors and other interesting deals. I’ve been running a variant of this for a while and scooped up at least a few things such as &lt;a href=&quot;https://forums.redflagdeals.com/best-buy-update-google-home-mini-now-49-2184059/&quot;&gt;Google Home Mini’s for $30 to due a coupon error&lt;/a&gt;. The original thread title used to say &lt;strong&gt;HOT&lt;/strong&gt; but it was modified since the deal has been expired. It’s not perfect, so I often actually combine this with digests at the end of the day to comb through “not error” things but things I still may be interested in.&lt;/p&gt;

&lt;p&gt;Happy savings &amp;amp; hope you learned something!&lt;/p&gt;

&lt;p&gt;Got a better idea for a more comprehensive regular expression? Are there better platforms? Just want to say hi? Let me know in the comments.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Setting up Huginn on unRAID</title>
   <link href="http://vaughanhilts.me/blog/2018/04/26/setting-up-huggins-on-unraid-for-automation.html"/>
   <updated>2018-04-26T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2018/04/26/setting-up-huggins-on-unraid-for-automation</id>
   <content type="html">&lt;p&gt;I recently became intrigued with using Huggin for a few automation tasks I had been doing manually up to this point. However, it looks like nobody to this point had bothered to really post how to set this up with unRAID. It was not too tricky since you can use &lt;strong&gt;Docker&lt;/strong&gt; with unRAID but there were a few things that slowed me down.&lt;/p&gt;

&lt;p&gt;I’m documenting them here for anyone else who wants to do this, you can hopefully be saved some time.&lt;/p&gt;

&lt;h2 id=&quot;get-an-unraid-huginn-template&quot;&gt;Get an unRAID Huginn template&lt;/h2&gt;

&lt;p&gt;As the first step, you’re going to to need a template to do this since unRAID makes use of Docker templates for setting up things quickly. I created one you can use &lt;a href=&quot;https://github.com/hilts-vaughan/unraid-docker-templates/tree/master/unraid-hilts-vaughan-templates&quot;&gt;right here&lt;/a&gt; if you don’t want to create your own. That template assumes you have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appdata&lt;/code&gt; mount point already existed for your other applications. If you don’t have one already (this is your first docker app in unRAID) then &lt;a href=&quot;https://lime-technology.com/forums/topic/55263-how-should-i-set-up-my-appdata-share/&quot;&gt;you can read this to get more info&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are using my template, you can follow the below directions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Go to the “Docker” tab in the unRAID interface&lt;/li&gt;
  &lt;li&gt;In the “Template Repositories” at the bottom of the page, add my repository which is at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://github.com/hilts-vaughan/unraid-docker-templates/tree/master/unraid-hilts-vaughan-templates&lt;/code&gt; and then hit “Save”&lt;/li&gt;
  &lt;li&gt;Click “Add Container” which is a button on the Docker Page&lt;/li&gt;
  &lt;li&gt;Select my template from the dropdown  above, to be prompted with something like this:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/8c060306-fd8a-45a5-8736-2cb77c089c79/1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You can accept the defaults and let it pull down – which should give you a working instance once it comes up at (by default) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tower:3000/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Login with the default credentials of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;password&lt;/code&gt; – make sure you have saved these.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;getting-email-working&quot;&gt;Getting email working&lt;/h2&gt;

&lt;p&gt;I had to do a couple things in unRAID land to get this working properly as it was not working out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuring the user in Huginn&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Once signed in, head to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://tower:3000/users/edit&lt;/code&gt; (you can change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tower&lt;/code&gt; if you changed the name of your unRAID box)&lt;/li&gt;
  &lt;li&gt;You should see no e-mail in the box – so you can configure one, like so:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/8c060306-fd8a-45a5-8736-2cb77c089c79/2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then, you can hit “Update”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuring unRAID with environment variables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you plan on using GMail for the e-mail in Huginn, you may want to read the below section first. To configure environment variables, and email specifically for Huginn, you can use the following steps at the time of publication (tested for GMail):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Go to your “Docker” tab&lt;/li&gt;
  &lt;li&gt;Click edit on the image&lt;/li&gt;
  &lt;li&gt;Using “Add another Path, Port, Variable or Device” at the bottom of the page, configure something like this:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/8c060306-fd8a-45a5-8736-2cb77c089c79/3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/8c060306-fd8a-45a5-8736-2cb77c089c79/4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you want to configure anything else at this point, you can &lt;a href=&quot;https://github.com/huginn/huginn/blob/master/.env.example&quot;&gt;refer to this environment variable documentation to do so&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuring GMail&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are using GMail, there are additional steps go through to generate something secure and that is usable for Huginn. I was getting some interesting errors like:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;huginn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rbuf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fill&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… and authentication errors among other things. In practice, if you plan on using this for any amount of time I would advise you sign up for something like Amazon SES or something with a very basic (or free) SMTP server you can use and then have them send your emails for you. This will give you a layer of insulation against having your e-mail credentials served.&lt;/p&gt;

&lt;p&gt;Otherwise, do this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://support.google.com/accounts/answer/185839?hl=en&quot;&gt;Enable two factor authentication&lt;/a&gt; for your GMail account. This is not strictly needed but this guide will use it since it allows you to generate app specific passwords which are needed to keep your unRAID box from knowing your actual credentials.&lt;/li&gt;
  &lt;li&gt;Generate an &lt;a href=&quot;https://support.google.com/accounts/answer/185833?hl=en&quot;&gt;app password&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Use this password in the above steps, where it says “PASSWORD” use this disposable password. It’s slightly more secure and lets you bypass some of the “Use less secure apps” mode that some articles talk about. &lt;strong&gt;Do not use this mode if you can help it. It’s insecure, as the name implies.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Testing it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To test this, I would just run a couple of the default agents and see if it works. The easiest way to do this is:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Run the &lt;a href=&quot;http://tower:3000/agents/6?return=%2Fagents&quot;&gt;iTunes Trailer Source&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Run the &lt;a href=&quot;http://tower:3000/agents/3?return=%2Fagents&quot;&gt;Afternoon Digest&lt;/a&gt; agent&lt;/li&gt;
  &lt;li&gt;Check if your e-mail was sent successfully&lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;p&gt;That should be it. I hope this saves you a couple hours. I wish someone had told me about a couple of these things when I started (and that a unRAID docker template existed!)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Why are we still not enforcing our invariants in 2018?</title>
   <link href="http://vaughanhilts.me/2018/04/13/why-we-still-not-enforce-our-invariants-even-in-large-libraries.html"/>
   <updated>2018-04-13T03:11:00+00:00</updated>
   <id>http://vaughanhilts.me/2018/04/13/why-we-still-not-enforce-our-invariants-even-in-large-libraries</id>
   <content type="html">&lt;p&gt;&lt;em&gt;This post is a work in progress; it’s mostly a scratchpad for my thoughts&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;motivation--why-you-should-read-on&quot;&gt;Motivation &amp;amp; why you should read on&lt;/h1&gt;

&lt;p&gt;Before you read much more, here’s a summary of what you can expect:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;At least in some circles, we need to figure out how to enforce the invariants of our code better&lt;/li&gt;
  &lt;li&gt;Often, libraries (even very popular ones) do this very badly. We can do better – and it’s not that hard to do. It might just require some education on the tools available to us.&lt;/li&gt;
  &lt;li&gt;We’re going to look at some real case studies of where poorly enforced invariants cost me real time. That’s real money for someone.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;We’re going to look at why you might as well document assumptions and decisions as hard enforced constraints&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;preface&quot;&gt;Preface&lt;/h1&gt;

&lt;p&gt;It’s no secret that I work a lot in JavaScript. If you look at my GitHub profile, you will find no shortage of projects there that I’ve written in JavaScript and I’ve been writing it professionally for a number of years. Let that be a preface – I have worked in .NET, Java and other languages as well but I want it to be known that this very well might be a rant against the state of Javascript. I definitely know some languages handle this better&lt;/p&gt;

&lt;p&gt;I…&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Have written many commercial enterprise applications and features in it&lt;/li&gt;
  &lt;li&gt;Used a ton of libraries, frameworks, APIs and the like that interact with the ecosystem as whole in it&lt;/li&gt;
  &lt;li&gt;… and I’m a huge shill for static type systems since I come from a .NET background before delving into the web&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, I’ve worked with other peoples code a lot. I’ve invoked a lot of API(s). I’ve poked and invoked tons of external systems. I’ve played the integration system.&lt;/p&gt;

&lt;p&gt;More importantly, though:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I’ve also written a lot of code in .NET (quite a bit of it, I wrote a few games, game servers, and a couple non-trivial back-end web applications in .NET Core as well)&lt;/li&gt;
  &lt;li&gt;I’ve been on the end of being frustrated by poor API(s) that suck a bunch of my time as I try and debug what I did wrong (or the library in some cases is not documented properly)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last point is the one I want to focus on today since it’s probably wasted hundreds of hours over my life. Specifically, I want to talk about poor type systems, invariants, why we don’t enforce them, why we should, and how we can do better even in languages such as JavaScript that don’t support them.&lt;/p&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;If you already know about invariants, I implore you to skip this. It’s boring stuff. You can skip to the examples below of insanity.&lt;/strong&gt; The definitions below are far from Academic and they’re drawn from experience. Some places, such as the &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts#invariants&quot;&gt;Code Contracts&lt;/a&gt; documentation will point out the difference between &lt;em&gt;Preconditions&lt;/em&gt;, &lt;em&gt;Post Conditions&lt;/em&gt;, and &lt;em&gt;Invariants&lt;/em&gt;. I am not interested in such differences for the purpose of this post: I just care about valid state, all the way through.&lt;/p&gt;

&lt;p&gt;I don’t want this post to be too long but I do want to spell out what it means to violate an invariant. Invariants are things we expect to be true about the lifetime of some unit of encapsulation. There are more advanced definitions but there are some simple examples we can derive. We’ll talk about functions since they are applicable to all languages without needing to worry about the specifics of OOP, Prototype Inheritance, Functional etc. &lt;em&gt;Most&lt;/em&gt; languages have functions. Not all of them have classes – and it’s the smallest unit of work we can deal with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A word on validation vs invariants&lt;/strong&gt;: Validation can definitely enforce invariants, preconditions and more. However, often for a piece of code it might be too late. Validation usually implies some kind of deferred handling – which is sometimes &lt;em&gt;too late&lt;/em&gt; as we will explore after the &lt;em&gt;Introduction&lt;/em&gt;. We are more interested in immediately, observable&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Nullability and buffer lengths.&lt;/strong&gt; Let’s talk about these since they’re so easy to pick on. Validate your buffer lengths and the optionality of something. A large portion of the world does this now but still we have a ton of exploits involving these on a daily basis. Still, modern languages such as Rust, Swift and friends make this very hard to mess up. We’re moving forward.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Proper data type.&lt;/strong&gt; The most basic (and arguably, this is a loose definition but it should be easily digestible) is validating your data types for a parameter into a given function. If you have an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add&lt;/code&gt; function, you probably want it to take some integers. It might be an array, two integers, a variable length splat of integers (if your language supports such a construct) or any other set of parameters. However, the important thing is it’s decided what is supported and what is not. If we are to enforce this, we enforce the type.&lt;/p&gt;

    &lt;p&gt;There are a couple ways this is done. Static typing or run-time assertions are just two possible options.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Single Domain invariants&lt;/strong&gt;. I classify these as things that are specific to something about the domain of how a piece of data is being used. A simple example is &lt;em&gt;Percentages&lt;/em&gt;. If you have some floating point number (or even fixed point arithmetic operation) that you need to bound between some values (probably 0 and 100, if you are dealing with standard ones) you should go ahead and apply some invariants here. This means the value should not exceed 100 or be less than 100.&lt;/p&gt;

    &lt;p&gt;There are a few ways of accomplishing this. For example, Ada has a &lt;a href=&quot;https://en.wikibooks.org/wiki/Ada_Programming/Types/range&quot;&gt;range&lt;/a&gt; construct you can use to create bounded integer value. In Javascript, the only choice we might have is to write something like this:&lt;/p&gt;

    &lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&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;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;OutOfRangeError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;The value given &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;was out of range&lt;/span&gt;&lt;span class=&quot;dl&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;/div&gt;    &lt;/div&gt;

    &lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts&quot;&gt;Code Contracts&lt;/a&gt; for .NET provides something similar and a bit more automated. We’re not going to dive into the specifics here.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;**Class invariants. ** This is a classical OOP type – we touch upon it quickly here just because so many people are used to OOP. &lt;a href=&quot;https://en.wikipedia.org/wiki/Class_invariant&quot;&gt;Wikipedia&lt;/a&gt; has a pretty good article on this but the gist is &lt;em&gt;things that must be preserved across the larger unit of works lifetime&lt;/em&gt;. For example, if you had a class that held a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startDate&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;endDate&lt;/code&gt; and it should enforce that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startDate&lt;/code&gt; should always be before &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;endDate&lt;/code&gt; (the reverse is true, too) but you exposed two setters, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setStartDate&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setEndDate&lt;/code&gt; – then you would want to make sure this rule held and would need to examine both pieces of state in most cases.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an aside, there a lot of different ways of tackling invariants. Some design methodology (looking at you &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-driven_design&quot;&gt;Domain Driven Design&lt;/a&gt; actually gives some recommendations on how to do this depending on who you ask. We’re going to focus more on why you should do this more than &lt;em&gt;how&lt;/em&gt; you should do it and how it can save a ton of time. At the end of the day, we’re going to be talking about &lt;strong&gt;documenting your assumptions in code.&lt;/strong&gt; This might sound obvious but let’s look at what happens when we don’t do these things with some real code that has cost people time and money.&lt;/p&gt;

&lt;p&gt;We can look at solutions later, I find the problems will convince people to go “Ooo, I’ve experienced that before! I thought this was just normal”.&lt;/p&gt;

&lt;h1 id=&quot;the-cost-of-assuming-without-documenting&quot;&gt;The cost of assuming without documenting&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Buffer overflows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first kind of assumptions that we don’t validate that cost us all money that we encounter all the time is the classic &lt;a href=&quot;https://en.wikipedia.org/wiki/Buffer_overflow&quot;&gt;buffer overflow&lt;/a&gt;. Sure, this can only happen in a subset of languages in most circumstances but it illustrates a good example of where your bad assumptions can cost real money. Let’s look at all the damage buffer overflows have caused over the years. In no particular order:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://arstechnica.com/gaming/2018/04/the-unpatchable-exploit-that-makes-every-current-nintendo-switch-hackable/&quot;&gt;The “unpatchable” exploit that makes every current Nintendo Switch hackable&lt;/a&gt; - 2018 (details unclear, but definitely some kind of overflow attack)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://games.slashdot.org/story/05/09/24/1917246/buffer-overflow-found-in-psp-firmware-v20&quot;&gt;Buffer Overflow Found in PSP Firmware v2.0&lt;/a&gt; (this wasn’t the last either…)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cturt.github.io/ps4.html&quot;&gt;The PS4 was partially comprimised through buffer overflow via Webkit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These focus on game consoles and they are only some of the most basic examples. I talk about them since a lot of them will and did in the past open the door to piracy. No matter your stance, the impact is not zero on the industry. Money is spent on legal departments, patching, PR, and more handling these things.&lt;/p&gt;

&lt;p&gt;Depending on the systems, not handling some basic checks like this cost a ton.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Null pointers, null references, and friends&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There’s a lot of things wrong with null pointers as we have learned over the years. There’s some good articles on-line (&lt;a href=&quot;https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/&quot;&gt;here’s a decent one&lt;/a&gt;) that explain why this is the case and &lt;a href=&quot;https://en.wikipedia.org/wiki/Tony_Hoare&quot;&gt;Tony Hoare&lt;/a&gt; himself even indicates that:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.&lt;/p&gt;

  &lt;p&gt;Tony Hoare, inventor of ALGOL W.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Oftentimes (arguably always) these just occur because something was assigned &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; (or defaulted to) when people assumed they would not be. Simple to validate. Not often done. Tons of damage. Poorly handled null references can take crudely designed systems down. The most robust ones will behave wrongly.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://blogs.oracle.com/linux/much-ado-about-null%3a-exploiting-a-kernel-null-dereference-v2&quot;&gt;This is an interest read on gaining root with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;**OK, extreme examples, commonly known problems aside, let’s talk about the other large problems. **&lt;/p&gt;

&lt;p&gt;Buffer exploits. Null pointers. Improper authentication. All bad things. These are bad from &lt;em&gt;security&lt;/em&gt; but for a typical CRUD app running in your browser, maybe no big deal. But there’s a larger story here.&lt;/p&gt;

&lt;h1 id=&quot;what-can-we-do-about-it&quot;&gt;What can we do about it?&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Design good APIs that easy to use – but this is just a first step.&lt;/li&gt;
  &lt;li&gt;Document your assumptions and fail fast when someone breaks the promise&lt;/li&gt;
  &lt;li&gt;Use languages with good support for these invariants&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;a-word-on-tests&quot;&gt;A word on tests&lt;/h1&gt;

&lt;p&gt;I just wanted to make this a section on it’s own really fast since I often get this argument. Specifically, I want to attack Unit Tests. Often, I will get the argument: &lt;em&gt;“The tests pass – and the tests do the validation and document the values that are valid. If you want to figure out how to use it, you can look there. “&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I just want to make a few arguments. If you disagree, this might not be the article for you and that’s OK.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;If your tests are just testing known, good input, but do not cover if something is handling bad data (in the absence of a proper type checker at the most basic level) then you still have not solved the problem with users of your API who misuse it without realizing. That leads me into…&lt;/li&gt;
  &lt;li&gt;Users do not read your tests. They read your documentation, if you are lucky. In a lot of cases, the documentation either does not exist, is old, incomplete, does not work properly, or worse: it’s incorrect. Your code will not be incorrect (hopefully)&lt;/li&gt;
  &lt;li&gt;In some languages with a good enough type system, tests that probe the behavior of some these are actually just brittle and harmful. It does not excuse writing good code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To be continued?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Automating adding missing require statements for globals using jscodeshift</title>
   <link href="http://vaughanhilts.me/2018/04/13/automating-adding-missing-require-statements-for-globals-using-jscodeshift.html"/>
   <updated>2018-04-13T03:11:00+00:00</updated>
   <id>http://vaughanhilts.me/2018/04/13/automating-adding-missing-require-statements-for-globals-using-jscodeshift</id>
   <content type="html">&lt;p&gt;Sometimes, working on some older legacy codebases they are using some Frankenstein build systems they created in house or a port to something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gulp&lt;/code&gt;, especially in some older open source projects. As part of getting them over to something else and to make use of new tech. such as “module bundlers”, part of the challenge is to make sure all imports are valid and dependencies are clear. Unfortunately, in some of these projects this is not made clear and it’s hard to tell.&lt;/p&gt;

&lt;p&gt;Generally, you would add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; statements to let developers know you are importing some code for usage. In some cases, the system is setup with some kind of loader already such as RequireJS and it’s just being used improperly. For example, take the following pieces of code:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	   &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&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;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// set the view to something between 0-10&lt;/span&gt;
	   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&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;/div&gt;&lt;/div&gt;

&lt;p&gt;This has a dependency on something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lodash&lt;/code&gt; … or maybe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;underscore&lt;/code&gt;.  If the code base just uses one, then it’s fine to be able to just import it and move on, if you know what it is. In this case, this is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lodash&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;So, what if we have hundreds of files like this? We can analyze the source code and make good guesses.&lt;/p&gt;

&lt;h1 id=&quot;use-a-regular-expression-to-search-the-source-code-then-add-them&quot;&gt;Use a regular expression to search the source code, then add them…?&lt;/h1&gt;

&lt;p&gt;If we were going for quick and easy, we might be tempted to use a regular expression. This would work but for things like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lodash&lt;/code&gt; which uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;, there’s a few problems with that making it hard to identify when it’s actually in use:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You could have something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_(items)&lt;/code&gt; to wrap the entire collection for example, so you cannot just search for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_.&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;.. but because of that, you can’t just search for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt; either since you’re going to get way too many hits and next thing you know – every module depends on this! Might as well have just had a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global.js&lt;/code&gt; and had it declare it.&lt;/li&gt;
  &lt;li&gt;Even if you can write something to look out for the various forms, such as combing something like this:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/9dda9d4d-0de5-441d-849a-e32d10fa35db/regexp.png&quot; alt=&quot;/assets/9dda9d4d-0de5-441d-849a-e32d10fa35db/regexp.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;… you immediately notice comments are a problem. You could probably add something to parse the line as well and make sure it’s not a comment. I share the same sentiment as &lt;a href=&quot;https://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/&quot;&gt;Jeff Atwood&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I love regular expressions. No, I’m not sure you understand: &lt;a href=&quot;http://blog.codinghorror.com/if-you-like-regular-expressions-so-much-why-dont-you-marry-them/&quot;&gt;I really &lt;em&gt;love&lt;/em&gt; regular expressions&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;… but that blog post summarizes what’s happening:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Guess we should go fix them by hand, huh? Or should we charge on ahead? Or if you want, you play with the &lt;a href=&quot;https://regex101.com/r/pPszCt/1&quot;&gt;regular expression here first from above&lt;/a&gt;. Then do it for every single library… :(&lt;/p&gt;

&lt;p&gt;If you eventually keep patching up cases, to succeed, you end up out of necessity with a parser. So, then…&lt;/p&gt;

&lt;h1 id=&quot;using-a-parser-such-as-babylon-esprima-or-other-friends&quot;&gt;Using a parser such as Babylon, esprima or other friends&lt;/h1&gt;

&lt;p&gt;You can read a lot more about projects such as &lt;a href=&quot;https://github.com/babel/babel/tree/master/packages/babylon&quot;&gt;Babylon&lt;/a&gt; and &lt;a href=&quot;https://github.com/jquery/esprima&quot;&gt;esprima&lt;/a&gt; as you would like but there’s just a couple things you need to know for this blog post:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;They parse a chunk of code into syntax elements that make sense for programatic consumption – this means being able to differentiate between say, a comment, an assignment (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const foo = bar()&lt;/code&gt;), statements (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;something&lt;/code&gt;) and just other things in Javascript land.&lt;/li&gt;
  &lt;li&gt;… and you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jscodeshift&lt;/code&gt; plus one of the parsers to manipulate the &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_syntax_tree&quot;&gt;Abstract Syntax Tree&lt;/a&gt; they produce in order to suit your needs using Javascript scripts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, let’s recap:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;We can find the difference between comments, statements, assignments, etc. This means we can tell apart a &lt;em&gt;real&lt;/em&gt; usage of a token aside from a supposed usage.&lt;/li&gt;
  &lt;li&gt;We can script it and programming languages &lt;a href=&quot;https://softwareengineering.stackexchange.com/questions/165740/are-regular-expressions-a-programming-language&quot;&gt;are generally Turing Complete, where Regular Expressions are not&lt;/a&gt;. This means we can edit the AST as well, such as adding these require statements.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is enough for us to be able to parse out what is being used. So, let’s get our hands dirty and figure out how to do this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jscodeshift&lt;/code&gt; – &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install -g jscodeshift&lt;/code&gt; if you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Write a transform to do this, and then run it against files in your code&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;how-to-get-acquainted&quot;&gt;How to get acquainted?&lt;/h2&gt;

&lt;p&gt;There’s a great site called &lt;a href=&quot;https://astexplorer.net/&quot;&gt;ASTExplorer&lt;/a&gt; we’re going to use to get used to things. We’ll be using it to explore the code snippet from above. A couple housekeeping items…&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Make sure your language is set to “Javascript”&lt;/li&gt;
  &lt;li&gt;Parser should be set to “Babylon” or something similar – since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jscodeshift&lt;/code&gt; uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;babel&lt;/code&gt; parser by default.&lt;/li&gt;
  &lt;li&gt;Transform tool should be set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jscodeshift&lt;/code&gt; – that one should be obvious as to why.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you load up your snippet code, then you should get something like this;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/9dda9d4d-0de5-441d-849a-e32d10fa35db/ast.png&quot; alt=&quot;/assets/9dda9d4d-0de5-441d-849a-e32d10fa35db/ast.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You will notice I have some code that logs out &lt;em&gt;identifiers&lt;/em&gt;. First, let’s define what an identifier is and then let’s look at why we care about them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is an &lt;em&gt;identifier&lt;/em&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Identifiers are value pairs / nodes that reference or define the name of a node.&lt;/em&gt; Often, they are the names of &lt;em&gt;expressions, statements, class names, etc&lt;/em&gt; However, they are only for code. They have a couple important properties we care about:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;They don’t include any comments, which is undesirable for our case&lt;/li&gt;
  &lt;li&gt;They’re entire words, separated by delimiters defined by the language syntax, making it easier to tell them apart, for example: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Backbone.View&lt;/code&gt; is tokenized into something like:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Backbone&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;They can be boiled down into a list of identifiers that is nice and easy to iterate over and then map to statements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;So what about that output?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We get an output that looks something like:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;A
VM120:14 render
VM120:14 &lt;span class=&quot;nv&quot;&gt;$el&lt;/span&gt;
VM120:14 html
VM120:14 _
VM120:14 random
VM120:14 value_case
VM120:14 _
VM120:14 items
VM120:14 Backbone
VM120:14 View
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For the sake of argument, we can say this output is exactly what we need, since it parsed out the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt; and other identifiers we needed. If you add a comment with something else, like perhaps:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// $('div')&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;you will notice that nothing changes in the log changes. There are a couple flaws to this approach that aggressively would import more than require in some of the cases for some global tokens, but our goal is not perfect, just to get us most of the way there.&lt;/p&gt;

&lt;p&gt;With token info in hand, there’s only one a couple things left to do. Let’s outline our plan of attack:&lt;/p&gt;

&lt;h2 id=&quot;creating-a-script-to-import-something-like-lodash-that-was-being-used-globally&quot;&gt;Creating a script to import something like lodash that was being used globally&lt;/h2&gt;

&lt;p&gt;We can start with something simple, given our previous input:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	   &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&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;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// set the view to something between 0-10&lt;/span&gt;
	   &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value_case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		
       &lt;span class=&quot;c1&quot;&gt;// and then something here _(items) .. and then something here...		&lt;/span&gt;
	   &lt;span class=&quot;c1&quot;&gt;// and then $&lt;/span&gt;
	   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&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;/div&gt;&lt;/div&gt;

&lt;p&gt;We want something like this:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;underscore&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Backbone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;View&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	   &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$el&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&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;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// set the view to something between 0-10&lt;/span&gt;
	   &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value_case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		
       &lt;span class=&quot;c1&quot;&gt;// and then something here _(items) .. and then something here...		&lt;/span&gt;
	   &lt;span class=&quot;c1&quot;&gt;// and then $&lt;/span&gt;
	   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&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;/div&gt;&lt;/div&gt;

&lt;p&gt;We will need a couple things here:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A way of parsing out identifiers, which we already looked at.&lt;/li&gt;
  &lt;li&gt;A way of injecting require statements into the code&lt;/li&gt;
  &lt;li&gt;A way of checking if a require statement is already there, so we don’t duplicate it (this is optional – you can always run something like &lt;a href=&quot;https://github.com/cpojer/js-codemod/blob/master/transforms/rm-requires.js&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rm-requires&lt;/code&gt; after&lt;/a&gt; to clean this up)&lt;/li&gt;
  &lt;li&gt;A way of outputting the source code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;A way of parsing out identifiers, which we already looked at.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is already complete – we looked at it above. We know how to load in a source code file and then loop over each identifier.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A way of injecting require statements into the code&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There’s a few ways of doing this. There’s &lt;a href=&quot;https://www.npmjs.com/package/jscodeshift-imports&quot;&gt;this package&lt;/a&gt; that promises you can do this. However, for something simple we can do something like this instead assuming we want them at the top of the file:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;unshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;requireStatement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is basically getting the current file and then adding a line to the top.&lt;/p&gt;

&lt;p&gt;Some ASTs might have something to do this with a specific node type, for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ts-simple-ast&lt;/code&gt; for &lt;a href=&quot;https://dsherret.github.io/ts-simple-ast/details/imports&quot;&gt;TypeScript&lt;/a&gt; has this, but the parser we’re using does not for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt; statements, at least. After all, the only standardized module system is “ES2015 Modules” and if you were using those, you probably would not be in this problem.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A way of outputting the source code&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is built-in if you use the CLI tool – since it modifies files in place. You could also go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdout&lt;/code&gt; as well, which is handy if you are doing dry runs. You just need to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toSource&lt;/code&gt; on the end of your fluent API.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Checking for duplicates&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since the above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;body&lt;/code&gt; variable from the injecting step is an array, we can just use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;includes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Plan of attack&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That should be everything. Now:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Iterate over all identifiers&lt;/li&gt;
  &lt;li&gt;Finds one matching known problematic globals&lt;/li&gt;
  &lt;li&gt;Inject a require statements, checking if it already exists&lt;/li&gt;
  &lt;li&gt;.. and then terminate and print out the source code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Putting it all together, you get something like this&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;containsStatementAlready&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;nx&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;statement&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;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;statement&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;// Press ctrl+space for code completion&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transformer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jscodeshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;builder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;source&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;builder&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Identifier&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;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;statement&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_ - require('underscore');&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;containsStatementAlready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;statement&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;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;unshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;statement&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;nx&quot;&gt;toSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this, you get the output we wanted when run in &lt;strong&gt;ASTExplorer&lt;/strong&gt;! Pretty simple and you can automate most of this, with some manual code review after to make sure things weren’t added in error. Don’t forget to save this as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.js&lt;/code&gt; script and then use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jscodeshift&lt;/code&gt; to run this against as a sample file locally as well – that’s where the real power comes and where you can dot this en-mass.&lt;/p&gt;

&lt;p&gt;The best part of JSCodeShift is it’s just Javascript – so you’re scripting your automation. If wanted to, you can automate entire sets of globals using something as simple as a hash map (read: Javascript Object for simplicity) I’ll leave running this against your entire code-base (a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zsh&lt;/code&gt; glob will probably do the trick…) and for multiple global tokens an exercise.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/hilts-vaughan/jscodeshift-require-globals&quot;&gt;I actually did multiple tokens right here if you need something now.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m not sure this would be ready for a large project but it certainly should get you on the way. Most importantly, we learned a bit about what we can do with parsing an actual language that becomes a lot harder with something like a simple Regular Expression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where does this fail?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There is going to be partial matches, for example: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_.$.retry&lt;/code&gt;  - if this was a function, then we might (correctly) identify the identifier &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&lt;/code&gt; but then mistakenly classify it as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global&lt;/code&gt; – even though it is not. These are safe in that they will just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt; in things that are not needed.&lt;/li&gt;
  &lt;li&gt;You might miss things if you’re not careful – for example, it possible to do something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window['$']'&lt;/code&gt; and this is technically a string literal referring to the global. In practice, I find this is pretty rare so they can be solved by hand if required. However, we could definitely solve this problem with more code. This would become even  harder to do with Regular Expressions – since context becomes so important and knowing the semantics of the language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, next time before you reach for a regular expression to solve a problem involving language rules – grab for a parser first instead, it might make your life a bit easier.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Steam hanging when clicking "Login" on WINE Staging</title>
   <link href="http://vaughanhilts.me/blog/2018/02/16/steam-hanging-on-clicking-login-wine-staging.html"/>
   <updated>2018-02-16T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2018/02/16/steam-hanging-on-clicking-login-wine-staging</id>
   <content type="html">&lt;h1 id=&quot;steam-hanging-when-clicking-login-on-wine-staging&quot;&gt;Steam hanging when clicking “Login” on WINE Staging&lt;/h1&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:repos/hilts-vaughan.github.io ‹master›&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;wine &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
wine-2.21 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Staging&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I was installing Steam in WINE to play a game. I’m not sure if this is a recent problem or not but I was installing WINE and ran Steam, punched in my credentials, hit “Login” and then expected the Steam Guard.&lt;/p&gt;

&lt;p&gt;Instead my window hung. I could not click anything else, Steam was locked up. I ended up  having to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xkill&lt;/code&gt; it. What to do?  The WINE output had something like:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; x11drv: Can&lt;span class=&quot;s1&quot;&gt;'t allocate handle for display fd
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… ok. Out of file descriptors? Let’s see how many we have open…&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;os &lt;span class=&quot;nt&quot;&gt;-aux&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;wineserver
touma     8792 62.2  0.1  27760 16884 ?        Rs   Feb15 814:28 /usr/bin/wineserver
touma@setsuna:repos/hilts-vaughan.github.io ‹master&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;›&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;lsof &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 8792 | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
4060
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Well, that’s approaching my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ulimit&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4096&lt;/code&gt;, so I wonder what’s going on? Does it stop when it realizes it will not be able to allocate more? Let’s see what’s opened:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wineserve 8792 touma 4050r      REG                8,5    97664  7349547 /usr/share/fonts/TTF/YanoneKaffeesatz-ExtraLight.ttf
wineserve 8792 touma 4051r      REG                8,5   112472  7347499 /usr/share/fonts/TTF/YanoneKaffeesatz-Light.ttf
wineserve 8792 touma 4052r      REG                8,5   114376  7353990 /usr/share/fonts/TTF/YanoneKaffeesatz-Regular.ttf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Looks like WINE / Steam / someone is scanning all my fonts, or something. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YanoneKaffeesatz&lt;/code&gt; is part of the Google Fonts bundle, which I tried a while ago but never really use anymore. So, let’s get rid of them and see if it helps:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:~ &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yaourt &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; ttf-google-fonts-git	
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run Steam, login, and it works.&lt;/p&gt;

&lt;p&gt;A bug with Steam? I’m not sure. I hope this helps someone. At least Linux gives us the tools to debug our problems.%&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Playing Trails of Cold Steel I && II on Linux using WINE</title>
   <link href="http://vaughanhilts.me/blog/2018/02/16/playing-trails-of-cold-steel-on-linux-wine-guide.html"/>
   <updated>2018-02-16T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2018/02/16/playing-trails-of-cold-steel-on-linux-wine-guide</id>
   <content type="html">&lt;h1 id=&quot;guide-and-remarks-playing-trails-of-cold-steel-i--ii-on-linux-using-wine&quot;&gt;Guide and Remarks: Playing Trails of Cold Steel I &amp;amp;&amp;amp; II on Linux using WINE&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;If anything here becomes out of date, please email me.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’m a huge &lt;em&gt;The Legend of Heroes&lt;/em&gt; fan and love playing all the games from the series. &lt;em&gt;XSEED Games&lt;/em&gt; has done a great job releasing the ports for the PC where available and where they can but they only port to Windows. The games are more on the niche side, so it is understandable, but I love them so and still want to play them on Linux as well. I got it working after tinkering for a few hours so I wanted to save any other random Internet go-ers the trouble and write this up so other people can enjoy this as well and other Linux users can give &lt;em&gt;XSEED&lt;/em&gt; their money so they continue to bring us this great series. ;)&lt;/p&gt;

&lt;p&gt;I purchased on Steam version but since they are reported to all be DRM free this should work for any version. You can just skip the Steam instructions if you bought on GOG or something.&lt;/p&gt;

&lt;h2 id=&quot;step-1-preparing-a-wine-prefix-getting-wine-etc&quot;&gt;Step 1: Preparing a WINE prefix, getting WINE, etc&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Install WINE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You need a copy of WINE Staging (or Wine 3.2 that has CSMT enabled by default if your distro is up to date) to get started. Depending on your distribution, you might have to find it elsewhere. I’m on Arch Linux, so you can &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yaourt&lt;/code&gt; to get it there if you’re like me, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yaourt -S wine-staging&lt;/code&gt; (or Pacman since apparently it’s not a AUR package).&lt;/p&gt;

&lt;p&gt;If your distro makes it hard to get a copy of WINE Staging (I tested on 2.21) then you can install &lt;a href=&quot;https://www.playonlinux.com/en/&quot;&gt;PlayOnLinux&lt;/a&gt; or &lt;a href=&quot;https://lutris.net/&quot;&gt;Lutris&lt;/a&gt;  which provide local copies of different versions of WINE outside of the system version. Once it’s installed, run:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:Falcom/ed8_2 &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;wine &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
wine-2.21 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Staging&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… and this should show you that it’s running fine. We can move on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configure WINE Prefix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I had used WINE in the past for some one-off’s but had nothing of value. You can use WINE prefixes but to make this bulletproof I decided to just make a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.wine&lt;/code&gt; and save myself the trouble. i.e:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; ~/.wine ~/.wine.backup
winecfg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and this should generate a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~.wine&lt;/code&gt; for you. You should go check. If you do this with an already existing WINE prefix, you run the risk of having problems. You can either look up how to use WINEPREFIX or you can just move the backup back into place when you are done. This probably only works for the System Wine, if you installed through a third party tool such as Lutris you will need to configure out how to run the configurator for that version. When the dialog comes up, make sure you go to the Staging tab and check off “CSMT” mode as well since this will be needed later. Photo below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/e712d104-1465-46ba-8b60-dbefe9d8c8a4/wine.png&quot; alt=&quot;wine config&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you do not have this option, either:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You’re not running Wine Staging, make sure your version is as such (for example, make sure you are running the right wine configuration for the proper version)&lt;/li&gt;
  &lt;li&gt;They have merged the CSMT patches and you’re using WINE 3.2+ (which has this enabled by default – yay!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will also be using &lt;a href=&quot;https://github.com/Winetricks/winetricks&quot;&gt;winetricks&lt;/a&gt; – your distro should have it somewhere or you can follow the manual instructions &lt;a href=&quot;https://wiki.winehq.org/Winetricks#Getting_winetricks&quot;&gt;here&lt;/a&gt;. It should be fairly simple to get.&lt;/p&gt;

&lt;p&gt;With this, we can move on to installing Steam. If you have something else, you can probably skip this step.&lt;/p&gt;

&lt;h2 id=&quot;step-2-installing-steam&quot;&gt;Step 2: Installing Steam&lt;/h2&gt;

&lt;p&gt;I referenced this &lt;a href=&quot;https://appdb.winehq.org/objectManager.php?sClass=version&amp;amp;iId=19444&quot;&gt;test run&lt;/a&gt; at time of writing and it seems to work. For brevity and to prevent link rot, I will repeat roughly the steps you need to perform below:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;winecfg &lt;span class=&quot;c&quot;&gt;# Setup a prefix (we already did this, so you can ignore)&lt;/span&gt;
winetricks corefonts
winetricks steam
winetricks d3dx9_42
winetricks vcrun2008
winetricks xact
winetricks vcrun2015
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;.. one of these failed but it didn’t matter. Or it was one of the commands below. I think it was a package that did not exist or was typo’d. For me, it made no difference. So, don’t worry about it.&lt;/p&gt;

&lt;p&gt;After you have DSound as well installed, you will need to change the DSound library from native to builtin to avoid crackling and latency problems. You can do this in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winecfg&lt;/code&gt; like we did with CSMT, you can a screenshot below. Just hit “Edit” on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dsound&lt;/code&gt; to get the desired &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;builtin&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/e712d104-1465-46ba-8b60-dbefe9d8c8a4/dsound.png&quot; alt=&quot;wine config&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I also know from other Falcom titles that these are good to have in hand and won’t hurt Cold Steel, I don’t know if they are strictly needed but better safe than sorry &lt;strong&gt;in this case&lt;/strong&gt; since all we care about is Cold Steel. If this was a shared prefix, we would have to be more careful.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;winetricks amstream
winetricks dsound
winetricks gdiplus
winetricks quartz
winetricks xvid
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That should be everything. You can go ahead and then start Steam if you have not already (you need to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine Steam.exe -no-cef-sandbox&lt;/code&gt; to do this, inside the steam folder), login and start installing Cold Steel. If you have problems with Steam hanging on login (you hopefully will not), you can check out this other post &lt;a href=&quot;/blog/2018/02/16/steam-hanging-on-clicking-login-wine-staging.html&quot;&gt;wrote on the topic&lt;/a&gt; which is not documented very well on the web.&lt;/p&gt;

&lt;h2 id=&quot;step-3-configuring-cold-steel-and-then-running-it&quot;&gt;Step 3: Configuring Cold Steel, and then running it&lt;/h2&gt;

&lt;p&gt;If everything goes well, Steam should be running and you should be able to hit &lt;em&gt;Play&lt;/em&gt; to begin the game. You can configure it first. I have the following configuration:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/e712d104-1465-46ba-8b60-dbefe9d8c8a4/settings.png&quot; alt=&quot;wine config&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Just a few notes on my configuration, which I hit “Maximum” and then tweaked from there:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;MSAA&lt;/strong&gt;: Yeah, this is prretty much the only thing I could not get working. It crashed on startup if I had this set at all. The game looks very good without it, so whatever.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Mouse and Keyboard&lt;/strong&gt;: I tested the gamepad and it worked fine but I prefer the mouse and keyboard.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fullscreen&lt;/strong&gt;: I tried window mode as well, it worked fine.&lt;/li&gt;
  &lt;li&gt;Everything else seemed to work fine, including turbo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;YMMV. At this point in time, you may want to check all the “Skip video” checkboxes as well, since it will crash initially if you let them play. There’s more on that in another section to get that working, detailed below.&lt;/p&gt;

&lt;p&gt;If you want, you should be able to launch the actual game with my configuration and start playing.&lt;/p&gt;

&lt;h2 id=&quot;step-4-getting-movies-working&quot;&gt;Step 4: Getting movies working&lt;/h2&gt;

&lt;p&gt;If you can either just watch the video files as you need to from the game folder (there’s seriously almost no videos in the game, mostly cutscenes) or you can install &lt;a href=&quot;https://github.com/Nevcairiel/LAVFilters/releases&quot;&gt;LAVFilters&lt;/a&gt; in your WINE to get the videos working. This will vary on system to system, so YMMV.&lt;/p&gt;

&lt;h2 id=&quot;step-5-loading-up-your-clear-save-data-importing-a-cs2-save-file-or-someone-elses-from-the-internet&quot;&gt;Step 5: Loading up your clear save data, importing a CS2 save file, or someone else’s from the Internet&lt;/h2&gt;

&lt;p&gt;If you are playing Cold Steel II, then you would want to import some data. There’s some cool stuff if you do. If you’re like me and played on the Vita or PS3 first and just want to bring your new save into CS2, then you can download save files from the web. I have one &lt;a href=&quot;/assets/e712d104-1465-46ba-8b60-dbefe9d8c8a4/saves.7z&quot;&gt;right here&lt;/a&gt; that is a Level 99 Rean NG+ with Alisa selected as the dance partner.  Other people have posted collections on-line, such &lt;a href=&quot;https://www.reddit.com/r/Falcom/comments/7vntbc/a_collection_of_cs1_clear_data_ready_for_ng_or_to/&quot;&gt;as here&lt;/a&gt;. If you do not care, you can skip this step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Importing the saves&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OK, so on the web you will see a lot of people saying you need to place these in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Users\&amp;lt;your_username&amp;gt;\Saved Games\FALCOM\ed8&lt;/code&gt; (or ed8_2 for Cold Steel II) which under WINE would be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/home/touma/.wine/drive_c/users/touma/Saved Games/FALCOM/ed8&lt;/code&gt; – however, if you are like me, placing your saves here will not work. Instead…&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:~/.wine &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;find &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ed8_2&quot;&lt;/span&gt;
./drive_c/users/touma/Application Data/Falcom/ed8_2
touma@setsuna:~/.wine &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;
/home/touma/.wine
touma@setsuna:~/.wine &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;

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

&lt;p&gt;.. and you will realize that there is a folder sitting inside of &lt;em&gt;Application Data&lt;/em&gt;. For Cold Steel II import, just create a folder called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ed8&lt;/code&gt; and then inside, place your save files:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:Falcom/ed8 $ ls -la
total 1248
drwxr-xr-x 2 touma touma   4096 Feb 15 22:22 .
drwxr-xr-x 3 touma touma   4096 Feb 15 21:46 ..
-rw-r--r-- 1 touma touma 169016 Feb 15 22:08 save000.bmp
-rw-r--r-- 1 touma touma 460992 Feb 15 22:08 save000.dat
-rw-r--r-- 1 touma touma 169016 Feb 15 22:08 save001.bmp
-rw-r--r-- 1 touma touma 460992 Feb 15 22:08 save001.dat

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

&lt;p&gt;… and you should be able to load them. Start the game. Hit “New Game” and when prompted to load clear data, hit yes. The files will be invisible (a problem on Windows as well) but just click slot 0 or 1 and you should load up no problem.&lt;/p&gt;

&lt;p&gt;Similar, if you have Cold Steel II Data, just drop it there:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:Falcom/ed8_2 $ ls -la
total 9536
drwxr-xr-x 2 touma touma   4096 Feb 15 23:56 .
drwxr-xr-x 4 touma touma   4096 Feb 15 22:04 ..
-rw-r--r-- 1 touma touma 493976 Feb 15 23:56 autosave00.dat
-rw-r--r-- 1 touma touma   1536 Feb 15 23:56 autosave00_t.dat
-rw-r--r-- 1 touma touma 493976 Feb 16 00:03 autosave01.dat
-rw-r--r-- 1 touma touma   1536 Feb 16 00:03 autosave01_t.dat
-rw-r--r-- 1 touma touma 493976 Feb 16 00:10 autosave02.dat
-rw-r--r-- 1 touma touma   1536 Feb 16 00:10 autosave02_t.dat
-rw-r--r-- 1 touma touma 493976 Feb 16 00:15 autosave03.dat
-rw-r--r-- 1 touma touma   1536 Feb 16 00:15 autosave03_t.dat
-rw-r--r-- 1 touma touma 493976 Feb 16 00:26 autosave04.dat
-rw-r--r-- 1 touma touma   1536 Feb 16 00:26 autosave04_t.dat
-rw-r--r-- 1 touma touma 493976 Feb 16 00:31 autosave05.dat
-rw-r--r-- 1 touma touma   1536 Feb 16 00:31 autosave05_t.dat
-rw-r--r-- 1 touma touma 493976 Feb 16 00:50 autosave06.dat
-rw-r--r-- 1 touma touma   1536 Feb 16 00:50 autosave06_t.dat
-rw-r--r-- 1 touma touma 493976 Feb 15 23:50 autosave07.dat
-rw-r--r-- 1 touma touma   1536 Feb 15 23:50 autosave07_t.dat
-rw-r--r-- 1 touma touma 493976 Feb 16 00:50 save000.dat
-rw-r--r-- 1 touma touma 493976 Feb 15 22:50 save001.dat
-rw-r--r-- 1 touma touma 493976 Feb 15 22:50 save002.dat
-rw-r--r-- 1 touma touma 493976 Feb 15 22:50 save003.dat
-rw-r--r-- 1 touma touma 493976 Feb 15 22:50 save004.dat
-rw-r--r-- 1 touma touma 493976 Feb 15 22:50 save005.dat
-rw-r--r-- 1 touma touma 493976 Feb 15 23:03 save006.dat
-rw-r--r-- 1 touma touma 493976 Feb 15 23:03 save007.dat
-rw-r--r-- 1 touma touma    120 Feb 16 00:50 save255.dat
-rw-r--r-- 1 touma touma 368640 Feb 16 00:50 sdslot.dat
-rw-r--r-- 1 touma touma 169014 Feb 16 00:50 thumb000.bmp
-rw-r--r-- 1 touma touma 169014 Feb 15 22:50 thumb001.bmp
-rw-r--r-- 1 touma touma 169014 Feb 15 22:50 thumb002.bmp
-rw-r--r-- 1 touma touma 169014 Feb 15 22:50 thumb003.bmp
-rw-r--r-- 1 touma touma 169014 Feb 15 22:50 thumb004.bmp
-rw-r--r-- 1 touma touma 169014 Feb 15 22:50 thumb005.bmp
-rw-r--r-- 1 touma touma 169014 Feb 15 23:03 thumb006.bmp
-rw-r--r-- 1 touma touma 169014 Feb 15 23:03 thumb007.bmp
-rw-r--r-- 1 touma touma  43256 Feb 16 00:50 thumb255.bmp

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

&lt;p&gt;.. as you can see, I’ve saved a few times. ;)&lt;/p&gt;

&lt;p&gt;Eventually, you should have a game running. Minor spoilers below…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/e712d104-1465-46ba-8b60-dbefe9d8c8a4/game.png&quot; alt=&quot;wine config&quot; /&gt;&lt;/p&gt;

&lt;p&gt;… That should be everything you need to play! There are a couple other things that I noticed as well but they might not affected everyone. I’ve attached some of that info inside of the misc section below. You can read it if you have problems.&lt;/p&gt;

&lt;h2 id=&quot;step-6-misc-other-things&quot;&gt;Step 6: Misc. other things&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DLC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I noticed I had a bunch of DLC unlocked, I was not sure if this was intentional or a WINE bug.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/e712d104-1465-46ba-8b60-dbefe9d8c8a4/dlc.png&quot; alt=&quot;wine config&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The outfits:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/e712d104-1465-46ba-8b60-dbefe9d8c8a4/outfit.png&quot; alt=&quot;wine config&quot; /&gt;&lt;/p&gt;

&lt;p&gt;is for owners of the Trails Series on Steam and other platforms, which I have. So, that makes sense. The rest, I am unsure. Speaking of outfits…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crashes with costumes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On Windows as well at the time of writing, wearing costumes sometimes can cause the game to crash. For example, early on when you enter a certain hot spring, the game will crash wearing the costumes given from the DLC, which I experienced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Camera spinning on startup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xboxdrv&lt;/code&gt; installed? I did. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemctl stop xboxdrv.service&lt;/code&gt; should do the trick while you’re playing. You an always &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start&lt;/code&gt; it when you are done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance notes, audio, wine debug&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have problems with performance / audio, make sure you set the &lt;a href=&quot;https://askubuntu.com/questions/85221/turn-off-wine-debugging&quot;&gt;WINE Debug flags&lt;/a&gt; accordingly to get your performance back.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;reference-system&quot;&gt;Reference System&lt;/h2&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touma@setsuna:Falcom/ed8_2 &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;neofetch
                   -&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;                    touma@setsuna 
                  .o+&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;                   &lt;span class=&quot;nt&quot;&gt;-------------&lt;/span&gt; 
                 &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;ooo/                   OS: Arch Linux x86_64 
                &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;+oooo:                  Kernel: 4.15.3-1-ARCH 
               &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;+oooooo:                 Uptime: 13 days, 16 hours, 23 minutes 
               -+oooooo+:                Packages: 1620 
             &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/:-:++oooo+:               Shell: zsh 5.4.2 
            &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/++++/+++++++:              Resolution: 1920x1080, 1920x1080 
           &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/++++++++++++++:             DE: GNOME 
          &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/+++ooooooooooooo/&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;           WM: GNOME Shell 
         ./ooosssso++osssssso+&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;          WM Theme: Adwaita 
        .oossssso-&lt;span class=&quot;sb&quot;&gt;````&lt;/span&gt;/ossssss+&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;         Theme: Paper &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;GTK2/3] 
       &lt;span class=&quot;nt&quot;&gt;-osssssso&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;      :ssssssso.        Icons: Numix &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;GTK2/3] 
      :osssssss/        osssso+++.       Terminal: gnome-terminal 
     /ossssssss/        +ssssooo/-       CPU: Intel i5-2500 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;4&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; @ 3.7GHz 
   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/ossssso+/:-        -:/+osssso+-     GPU: NVIDIA GeForce GTX 970 
  &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;+sso+:-&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;                 &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;.-/+oso:    Memory: 6230MiB / 16005MiB 
 &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;++:.                           &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;-/+/ 
 .&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;                                 &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;/                           


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

&lt;p&gt;I play games on GNOME since it works better for me than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3wm&lt;/code&gt; which is my development WM. I leave this here just so people can see what I was using at the time.&lt;/p&gt;

&lt;h2 id=&quot;ramblings&quot;&gt;Ramblings&lt;/h2&gt;

&lt;p&gt;I’ve only played about 4 hours by now but I’ve not noticed any game crippling issues. Game seems to run great, with the occasional minor hiccup but things are good. I’ll edit this article if I come across anything that is a deal breaker and how I managed to work past it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Fixing "playing games under WINE in Steam, the camera rotates in one direction "</title>
   <link href="http://vaughanhilts.me/blog/2018/02/16/camera-rotating-wine-game-joystick.html"/>
   <updated>2018-02-16T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2018/02/16/camera-rotating-wine-game-joystick</id>
   <content type="html">&lt;p&gt;Just writing this down here in case anyone else stumbles across this. On my Arch Linux system, many games running under WINE were having their camera spinning over and over or it would look like a joystick was held down. For example, in &lt;em&gt;Trails of Cold Steel II&lt;/em&gt; the camera would spin but in &lt;em&gt;Recettear: An Item Shop’s Tale&lt;/em&gt; the main menu would scroll through all the options over and over. Something is sending joystick input.&lt;/p&gt;

&lt;p&gt;Turns out, for me, it was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xboxdrv&lt;/code&gt; – and you can turn it off while you’re playing using your distributions service manager. For Arch Linux (and probably any systemd system, which most are by now at time of writing), just:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;systemctl stop xboxdrc.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… or just uninstall &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xboxdrv&lt;/code&gt; if you don’t need it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Setting up a TF2 Server with Custom Maps using Linux Game Server</title>
   <link href="http://vaughanhilts.me/blog/2018/02/06/setting-up-a-tf2-server-on-linux-game-server.html"/>
   <updated>2018-02-06T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2018/02/06/setting-up-a-tf2-server-on-linux-game-server</id>
   <content type="html">&lt;h1 id=&quot;setting-up-a-tf2-server-with-custom-maps-using-linux-game-server&quot;&gt;Setting up a TF2 Server with Custom Maps using Linux Game Server&lt;/h1&gt;

&lt;p&gt;I was recently trying to play some custom maps with some friends on Team Fortress 2 but with some custom maps. There are tons of community servers that run certain maps on rotation but these are not always the ones you want to play, especially if you want to play the older maps. I had a bit of trouble setting the server up since there is very little up to date documentation on how to get it running with  &lt;strong&gt;custom maps specifically&lt;/strong&gt; so I figured I would try and fill the gap for those who stumble across this in the future.&lt;/p&gt;

&lt;p&gt;I’ll leave the guide here and commentary to the end, in case you are interested in ramblings. This is for Linux, whether on a personal Linux host or on your cloud provider. Some of the lessons here can definitely be used on a Windows machine, such as the files you need to place and where but the commands, scripts, etc are very Linux centric and not portable. You may have luck with the &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/wsl/install-win10&quot;&gt;Linux Subsystem for Windows 10&lt;/a&gt;, but I have not tried it.&lt;/p&gt;

&lt;h2 id=&quot;step-1-getting-the-linux-game-server-aka-a-stock-install&quot;&gt;Step 1: Getting the Linux Game Server, aka a stock install&lt;/h2&gt;

&lt;p&gt;This much is pretty simple, you can follow the directions on their &lt;a href=&quot;https://gameservermanagers.com/lgsm/tf2server/&quot;&gt;site&lt;/a&gt; and that’s all you have to do for setup. For completion sakes and because link rot is sometimes a thing, I will include the exact directions here:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;adduser tf2server
passwd tf2server
su - tf2server
wget &lt;span class=&quot;nt&quot;&gt;-N&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-check-certificate&lt;/span&gt; https://gameservermanagers.com/dl/linuxgsm.sh &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; +x linuxgsm.sh &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; bash linuxgsm.sh tf2server
./tf2server &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This should get you a working install, after working through that stuff. There are a few other things you may want to change, you can read the rest of the page there to find out more. The download is fairly big and can take a bit, so you can can read on and be prepared for when it’s done. You can even complete Step 2 while this is going in the background.&lt;/p&gt;

&lt;h2 id=&quot;step-2-expose-it-to-the-internet&quot;&gt;Step 2: Expose it to the Internet&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Home Connections&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This will sound pretty obvious if you’ve ever ran a game server but I will mention it for completion sakes. You will need to open the port that inbound connections will be coming on if you sit in a typical residential network with a gateway in front of your server.&lt;/p&gt;

&lt;p&gt;You can refer to you routers manual for specifics but you need to setup Port Forwarding for the inbound port, 27015 and there is no sense in going over a tutorial on this here, since there are tons of guide on the web.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud Providers, Digital Ocean&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are using Digital Ocean or some other cloud provider, the port is probably already available if you have a dedicated IP for yourself. You may need to allow the port as well, depending on the distro you chose to run. If you are running something running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ufw&lt;/code&gt; then you can use something like: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo ufw allow 27015&lt;/code&gt; to open inbound traffic on that port for yourself. Otherwise, open the port on the firewall however you choose.&lt;/p&gt;

&lt;p&gt;You can read more about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ufw&lt;/code&gt; on the &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/ufw-essentials-common-firewall-rules-and-commands&quot;&gt;DigitalOcean site&lt;/a&gt; or elsewhere on the web, if you need to deal with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checking connectivity…&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are tools you can use such as &lt;a href=&quot;http://canyouseeme.org/&quot;&gt;CanYouSeeMe&lt;/a&gt; for local installs to check a port. Linux Game Server has something built in for this, so there’s no need though.  Just run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./tf2server monitor&lt;/code&gt; and you can check your status. If it says &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OK&lt;/code&gt; then you should be good to go.&lt;/p&gt;

&lt;h2 id=&quot;step-3-load-up-custom-maps-into-the-directories-needed&quot;&gt;Step 3: Load up custom maps into the directories needed&lt;/h2&gt;

&lt;p&gt;You can find a ton all over the web, these are just a few places:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gamebanana.com/maps/games/297&quot;&gt;GameBanana&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.teamfortress.com/wiki/Custom_maps&quot;&gt;Wiki&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tf2maps.net/&quot;&gt;TF2Maps&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;… or any other BSP files you can find on the web that is supported&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find a ton of them in various indexes available on the web as well, such as &lt;a href=&quot;http://custompc.ca/DOWNLOADS/TF2/maps/&quot;&gt;here&lt;/a&gt;. Once you have a few, you can follow the below directions.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;You can begin by entering your directory of your server as the user you created when using the TF2Server installer.  If you run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd serverfiles/tf/maps/&lt;/code&gt; you will end up in a directory full of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bsp&lt;/code&gt; files. In here,  you can place all the files you downloaded and want to play. There are a couple ways to do this….&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;If it’s local, you can just use a File Explorer, of course.&lt;/li&gt;
      &lt;li&gt;If it’s remote, you can look at something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scp&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ftp&lt;/code&gt;, mount your file system as SSH or whatever you prefer. You can use &lt;a href=&quot;https://www.google.ca/search?q=transfer+file+to+remote+system+linux&amp;amp;oq=transfer+file+to+remote+system+linux&amp;amp;aqs=chrome..69i57.4320j0j7&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&quot;&gt;Google&lt;/a&gt; to find this information…&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Then, you can &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd - &lt;/code&gt; to go back to the root directory, where you were and your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./tf2server&lt;/code&gt; script should reside. You need to add the maps that you have to your config now, so you can this by executing a bash one liner. This was the part that confused me the most, since a lot of places on the web talk about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;maplist&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapcycle&lt;/code&gt; and to edit it to include the new maps you want to play. If you are like me, you would not have had these files at this point and would be unable to find them using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find . -name &quot;*maplist*&quot;&lt;/code&gt; and it would turn out that it does not. You need to create it. To do this…&lt;/p&gt;

    &lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;serverfiles/tf/maps/ &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;bsp//g&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./serverfiles/tf/cfg/maplist.cfg

&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;serverfiles/tf/maps/ &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;bsp//g&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./serverfiles/tf/cfg/maplist.txt

&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;serverfiles/tf/maps/ &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;bsp//g&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ./serverfiles/tf/maplist.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;To be honest, I am not sure you need to duplication but I have not gotten around to testing it yet. However, this should be at least a working install. You can throw this in a script and call it, say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;updateMaps.sh&lt;/code&gt; if you want so that you can re-run it every time you add new maps.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;For some maps, there are some additional settings to set as well to set. You can find those below, make sure to read them if you need them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Restart your server. You can do this using the Linux Game Server script, by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./tf2server restart&lt;/code&gt; and then waiting a few minutes for the server to come back up.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There’s also some additional configuration to do depending on the map you play. For example, some maps have bots that occupy slots and need a large number of slots for them, such as &lt;a href=&quot;https://wiki.teamfortress.com/wiki/Mann_vs._Machine&quot;&gt;Mann vs. Machine&lt;/a&gt; and perhaps other modes. Some maps are just big. In our case, we needed to do this:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; nano lgsm/config-lgsm/tf2server/tf2server.cfg  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;… and then add these lines&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;maxplayers=&quot;32&quot;
net_maxfilesize=&quot;64&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will let you play most maps without trouble. You will need to restart your server after any of these changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some places on the web will let you know you need to also configure a FastDL server, this is false at the time of writing this in 2018. You only need this if you want to serve files that are large at a quick download time.&lt;/strong&gt; If you are just setting up a local server to play with some friends and have custom maps rotate out, this is overkill and your friends can wait the 5 minutes it needs to download a map, &lt;strong&gt;once&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;step-4-connect-and-then-load-the-map&quot;&gt;Step 4: Connect and then load the map&lt;/h2&gt;

&lt;p&gt;In Team Fortress 2, you can then click “Find Game”:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://wiki.teamfortress.com/w/images/thumb/c/c4/GUI_Main_menu.png/500px-GUI_Main_menu.png&quot; alt=&quot;https://wiki.teamfortress.com/w/images/thumb/c/c4/GUI_Main_menu.png/500px-GUI_Main_menu.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;.. and then click “Community Servers”. Then, you can click the “Favourites” tab and then “Add Server” button in the bottom right. You can then add the IP of the server. You can find the public IP pretty easily by requesting it from the outside world by asking &lt;a href=&quot;https://www.google.ca/search?q=ip+check&amp;amp;oq=ip+check&amp;amp;aqs=chrome..69i57j69i60l2j69i65j69i60l2.2024j0j7&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8&quot;&gt;Google&lt;/a&gt; or if you know there’s no gateway in front you can just do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip addr&lt;/code&gt; to figure it out.&lt;/p&gt;

&lt;p&gt;If all went well, you should be dumped into whatever the default map is when you connect. If not, time to troubleshoot.&lt;/p&gt;

&lt;p&gt;To change maps, the easiest way is through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rcon&lt;/code&gt; and you can find most of this through the Linux Game Server documentation. The gist is, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./tf2server console&lt;/code&gt; and then you will be dropped in a console. Then…&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You can run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;maps*&lt;/code&gt; to get a listing of all the installed maps. Yours should be listed now, without the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bsp&lt;/code&gt; suffix since that’s the convention.&lt;/li&gt;
  &lt;li&gt;You can run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;changelevel&lt;/code&gt; to change the map that is currently being played, using the name of the map from the above command or just use the filename of the map without the extension (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bsp&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are other &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rcon&lt;/code&gt; commands and there are various guides on the web with interacting with it. I reference this &lt;a href=&quot;http://ozfortress.com/showthread.php?p=415211&quot;&gt;http://ozfortress.com/showthread.php?p=415211&lt;/a&gt; but there are probably other guides out there that are better / more detailed.&lt;/p&gt;

&lt;h2 id=&quot;ramblings&quot;&gt;Ramblings&lt;/h2&gt;

&lt;p&gt;I found it pretty frustrating that most of the information on the web was pretty incomplete in terms of what to do to get a fully working install with nothing. &lt;a href=&quot;https://www.google.ca/search?ei=O1h6WoXIMdiwjAO4-K-4Bw&amp;amp;q=setup+community+server+with+custom+maps+tf2&amp;amp;oq=setup+community+server+with+custom+maps+tf2&amp;amp;gs_l=psy-ab.3...2258.2735.0.2772.6.5.0.0.0.0.151.151.0j1.1.0....0...1c.1.64.psy-ab..5.0.0....0.TCqd2flnpMU&quot;&gt;Google&lt;/a&gt; gives a lot of guides on Windows which are incomplete and talk about files that are not even there and does a good job of misleading you through what you need as a minimum. For example, the first Steam Link there insists you setup a web server and FastDL and spends most of the post on that. There are other interesting problems aside from FastDL. I kind of wish there was a better way and I am kind of surprised that the folks at Linux Game Server don’t have a way to do this since they have a mod installer but not a map installer.&lt;/p&gt;

&lt;p&gt;It took a pretty large amount of time to get everything right and it could have been a lot easier with a proper write up and instructions that detailed the custom map portion. So, I leave this in hopes it will help someone else.&lt;/p&gt;

&lt;p&gt;Happy playing! If there are questions, you can drop them below.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>You need to learn to navigate code</title>
   <link href="http://vaughanhilts.me/blog/2017/11/22/you-need-to-learn-to-navigate-code.html"/>
   <updated>2017-11-22T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2017/11/22/you-need-to-learn-to-navigate-code</id>
   <content type="html">&lt;h1 id=&quot;you-need-to-learn-to-navigate-code&quot;&gt;You need to learn to navigate code&lt;/h1&gt;

&lt;p&gt;Often when we talk about productivity of developers, we will measure various outputs. In the worst places, this metric might be lines of code. In better ones, it will be bugs density, features completed, support requests answered. Often, to get better at these we will reference things like better software design, maintainable code, unit tests,  and more. Some of these focus on letting other people read our code in a more efficient manner and others just help us write better code for ourselves. The best will do both. There is another side of the equation, though.  We write readable code because we know that eventually someone else will read it, even if that “someone” is ourselves.  The thing we neglect to also talk about sometimes is that being able to &lt;strong&gt;read your code in an efficent way&lt;/strong&gt; is almost as important.&lt;/p&gt;

&lt;h2 id=&quot;learn-your-ide-shortcuts-and-make-use-of-them&quot;&gt;Learn your IDE shortcuts and make use of them&lt;/h2&gt;

&lt;p&gt;This might sound obvious. It might even seem like it goes without saying.  However, I have witnessed many developers that simply do not use any hot keys or know the shortcuts to navigate their editor. They do not use any shortcuts. When you are reading a dense chunk of code, this can cost you minutes that will add up in a very long session. These days, I do mostly web development so I will be speaking mostly from that perspective. I use &lt;strong&gt;Atom&lt;/strong&gt; and &lt;strong&gt;Visual Studio Code&lt;/strong&gt; as my main editors  and feel comfortable talking about these. Even though I prefer &lt;strong&gt;Visual Studio Code&lt;/strong&gt; more nowadays, I focus a lot on Atom since I think a lot more developers still use it. It’s very popular and because of that, I feel like a lot of people use it without actually configuring it properly.  It is &lt;em&gt;is&lt;/em&gt; possible that this phenomenon is exclusive to web developers but I have a feeling it can be applied to others, too. I feel like developers with full IDEs are more aware of these kinds of things, especially in languages like Java where the tooling has been very good for a while now.&lt;/p&gt;

&lt;p&gt;These are some things you need to learn to use, else you are severely missing out:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;**Jump to method **. If you are pressing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl + F&lt;/code&gt; to find a method inside of your code, you are doing it wrong. Most IDEs and even text editors, such as Atom (with the proper language server / support) can jump straight there. For example, in Atom, you can do this with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl + R&lt;/code&gt; (at least on Linux) There are numerous advantages&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;The search is often fuzzy, so you only need to recall a few characters&lt;/li&gt;
      &lt;li&gt;You can see all the symbols in one view, so you can flip through them fast if you need to often&lt;/li&gt;
      &lt;li&gt;You can get there by just typing some characters instead of scrolling and then positioning the cursor&lt;/li&gt;
      &lt;li&gt;You only get &lt;strong&gt;definitions&lt;/strong&gt; and not all the usages as well and then need to read each result you get if you were to have done a search&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;​&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Go to file / class&lt;/strong&gt;. This is also a big one that I see a lot of people use already and it is rare that I do not see someone use it. Hunting for a single class or file in your structure is painful and could require dozens of seconds to get right, depending on how large your project is. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl + Shift + F&lt;/code&gt; is not the right answer ==  instead, use something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl + P&lt;/code&gt; in Atom or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl + O&lt;/code&gt; in Jetbrains IDEs. … and now you get something that can help you find a file very quickly.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;If your tooling supports it, learn your quick navigation tools such as “Go to class” or “Go to definition” when you have a word selected.&lt;/strong&gt; Visual Studio Code has good support for this.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In fact, there are a ton more. These are just some of the very basic ones that kill me I see someone not using them. Atom does not support much out of the box but Visual Studio Code supports a ton more. I do not need to repeat much more of what is already available. Just read the documentation for your IDE if you have not already. Scour the web, people have summarized their findings for you.&lt;/p&gt;

&lt;p&gt;I’ll put some links below to some good articles on getting the most out of your IDE for code navigation:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://code.visualstudio.com/docs/editor/editingevolved&quot;&gt;Visual Studio Code&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.jetbrains.com/help/idea/navigating-through-the-source-code.html&quot;&gt;IntelliJ&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/1888161/navigating-through-code-with-keyboard-shortcuts&quot;&gt;Visual Studio, random shortcuts from SO&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;.. and there’s more. You can find them all from a simple search with “your favourite IDE” + “code navigation”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just learn your keyboard shortcuts.&lt;/p&gt;

&lt;h2 id=&quot;spend-some-time-setting-up-your-environment-to-your-workflow&quot;&gt;Spend some time setting up your environment to your workflow&lt;/h2&gt;

&lt;p&gt;These are just a few things I have done to my &lt;strong&gt;Atom&lt;/strong&gt; install. For each thing, I identified where time was being sunk into and then make changes to make things less cumbersome.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Select the file in the tree view you are looking at by default&lt;/strong&gt; &lt;em&gt;( Settings &amp;gt; Tree View &amp;gt; ‘Auto reveal’)&lt;/em&gt;: If you are exploring new code, there is a chance you will be looking at files grouped in a similar package or module. If you are using your keyboard to hop between files as you find them you  might want your file finder to follow you as well. Some Jetbrains IDE have this feature as well which is disabled by default. This will save you time from hunting down the file or executing the “Show in tree view” command (once you figure it out…)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Look into tools that can provide you extra value. ** For example, in **Atom&lt;/strong&gt;   we do not have a fully fledged IDE available but there are plugins that will make a big difference, such as &lt;strong&gt;TernJS&lt;/strong&gt; for Javascript which allows us to get some “type hinting” on code that is not annotated.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rearrange Windows if you have multiple monitors, make use of them.&lt;/strong&gt;  I was guilty of this one for a while. I would be making use of only one monitor when developing and using the other for documentation. On a 1080p monitor, I thought of better things to do with a 2nd monitor then holding a browser I would look at ‘sometimes”. The stock configurations for most environments are not suited for dual monitors, let alone multiple.
    &lt;ol&gt;
      &lt;li&gt;Unit Test Feedback that I can glance at from time to time to make sure nothing is broken&lt;/li&gt;
      &lt;li&gt;Console ouput that can be monitored&lt;/li&gt;
      &lt;li&gt;The running application when doing web development, so I can see the change in front of me&lt;/li&gt;
      &lt;li&gt;… anything else related to the current task’
​&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Find a colour scheme for you that makes it easy to differentiate things&lt;/strong&gt; This one is simple but makes a big difference. Make sure the colour scheme you are using is providing you value and you can tell things apart.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are tons of other things you can do. The web has covered them all everywhere and there is no reason to repeat everything that has been blogged to death. Instead, I beg, notice what you are doing and what is taking forever. Then, you should find a way to fix it. Just by changing up a few things, I saved myself a lot of frustrating and got some very helpful hints while reading code.&lt;/p&gt;

&lt;h2 id=&quot;yep-thats-it&quot;&gt;Yep, that’s it&lt;/h2&gt;

&lt;p&gt;Yeah, that is really all I wanted to say. All this information is already available elsewhere if you are looking for it but nobody talks about this in academics. In school, you are not taught to learn about your tooling all the time. (At least, I was not) If you have good co-workers, they will probably point out your inefficiency when they see it. If you are self employed, you will need to discover this on your own. You know, most people already know this stuff. But I hope this will reach someone out there whom never considered it.&lt;/p&gt;

&lt;p&gt;Happy reading and navigating.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Honest Perspective - A year on Arch Linux coming from Windows and macOS</title>
   <link href="http://vaughanhilts.me/blog/2017/11/20/honest-perspective-arch-linux-one-year.html"/>
   <updated>2017-11-20T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2017/11/20/honest-perspective-arch-linux-one-year</id>
   <content type="html">&lt;h1 id=&quot;honest-perspective-a-year-on-arch-linux-coming-from-windows-and-macos&quot;&gt;Honest Perspective: A year on Arch Linux coming from Windows and macOS&lt;/h1&gt;

&lt;p&gt;A little background about me before we begin fully:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I’m a Software Developer in Canada, I’ve been writing web applications professionally for a number of years&lt;/li&gt;
  &lt;li&gt;Most of my development is done in &lt;strong&gt;Java&lt;/strong&gt;, &lt;strong&gt;C#&lt;/strong&gt;, and &lt;strong&gt;Javascript&lt;/strong&gt;. So, this will be written from the perspective of someone who works in those technologies where applicable. However, in general, my experience with development was very pleasant, so there is not much to write about!&lt;/li&gt;
  &lt;li&gt;My previous Linux experience amounts to working on a remote server with a few basic *NIX commands and using macOS&lt;/li&gt;
  &lt;li&gt;I like a little bit of punishment when I do things wrong and understanding why my decisions were poor – this ties into my distribution choice later on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A little over a year ago, I switched from Windows to Linux completely on my journey to finding a better development environment that would serve me on my home machine. At the time, the &lt;a href=&quot;https://msdn.microsoft.com/en-us/commandline/wsl/install-win10&quot;&gt;Windows Subsystem for Linux did not exist.&lt;/a&gt; There were a few reasons I wanted to switch over:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There were some development tools that I used a lot that I just wish I could use hassle-free under Windows. They were mostly Linux tools or software. These includes a lot of command line utilities and other goodies  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dd&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zsh&lt;/code&gt; , &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; and a host of other things. Some of these worked fine under Windows, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt;, but the experience was not as good.&lt;/li&gt;
  &lt;li&gt;I was sick of being unable to properly diagnose my machine under Windows with full understanding. The kernel logs were not as easily exposed and things were always a bit more arcane when they went wrong, with less hope of debugging them on my own. I take pride in being able to debug software – why not my operating system when I need to be able to?&lt;/li&gt;
  &lt;li&gt;I wanted to try a new workflow other than the one Windows could provide me with. This included new file managers, new desktop environments and new ways of navigating my machine. After using a Mac for a while, I had come to appreciate some of the features macOS had that Windows did not natively, such as brew and workspaces (before Windows had any!). (Yes, I know &lt;a href=&quot;https://chocolatey.org/&quot;&gt;Chocolately&lt;/a&gt; and there are other 3rd party workspace managers, but none of them were tightly integrated with the OS and felt bolted on through some “not-designed-for-this” APIs)&lt;/li&gt;
  &lt;li&gt;I wanted to play around more with &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt; a little more and “Docker Machine” was a pain and it was not the “native experience” that Docker was claiming to fame. I played around with it in a Virtual Machine a bit but I wanted to experience the full thing inside of a native operating system.&lt;/li&gt;
  &lt;li&gt;It was something new and cool – who doesn’t like cool and new things?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;choices--setting-up&quot;&gt;Choices &amp;amp; Setting up&lt;/h2&gt;

&lt;p&gt;I spent a long while deciding on what distribution to install and I eventually settled on &lt;a href=&quot;https://www.archlinux.org/&quot;&gt;Arch Linux&lt;/a&gt;. There were a few reasons for this but the main decision points just boiled down to this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The AUR is awesome and had almost everything I could have wanted when I researched it, this seemed like a great perk.&lt;/li&gt;
  &lt;li&gt;I wanted up to date drivers and video hardware. At the time, I was running  an AMD card and I heard the bleeding edge drivers were a lot better. As it would turn out later, better was not even close to good enough at the time.&lt;/li&gt;
  &lt;li&gt;I wanted some a little less abstract so I could learn the nuts and bolts&lt;/li&gt;
  &lt;li&gt;I needed something that out of the box would let me do all the customization I needed.  For example, I already knew I wanted &lt;a href=&quot;https://github.com/Airblader/i3&quot;&gt;i3-gaps&lt;/a&gt; and wanted to try some alternative menus such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dmenu&lt;/code&gt;. This made it harder to choose distros that would prepackage their own environment which I would then have to dissect.&lt;/li&gt;
  &lt;li&gt;I needed to be able to install all the developers tools I needed with no friction, and the AUR was a huge help with this.&lt;/li&gt;
  &lt;li&gt;.. and it was hyped up to be the best thing since sliced bread. Might as well play the hype machine, right?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The runner ups were &lt;strong&gt;Ubunutu&lt;/strong&gt; and &lt;strong&gt;Manjaro&lt;/strong&gt;. &lt;strong&gt;Ubuntu&lt;/strong&gt; was too stock and in the way of what I wanted to do, so it was out.  Manjaro? Well, I read something about a SSL certificate that went something like, not once, but twice:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hello!&lt;/p&gt;

  &lt;p&gt;Our SSL certificate has once again expired. We are waiting for a new one to be issued (while also looking at more sustainable alternatives, i.e. Let’s Encrypt). If you’re having problems accessing any of the sites please use a different browser profile, or Private/Incognito Browsing. You will then be able to add a temporary exception.&lt;/p&gt;

  &lt;p&gt;Example (Firefox 46)&lt;/p&gt;

  &lt;p&gt;https://manjaro.github.io/SSL-Certificate-Expired/&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;.. and it left a bad impression. So, that was out. I figured I might as well for the full authentic experience.&lt;/p&gt;

&lt;p&gt;So, I followed the &lt;a href=&quot;https://wiki.archlinux.org/index.php/Installation_guide&quot;&gt;Beginner’s Install Guide&lt;/a&gt;  and was installed in a couple hours with GDM and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3-gaps&lt;/code&gt; with a multi-monitor setup using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arandr&lt;/code&gt; to configure myself. I did the initial run with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gnome&lt;/code&gt; since I figured it would give me the least amount of problems and at least a working environment to boot into. These are the notes I left for myself when I had installed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arandr&lt;/code&gt; did not work out of the box and I had to manually create my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xorg&lt;/code&gt; file. This was kind of annoying but considering it worked under the GNOME Environment that I initially installed, I assume it was a bug with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arandr&lt;/code&gt; or the way I was using it.&lt;/li&gt;
  &lt;li&gt;The video drivers for AMD were bad. I was unable to play most games on Steam with acceptable frame rates. My 7770 was already getting pretty old and I was eying a 970 anyway, so I bit the bullet with the understanding that: NVIDIA drivers were better on Linux than AMD and that I would be able to play things and the monitor setup would be easier. Turns out, both were true. Success!&lt;/li&gt;
  &lt;li&gt;The media keys were not working out of the box on my keyboard along with some other things taken for granted. I did want a DIY approach and I think some of this worked under GNOME when I tried it briefly, but it would have been nice if there pre-packaged sane defaults that I could install. I ended up installing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3-gnome&lt;/code&gt; which gave my some of these “sane defaults” I wanted by running some of the GNOME subsystem. Other things missing which I did not realize I had missed: easy screen snipping, volume management, and well thought out settings GUI applications for the day to day stuff.&lt;/li&gt;
  &lt;li&gt;I had to jump through some hoops to customize my K70 keyboard again. I just configured it and left it alone..&lt;/li&gt;
  &lt;li&gt;I had a problem where I noticed fonts sucked really bad out of the box. I had to install some additional packages to make it look better.&lt;/li&gt;
  &lt;li&gt;Some of my games and applications would not launch due to missing libraries. I had to learn how to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ldd&lt;/code&gt;… I guess I asked for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: At the time of writing this, it looks like the Beginner’s Guide no longer exists. It seems it has been consolidated. I cannot comment on the quality of this new guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The final setup looks  something like this after all is said and done. I think the only thing I have done since is added another 8GB of RAM to keep things happy, especially since I needed the Windows VM from time to time now.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;'                   -`                   touma@setsuna 
                  .o+`                   ------------- 
                 `ooo/                   OS: Arch Linux x86_64 
                `+oooo:                  Kernel: 4.13.11-1-ARCH 
               `+oooooo:                 Uptime: 7 days, 6 minutes 
               -+oooooo+:                Packages: 1649 
             `/:-:++oooo+:               Shell: zsh 5.4.2 
            `/++++/+++++++:              Resolution: 1920x1080 
           `/++++++++++++++:             WM: i3 
          `/+++ooooooooooooo/`           Theme: Arc-Dark [GTK2/3] 
         ./ooosssso++osssssso+`          Icons: HighContrast [GTK2/3] 
        .oossssso-````/ossssss+`         Terminal: terminator 
       -osssssso.      :ssssssso.        CPU: Intel i5-2500 (4) @ 3.7GHz 
      :osssssss/        osssso+++.       GPU: NVIDIA GeForce GTX 970 
     /ossssssss/        +ssssooo/-       Memory: 7041MiB / 16013MiB 
   `/ossssso+/:-        -:/+osssso+- 
  `+sso+:-`                 `.-/+oso:                            
 `++:.                           `-/+/ 
 .`                                 `/ 



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

&lt;h3 id=&quot;package-managers-are-great&quot;&gt;Package managers are great&lt;/h3&gt;

&lt;p&gt;There’s nothing much to say here. I always liked &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew&lt;/code&gt; on macOS even if it was a bit clunky to use and the method of installing it was, shady, at best. After using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman&lt;/code&gt; for a while, I can say that I never want to go back to manual installers infested with AdWare ever again. You get so much for free with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman&lt;/code&gt;, some of which is not exclusive to it, but just a part of package managers in general in most distros:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Dependency Management&lt;/li&gt;
  &lt;li&gt;Versioning (rollbacks, if needed)&lt;/li&gt;
  &lt;li&gt;Visibility into what is about to be installed&lt;/li&gt;
  &lt;li&gt;Installs in &lt;strong&gt;seconds&lt;/strong&gt; in some cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seriously. They are awesome. I wish Windows was more careful about this kind of thing and that macOS supported something a bit better. I guess the application stores are getting there, but they are a little more cumbersome and not really “developer oriented”.&lt;/p&gt;

&lt;p&gt;I won’t go into this more. There are dozens of articles on the web detailing why they are great.&lt;/p&gt;

&lt;h3 id=&quot;picking-your-own-file-manager-is-great-better-selection&quot;&gt;Picking your own file manager is great, better selection&lt;/h3&gt;

&lt;p&gt;There are replacements for the file managers on Windows as well but they are not as well integrated and a lot of them I find are pretty clunky. I have found I actually really like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcmanfm&lt;/code&gt;. It has very few animations on my setup, the search is very fast, I can hop directories with little trouble, it integrates well with my dark theme, and it still has enough features to not get in my way. For example, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gvfs&lt;/code&gt; it plays with automounts fine, script executing, and good selection capabilities. And it’s integrated with my system with no additional trickery. I also tried &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dolphin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nautilus&lt;/code&gt; and found them okay as well but not quite my taste.&lt;/p&gt;

&lt;p&gt;In Windows and macOS, changing the file manager is pretty tricky across the entire system from my experience. Windows Explorer I find is pretty good. I found “Finder” almost unusable and just using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MacRanger&lt;/code&gt; on macOS for the small amount of times I need a file manager there.&lt;/p&gt;

&lt;p&gt;It was refreshing to pick something I like and being able to zip through folders at high speed.&lt;/p&gt;

&lt;h3 id=&quot;web-development-is-great-as-well&quot;&gt;Web development is great as well&lt;/h3&gt;

&lt;p&gt;There is also not much to say here, either. For my development work there were a few immediate benefits in most cases:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Reduced CPU usage in the case of some “file watcher” implementations due to better native support.&lt;/li&gt;
  &lt;li&gt;The support in general was better for a lot of tools – including Apache and Docker. I was able to spin up tons of projects and keep them running with minimal resource usage.  This was awesome – Docker Machine was unable to do that.&lt;/li&gt;
  &lt;li&gt;The Git CLI was a first class citizen. It worked great with some ZSH extensions and made me appreciate what the CLI could do that Windows was unable to do. I was used to this from macOS but it was nice to see it not exclusive to there.&lt;/li&gt;
  &lt;li&gt;Scripts other people wrote just worked. You found something on StackOverflow for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; or some other tool you wanted to run? There is a chance it is written in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bash&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;perl&lt;/code&gt; They ran with no problem without any additional tools in most cases. When they did not, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman -S&lt;/code&gt; got me sorted in a few seconds.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall, a much better experience than Windows and even a little better than macOS. I’m looking at you, long polling implementations for file watching under macOS.&lt;/p&gt;

&lt;h3 id=&quot;java---c&quot;&gt;Java  &amp;amp; C#&lt;/h3&gt;

&lt;p&gt;**C#: ** Project Rider and Visual Studio Code do a wonderful  job of giving you a competent environment to write code for this language. I was able to maintain the handful of console applications and the .NET Core applications I needed to without much trouble within these environments. They ran pretty good.  Visual Studio Code  is a bit laggy but much more responsive than Atom. Considering writing C# code on Linux was not even an option not so long ago, this is something I am excited about.&lt;/p&gt;

&lt;p&gt;**Java: ** IntellIj worked out of the box pretty much the same. No comment here.&lt;/p&gt;

&lt;p&gt;All things considered, the experience in these were on par with what I was getting before. Thus, no complaints.&lt;/p&gt;

&lt;h3 id=&quot;games-are-still-a-problem-in-some-cases-but-i-was-pleasantly-surprised-how-well-things-ran-when-they-did-work&quot;&gt;Games are still a problem in some cases, but I was pleasantly surprised how well things ran when they did work&lt;/h3&gt;

&lt;p&gt;I use Steam to play most of my games. It’s not a secret that if you want to access the largest collection of games possible, you need to have an account here. I also happen to like playing games with some of my friends on this platform. These are a few notes from  that experience.&lt;/p&gt;

&lt;p&gt;A surprising amount of   games have ports that run pretty well. For example,  Terraria had a good port and Minecraft runs very well. Civilization works well, as well. Borderlands 2 was a nice surprise, as well. Some of the games that did not have ports  would run fine under WINE. For example, the first Borderlands was played from start to finish over the Internet with a Windows user. I had a hard crash or two but other than that, everything went fine. However, there are a few times where I spent way too much time trying to get things to work. For example, “Duck Game” was not working in my prefix for some various reasons which I eventually resolved. It’s kind of annoying to have friends ping you to ask you to play – just to have to turn them down because you &lt;em&gt;cannot start the game.&lt;/em&gt;  Ouch. Nowadays, we mostly play Linux compatible titles with more and more companies releasing for the platform. For single player games, I just do not buy games that do not support my platform of choice or I just play on a console.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I made an exception for the Trails in the Sky series. The series is amazing and the XSEED team did an amazing job bringing it to us. If you have not read the struggle and immense amount of work that went into &lt;a href=&quot;https://kotaku.com/the-curse-of-kiseki-how-one-of-japans-biggest-rpgs-bar-1740055631&quot;&gt;localizing the game I suggest you read it here if you have some time.&lt;/a&gt; The article is a bit long but it comes from the heart. I’ve played the latter  two games inside of WINE with no problems since they are older.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Performance is just okay. There are a few instances where the performance has clearly taken a hit in order to be playable on Linux. There were problems unrelated to ports, too. When I first installed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dolphin-emu&lt;/code&gt; from the AUR, I was unable to play any emulated games of my choosing from my ripped library with adequate performance. Most of them would lag pretty hard. I was not the only one, either. Check out these quotes from the AUR:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Dolphin-emu is still super slow with the new Nvidia driver 364.16 (it was all good months ago).  -Neros&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’m also using NVIDIA and noticed that the performance is very impaired in some cases. I don’t know since when exactly, because I’m not playing regularly. -Martchus&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are other cases as well. At the time of writing, the problem  no longer exists. It resolved itself after a routine update sometime a few months ago. However, I am documenting it here since it was real and it stopped me from playing some of my older games without unpacking my Gamecube.&lt;/p&gt;

&lt;p&gt;In other cases, some emulators worked better under Linux in terms of compiling and setting up.  Simply put, the experience is not the same. However, for me, the experience was close enough that I am happy with it in 2017.&lt;/p&gt;

&lt;h3 id=&quot;tiling-window-managers-are-awesome&quot;&gt;Tiling window managers are awesome!&lt;/h3&gt;

&lt;p&gt;I’ve been using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3&lt;/code&gt; for a about a year now. And when Wayland hits, I think I will also check out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sway&lt;/code&gt; (&lt;a href=&quot;https://github.com/swaywm/sway&quot;&gt;link&lt;/a&gt;) and continue to use the same kind of layout for a while. These are the primary reasons I wanted to start using it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I found myself maximizing a lot of windows by hand anyway, such as Chrome and most of the windows I was “working with” and then laying them out side by side&lt;/li&gt;
  &lt;li&gt;I loved being able to snap Windows in interesting ways.  This is one of the features macOS is missing out of the box that annoys me every day.  The fact that I have to find my mouse and drag a window to fit how I want is annoying enough – this could be achieved with other window managers, but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3&lt;/code&gt; has a whole other level of control in this   category.&lt;/li&gt;
  &lt;li&gt;I wanted a keyboard driven work flow. I already spent most of my time in a terminal in Windows and in my text editor, an environment that would allow me to spend more time on my keyboard and less on the mouse was a plus.&lt;/li&gt;
  &lt;li&gt;I wanted something that would let me build something of my own, “ricing” seemed kind of fun. :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PL5ze0DjYv5DbCv9vNEzFmP6sU7ZmkGzcf&quot;&gt;I followed this set of screen casts to learn the basics&lt;/a&gt; and then after and that I went on to read the documentation to put a few more customizations in place that I required (mostly floating windows for my file manager and a few keyboard repeat settings and color changes) and then I used the setup for about a year.  These are some things I found awesome about tiling window managers, and i3 in particular:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The learning curve was not that bad at all. I think after some custom configuration I was productive using it in as little as a couple weeks.  Within a month, I was able to accomplish some tasks faster than using the old window modal method.&lt;/li&gt;
  &lt;li&gt;I was able to create my own “custom development environment” with no trouble.  I could tile a code editor, such as Atom, and a terminal on the bottom. This allowed me to use the best native bits of my platform when it was called for without needing to do a bunch of dragging on the screen. No interrupted thoughts!&lt;/li&gt;
  &lt;li&gt;I was able to create custom launch configurations and layouts for frequent tasks.&lt;/li&gt;
  &lt;li&gt;I always knew exactly where everything was.  Browser was always on Desktop 1, no more flipping through windows.  My development environment was always on  3. Scratch workspaces always on 0.  Everything has a home.&lt;/li&gt;
  &lt;li&gt;Multi-monitor support worked in the way I wanted it to. To the above point, certain workspaces were always on the other monitor. This  was super  handy for flipping to a documentation window or when playing a game with friends and I needed to pull up a Wiki page. (Need focus on that Terraria wiki page over there?  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Super +  Right&lt;/code&gt; will get you sorted out there without guessing how many “Alt-Tab”s you would need to get there. Your hands are already on the keyboard anyway, right?)&lt;/li&gt;
  &lt;li&gt;Yet, it remained able to do things I needed it to. In the Tabbed Mode of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3&lt;/code&gt;, I was able to replicate the old Alt + Tab workflow where it was needed. I could stack a bunch of things in sequence and get it done.&lt;/li&gt;
  &lt;li&gt;Minimalistic and less space taken up. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3bar&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3&lt;/code&gt; with no window chrome allows me to focus on what I am doing. I’m typing on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;typora&lt;/code&gt; right now and everything is clean and with little distraction. I can full screen any application with the press of a few buttons. There is nothing to get in my way of authoring content.&lt;/li&gt;
  &lt;li&gt;Paired with Vimium for Chrome, it was a real joy to be able to drive everything with the keyboard!&lt;/li&gt;
  &lt;li&gt;It looked great and it was mine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What was not so hot?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;File Managers were kind of harder to use. I don’t always to stack my file manager. So, I made it a popover scratch window bound to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Super +  -&lt;/code&gt;  and this lets it float over top of the other windows. This is handy when I need to just recall something very fast and don’t want to have to place it somewhere. However, it’s not the only application…&lt;/li&gt;
  &lt;li&gt;Opening things outside of the normal work flow could be annoying and take some forethought when it used to be effortless. For example, opening that JPEG of that puppy? Well, it’s going to split your screen in some way to make room for it. However, now you can only see half the puppy!  Better waste some time resizing… ah well.  I’ve worked around this by specifying manual overrides for some windows to launch in full screen or to open in specific workspaces.  In some extreme cases, I make them floating since they just work better like this. It’s a bit jarring but it’s not often I need to break out of this workflow since I normally use my PC these days to work on the same type of tasks.&lt;/li&gt;
  &lt;li&gt;Some games are not very cooperative with it. For example, sometimes they will spawn at quarter resolution in the middle of the screen and I have to hunt them with my mouse and then full screen them. Annoying. But livable.&lt;/li&gt;
  &lt;li&gt;Other people have no idea how to use my computer. My life partner knows how to use it when she needs to from time to time but I had to show her a few things.  It’s not very friendly to people who have no idea what they are doing. However, in the end it’s my machine to work done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will also say this: The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3&lt;/code&gt; developers have done a great job making things robust and stable. I have not had to fix or tweak my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.i3config&lt;/code&gt; much since I created it. Things have just been working. Kudos! If you have not tried a tiling window manager and you have similar needs to me, it would be worth checking out at least. I was skeptical at first but it was a game changer for me.&lt;/p&gt;

&lt;h3 id=&quot;misc-moments-where-i-thought-this-is-amazing&quot;&gt;Misc moments where I thought: “This is &lt;strong&gt;amazing&lt;/strong&gt;!”&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Forgot to sleep the PC before bed and already tucked in? Within 30 seconds, I was able to SSH in to the already installed and configured daemon (from a prior setup) and simply sleep it from the CLI.&lt;/li&gt;
  &lt;li&gt;Native SSH is awesome for administering a file server. Sure, there is Putty on Windows which is widely used but it’s just not nearly as nice. Nothing is as good as using your terminal from your own computer with all your configuration already setup.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsnapshot&lt;/code&gt; is amazing and I love backing up my server with it. Part of this is the great filesystems provided and available with Linux.&lt;/li&gt;
  &lt;li&gt;Dotfiles synced with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Git&lt;/code&gt; to my laptop is nice. Keeping configs in sync on other platforms is less than fun without some kind of cloud storage.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Being able to modify the source code of a package, and then have it still managed by my package manager&lt;/strong&gt;. This is a great feeling, even if a bit of a hack. You can read more on my .NET Core experience to know why this was a boon but being able to just modify an “installer” that was open and &lt;strong&gt;fix my problem&lt;/strong&gt; is great.&lt;/li&gt;
  &lt;li&gt;Just running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;youtube-dl&lt;/code&gt; against a site and noticing that I was already running the most up to date version and that I would not have to waste time making sure I was up to date. The same goes with other packages.&lt;/li&gt;
  &lt;li&gt;Hey, I can run the tools my server is running!&lt;/li&gt;
  &lt;li&gt;I didn’t like the color of some things on the my GTK theme. So, I opened up the theme overrides and applied some CSS. Done.&lt;/li&gt;
  &lt;li&gt;Docker is working the way I wanted it to!!&lt;/li&gt;
  &lt;li&gt;When was the last time I was nagged to do a system update, again?&lt;/li&gt;
  &lt;li&gt;Stability: I have had up time that was longer than I should admit because I really should have patched my kernel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;so-what-are-some-of-the-things-that-bothered-me-more&quot;&gt;So, what are some of the things that bothered me more?&lt;/h2&gt;

&lt;p&gt;There’s a few things that bother me and they might have something to do with me running an odd setup. However, I wanted to give an honest recollection from someone who just dove right in.&lt;/p&gt;

&lt;h3 id=&quot;january-2017-infinality-fiasco&quot;&gt;January 2017: Infinality fiasco&lt;/h3&gt;

&lt;p&gt;I did a full system update like any other day. Then, I got a bunch of errors about repositories that I had been using being discontinued. I guess “Infinality” had been discontinued and it was now up to me to decide what to do. I was not able to update until I resolved it.&lt;/p&gt;

&lt;p&gt;I probably spent a couple hours resolving things while I was trying to figure out what was going on. At the same time, I really needed a newer version of a package and this was kind of in the way. Arch has a pseduo-rule that you should never do partial  upgrades, so that was out of the question.&lt;/p&gt;

&lt;p&gt;In the end, I found some advice to migrate away and managed to get my system into a better state.&lt;/p&gt;

&lt;h3 id=&quot;april-2017-microsoft-word-stops-working-in-wine&quot;&gt;April 2017: Microsoft Word stops working in WINE&lt;/h3&gt;

&lt;p&gt;A day in April I did a full system update, using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman&lt;/code&gt; and then tried to run my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wine-prefix&lt;/code&gt; containing &lt;strong&gt;Microsoft Word&lt;/strong&gt;. Yeah, I was using this product since I was used to it and needed something to ease the transition. It stopped working, WINE was a pain to debug and in the end I discovered I really only needed Google Documents and LibreOffice for the occasional thing. So, I never got to the bottom of this. However, it is annoying that things stop working “randomly”.&lt;/p&gt;

&lt;p&gt;I treat this as a minor incident but I wanted to point it out since a lot of the time you will hear the rumour that “Arch does not break! It is user error if your system stops working.”&lt;/p&gt;

&lt;p&gt;User-space applications certainly do break sometimes.&lt;/p&gt;

&lt;h3 id=&quot;august-2017-net-core&quot;&gt;August 2017: .NET Core&lt;/h3&gt;

&lt;p&gt;I was working on a new client project and had inherited some .NET Core code that was already running in production. I had the goal of adding some new features to and re-writing the UI. I estimated this would probably take a dozen hours or so, of which maybe 10 of them would be billable. The rest of them would be new environment configuration that I was responsible for since I had not worked in .NET Core before. I was pretty excited to start especially since Microsoft had announced recently that .NET Core support would be coming to Linux. They had even announced a cool new editor that is now loved by many, known as Visual Studio Code. Alas, things were not so easy…&lt;/p&gt;

&lt;p&gt;Arch Linux was not a supported problem. I ran to the &lt;strong&gt;AUR&lt;/strong&gt; which is my response to these kinds of things to see what I could find. I found a package (that is no longer available now) and installed it. The package itself installed fine without many problems and I wrote a couple “Hello World” applications. I started up a basic ASP.NET core project as well and everything seemed fine. &lt;em&gt;Success!&lt;/em&gt; or so I thought. As it would turn out, making any sort of database query would cause a native exception to be thrown. You can read about how I ended up resolving this &lt;a href=&quot;http://vaughanhilts.me/blog/2017/02/06/openssl-with-sslv3-on-arch-linux-for-dot-net-core.html&quot;&gt;here&lt;/a&gt; but in the end it ended up costing me over 6 hours to debug this thing and trace it down. I doubt I am the only one either, since if you end up searching for my post, it’s linked around the web a few times as well as the solution to the problem for the .NET Core 1.x series. I have not followed up to see if the .NET Core 2.x series has this problem.&lt;/p&gt;

&lt;p&gt;In the end, it was not so bad but on Windows this probably would have worked out of the box considering it’s Microsoft’s own platform. Then again, I have vague memories of installing Visual Studio and it not starting and having no recourse to debug…&lt;/p&gt;

&lt;h3 id=&quot;november-2017-full-machine-breakage&quot;&gt;November 2017: Full Machine Breakage&lt;/h3&gt;

&lt;p&gt;I ran a full system update and there was an OpenSSL change. I took the upgrades and followed  the mailing list advice but still ended up with a bricked machine. A little disappointing but it was probably my fault somehow. Still, bricking a machine is no fun. The journal had indicated something about failed updates and failure to rollback – so I left it for a while.&lt;/p&gt;

&lt;p&gt;I never did figure out the exact problem, however, when I did &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt; into the machine from a different PC and ran another full system update the next day, the problem resolved itself.  +1 for being able to read your logs, huh?&lt;/p&gt;

&lt;p&gt;Huh. I still need to dig into this one.&lt;/p&gt;

&lt;h3 id=&quot;reverse-engineering-tools-still-arent-all-the-way-there&quot;&gt;Reverse Engineering Tools still aren’t all the way there&lt;/h3&gt;

&lt;p&gt;In one of my &lt;a href=&quot;http://vaughanhilts.me/blog/2016/11/16/reverse-engineering-trails-in-the-sky-ed-6-game-engine.html&quot;&gt;previous posts&lt;/a&gt;, I reverse-engineered the game “Trails in the Sky” and provided an introduction to &lt;a href=&quot;http://kaitai.io/&quot;&gt;Kaitai Struct&lt;/a&gt; inside of it. You will notice I used a lot of NIX* tools in that guide. However, what is glossed over, is that a lot of the debugging was done on Windows with a debugger there. This is partly because the game is a Windows Executable and partly because the tools for debugging them were just better over there. There’s a couple reasons for that but it all stems to the ecosystem:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There are better memory editors on Windows, such as Cheat Engine that aided in probing the data&lt;/li&gt;
  &lt;li&gt;There are better debuggers for Windows executables there. The reason should be obvious: most developers debug  Windows Executables on Windows&lt;/li&gt;
  &lt;li&gt;I was able to actually able to &lt;strong&gt;run&lt;/strong&gt;  the executable there without needing to have WINE running as an abstraction over top of it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;gimp-is-no-photoshop&quot;&gt;GIMP is no Photoshop&lt;/h3&gt;

&lt;p&gt;Some people might try and convince you that &lt;strong&gt;GIMP&lt;/strong&gt; is a fine replacement but they were probably not power users. It’s true, if you just need to move some things around on a canvas and trim them, it is probably fine. Even for basic effects, it is probably fine. However, I found when loading complicated images and trying to do operations, things were just too different. Could I have done them with GIMP? Yeah, I probably could have. For now? I will stick to the free edition of &lt;a href=&quot;http://www.redmondpie.com/download-adobe-photoshop-cs2-for-free-legally-while-you-still-can/&quot;&gt;Photoshop CS2&lt;/a&gt; that was given out and use my time for other things that are of more value for me. There are only so many hours in the day and re-learning an image editing tool for the simple tasks I need to do are not worth my time. For the record, I found even basic stuff like: scaling layers, adding text effects, actions, and blending modes – a bit cumbersome. I think it was a combination of unfamiliarity and the clumsy UI.  It also did not cooperate very well out of the box with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i3wm&lt;/code&gt; and I had to do some setting tweaks and set it to full screen to get it to work even remotely well.&lt;/p&gt;

&lt;h3 id=&quot;playonlinux-is-not-all-that-good-in-a-lot-of-cases&quot;&gt;PlayOnLinux is not all that good in a lot of cases&lt;/h3&gt;

&lt;p&gt;For some of the Windows applications I was holding onto, I was trying to run them in a wine prefix under PlayOnLinux. I figured that since I only had a couple applications that I wanted to run, as the the old Photoshop CS2, I could just use this and not worry about learning the details. Unfortunately, in a lot of cases the scripts are older and use a very old WINE version. In some extreme cases, they do not work at all anymore. I assume this is due to changing systems and things probably do not look like they did when they were written. I learned fairly quick that backwards comparability in some parts of the ecosystem is not a priority.  In the end, I decided to just use a virtual machine for the occasional thing I needed and it worked great.&lt;/p&gt;

&lt;h3 id=&quot;misc-things-that-annoy--me&quot;&gt;Misc. things that annoy  me&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Atom randomly bugs out and there are visual artifacts. The tree view will go away, sometimes.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/linux_gaming/comments/64gfz6/raising_awareness_xbox_360_controller_does_not/&quot;&gt;Occasionally, a Linux kernel will break something on me. I am not this user, but you are not alone, user&lt;/a&gt;!&lt;/li&gt;
  &lt;li&gt;When a package is unsupported by my distro, it becomes up to me. The diversity of the distros is also a weakness.&lt;/li&gt;
  &lt;li&gt;Screen tearing is still a thing sometimes along with audio and video desynch on YouTube. I’ve heard “Wayland” might fix these problems – so I wait patiently.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;going-to-jump-in-heres-some-main-take-aways&quot;&gt;Going to jump in? Here’s some main take aways&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Make sure you know what your distribution is like and how likely you are to end up with a system that could be broken. If you can’t tolerate your machine being down for a day and needing to resolve a few issues here and there, rolling release distributions are probably not for you, at least not of the Arch based variety. I have heard good things about Solus.&lt;/li&gt;
  &lt;li&gt;Embrace the change. Do not let yourself become restricted to something Windows-esque and instead let yourself try some new paradigms. You may just fall in love. Try a new window manager. Use your package manager a lot. Automate tasks with powerful shell scripting.&lt;/li&gt;
  &lt;li&gt;Be prepared for some frustrating nights. There will be problems and a learning curve to conquer. Linux is still not perfect even in 2017&lt;/li&gt;
  &lt;li&gt;Not all your games are going to work in WINE and you will have to just accept that it is not a main goal of the Linux ecosystem.&lt;/li&gt;
  &lt;li&gt;Follow some forums on the web and become engrossed. There are several on the web, but  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/r/linux&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/r/archlinux&lt;/code&gt; for me in particular were helpful on Reddit in order to keep up on how things were doing. You will be happier if you are aware of what is going on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;Arch Linux was cool and it let me learn a lot. I think Linux in general is pretty awesome and I want to continue using it as my daily driver. I think will probably continue to do so for a while. That being said, there are some very cool distributions that are cropping up lately that are now on my radar. I like the “DIY” experience but not the breakage that comes with it some cases.  Perhaps I can find something that can meet me in the middle, but that is the joys of the Linux ecosystem, I can choose…&lt;/p&gt;

&lt;p&gt;With the Windows Subsystem on Linux now available as well, I plan on giving that a try and seeing how much of the tools that I am using can be used there now. I have a feeling that some of the pros I have listed will become the gold standard there now, such as the NIX* tools working out of the box. Games will work a heck of a lot better there, too, I am sure.  And despite the random complaints on the Internet sometimes, I would probably get less random breakages in some cases, since there are less choices to make.&lt;/p&gt;

&lt;p&gt;But in the end? I think I will stay where I am for now.  There is much more to learn and so much more to gain.  Compared to the pain, I think I am still way ahead.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Misc Development Tip - Move through blocks of text faster by simply increasing key repeat rate</title>
   <link href="http://vaughanhilts.me/blog/2017/10/16/for-faster-development-consider-changing-your-key-repeat-settings.html"/>
   <updated>2017-10-16T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2017/10/16/for-faster-development-consider-changing-your-key-repeat-settings</id>
   <content type="html">&lt;h1 id=&quot;tired-of-slow-scrolling-through-code-try-changing-your-key-repeat-rate&quot;&gt;Tired of slow scrolling through code? Try changing your key repeat rate&lt;/h1&gt;

&lt;p&gt;As part of an ongoing attempt to keep my development speedy and find those little micro optimizations that will make my workflow just a little bit faster, I found something I noticed while browsing some programming streams today. Specifically, some editors have very fast scroll speeds.&lt;/p&gt;

&lt;p&gt;When I hold my arrow keys to navigate from code block to code block (when not using the navigational shortcuts) there are times where it seems like the cursor just drags on forever.&lt;/p&gt;

&lt;p&gt;If you’re using Linux like I am, trying reduce your key repeat delay and then increase the amounts of repeat using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xset&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;xset r rate 150 55
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It makes a huge difference in terms of being able to scale through a ton of text effectively.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Dotnet Core Getting Around System Cryptography Initialization Error</title>
   <link href="http://vaughanhilts.me/2017/02/20/dotnet-core-getting-around-system-cryptography-initialization-error.html"/>
   <updated>2017-02-20T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/2017/02/20/dotnet-core-getting-around-system-cryptography-initialization-error</id>
   <content type="html">&lt;h1 id=&quot;systemsecuritycryptographynative-error-on-a-web-request-upgrade-systemnethttp-for-net-core&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Security.Cryptography.Native&lt;/code&gt; error on a web request? Upgrade &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Net.Http&lt;/code&gt; for .NET Core&lt;/h1&gt;

&lt;p&gt;I downloaded a sample .NET Core project off the web to play around with it. It was making use of web requests to proxy some data around the web. Everything was running fine until it would make an actual web request on my &lt;strong&gt;Arch Linux&lt;/strong&gt; machine…&lt;/p&gt;

&lt;div class=&quot;language-c# highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DllNotFoundException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Unable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DLL&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Security&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Cryptography&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Native&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;n&quot;&gt;The&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specified&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;could&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HRESULT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0x8007007E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Interop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Crypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetMaxMdSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Interop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Crypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cctor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ugh! This would happen every time I would make an outbound network request on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4.1.0&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Net.Http&lt;/code&gt; which is the version that was being used. The solution? I simply upgraded to the latest version, which as of writing today, is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4.3.0&lt;/code&gt; The problem went away.&lt;/p&gt;

&lt;p&gt;I am not sure if this was a bug being triggered or not but it seemed to have worked. Frustratingly, this was originally a red herring for my other &lt;a href=&quot;/openssl-with-sslv3-on-arch-linux-for-dot-net-core.html&quot;&gt;problem that I had a few weeks ago&lt;/a&gt; – oh well. :(&lt;/p&gt;

&lt;p&gt;I hope this helps someone else.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Dotnet Core Global Json Make Sure It Is At Your Root</title>
   <link href="http://vaughanhilts.me/2017/02/19/dotnet-core-global-json-make-sure-it-is-at-your-root.html"/>
   <updated>2017-02-19T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/2017/02/19/dotnet-core-global-json-make-sure-it-is-at-your-root</id>
   <content type="html">&lt;h1 id=&quot;net-core-make-sure-globaljson-is-at-the-root-of-your-repo&quot;&gt;.NET Core: Make sure global.json is at the root of your repo&lt;/h1&gt;

&lt;p&gt;I was recently writing some .NET Core code and I was getting some strange error messages. It was something like…&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Can't parse project.json(1,1)&quot;&lt;/span&gt;		
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This was when I was deploying my application to Azure. As it would turn out, if you do not specify a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global.json&lt;/code&gt; then Azure will automatically pick the latest version for you. This is a recipe for disaster considering I had not upgraded to the ABSOLUTE latest, as of yet.&lt;/p&gt;

&lt;p&gt;As it would turn out, it would seem that in .NET Core 1.1 had migrated to kill off the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;project.json&lt;/code&gt; format in favour of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.csproj&lt;/code&gt; style a la &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSBuild&lt;/code&gt;. I was not ready to migrate yet.&lt;/p&gt;

&lt;p&gt;The fix is simple: just add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global.json&lt;/code&gt; specifying your SDK version. Or it would be, anyway if your file structure was that your app was at the root of the repo. Alas, that was not me so I got the above error message over and over.&lt;/p&gt;

&lt;p&gt;The solution was to simply drop &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global.json&lt;/code&gt; into the root directory of my source control folder (and not in 
the same directory as the application). Bam, 
everything worked.&lt;/p&gt;

&lt;p&gt;I hope this helps someone out.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Recompiling OpenSSL with SSLv3 Support on Arch Linux for use with .NET Core</title>
   <link href="http://vaughanhilts.me/blog/2017/02/06/openssl-with-sslv3-on-arch-linux-for-dot-net-core.html"/>
   <updated>2017-02-06T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2017/02/06/openssl-with-sslv3-on-arch-linux-for-dot-net-core</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;NOTICE: As of .NET Core 2, this is no longer a problem. If you can upgrade your project and you were considering it already, you might as well do it to avoid this problem if you are having it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I was recently working on a project for a client and was trying to use the new .NET Core technology by Microsoft. Of course, this is not a supported platform for my operating system of choice. However, that did not stop me from trying to run with it.&lt;/p&gt;

&lt;p&gt;A lot of stuff works but Entity Framework does not out of the box. You will get the following error trying to run a query:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/opt/dotnet/dotnet: relocation error: /opt/dotnet/shared/Microsoft.NETCore.App/1.1.0/System.Security.Cryptography.Native.OpenSsl.so: symbol SSLv3_method, version OPENSSL_1.0.0 not defined in file libssl.so.1.0.0 with link time reference...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As it turns out, Arch Linux removed SSLv3 in this &lt;a href=&quot;https://git.archlinux.org/svntogit/packages.git/commit/trunk?h=packages/openssl&amp;amp;id=4b82ed4285c7cb76caf6d75a015c5a7542c625d1&quot;&gt;commit&lt;/a&gt;. There are some solutions like recompiling your application
that is using the SSLv3 stuff and stripping it off. Considering my stuff was from the AUR and I had other packages that had this problem and I did not feel like recompiling them all to get my work done, I decided to just add the support back myself
until I could decide how to tackle it. If anyone else is having this issue and needs SSLv3 back to get this working, you can follow the directions below:&lt;/p&gt;

&lt;p&gt;We’ll apply patches to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PKGBUILD&lt;/code&gt; provided by the Arch repos to include SSLv3 support. This is important to note as some advice is to downgrade your package on various parts of the WWW. This
is generally actually a bad idea since OpenSSL often has security vulnerabilities. Being several years behind on security patches is far worse.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Install &lt;a href=&quot;https://aur.archlinux.org/packages/customizepkg-git/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;customizepkg-git&lt;/code&gt;&lt;/a&gt; from the AUR.&lt;/li&gt;
  &lt;li&gt;Create a definition for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt; package to patch. To do this…&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo nano /etc/customizepkg.d/openssl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;**NOTICE / EDIT: ** It has come to my attention after upgrading my Arch Linux box, that the OpenSSL v1 has been replaced with OpenSSL v1 Compatability library from the AUR. So first of all, make sure &lt;a href=&quot;https://aur.archlinux.org/packages/libopenssl-1.0-compat/&quot;&gt;you have this package.&lt;/a&gt;. Secondly, make sure you edit the the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libopenssl-1.0-compat&lt;/code&gt; file instead, i.e:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo nano /etc/customizepkg.d/libopenssl-1.0-compat
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;instead…. continue on. :)&lt;/p&gt;

&lt;p&gt;and then put the following contents into the above file (most likely the compatabiltiy file if you are reading this on an updated system post June 2017)…&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;replace#global#no-ssl3-method#zlib
replace#global#no-ssl3#zlib
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;Then, just do a system update or just reinstall SSL (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yaourt -S openssl&lt;/code&gt;). You should see the diff shown and be able to just continue installing with support.&lt;/li&gt;
  &lt;li&gt;If this fails, you may need to install the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpg&lt;/code&gt; key for the package, i.e: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpg --recv-keys D9C4D26D0E604491&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Once the build is finished (took a couple minutes on my i5 2500) you should have SSLv3 support&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;… and that should enable quite a few applications on Arch Linux that have issues with this to begin working, including .NET Core. If you don’t want to enable this system wide, you can consider recompiling .NET Core’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;corefx&lt;/code&gt; assemblies
to accomplish this same kind of goal.&lt;/p&gt;

&lt;p&gt;For me, this is enough for a development machine. I hope this helps others.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Unlinking MKVs on Windows, OSX, and Linux - Native C# Port</title>
   <link href="http://vaughanhilts.me/blog/2016/11/27/unlinking-mkvs-natively.html"/>
   <updated>2016-11-27T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2016/11/27/unlinking-mkvs-natively</id>
   <content type="html">&lt;p&gt;You may have seen my &lt;a href=&quot;http://vaughanhilts.me/blog/2015/04/30/unlinking-mkvs-on-windows-osx-linux.html&quot;&gt;other post&lt;/a&gt; on unlinking those pesky segmented MKVs that I posted a while back. Lots of users have tried it out and it works pretty well – however, the original Perl port had a few issues with it. Mainly:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It required a lot of dependencies that Windows users weren’t used to having, such as “Strawberry Perl” since it’s not something that runs on Windows “natively”&lt;/li&gt;
  &lt;li&gt;It had a couple bugs that were hard to fix, since I am not a native Perl programmer. This made it hard to make it work for every release I wanted.&lt;/li&gt;
  &lt;li&gt;It made some assumptions about the process that have since been fixed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since I was still getting bug reports well into 2016 about certain MKV files not working with the process and I was having some bugs myself with certain files, I decided to rewrite a quick native port in C#
of the actual merge logic in order to work around these three issues.&lt;/p&gt;

&lt;h1 id=&quot;brute-force-linear-ordering&quot;&gt;Brute-Force Linear Ordering&lt;/h1&gt;

&lt;p&gt;The biggest bug I had to deal with was files that looked something like this:&lt;/p&gt;

&lt;pre&gt;mediainfo file.mkv
Menu
00:00:00.000                             : en:Prologue / en:Opening / en:Ending
00:05:57.019                             : en:Episode
00:22:40.059                             : en:Preview&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;MKVUnlink (Perl) was handling these pretty good but would occasionally trip up on these. If you look at the order inside the actual MKV itself, the chapters are presented in sequence but their timecodes are all wrong. I’m not sure if there is something I am not understanding or if this is just a bug in the way they were split out. A lot of media playback software that actually supported segmented playback actually worked find with these files so I was not sure. However, the algorithim I was using and that UnlinkMKV was using simply did not work sometimes for these files.&lt;/p&gt;

&lt;p&gt;The solution is to linearize these, you see the implementation online at &lt;a href=&quot;https://github.com/hilts-vaughan/UnlinkMKV-GUI/blob/master/UnlinkMKV-GUI/UnlinkMKV-GUI/merge/SegmentTimecodeSelector.cs&quot;&gt;Github&lt;/a&gt; but the basic premise is to just take the order the chapters and for each:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Measure the duration of the current clip&lt;/li&gt;
  &lt;li&gt;Set the start timecode of the current chapter to the end timecode of the previous&lt;/li&gt;
  &lt;li&gt;Then, make the ending equal to the duration + the start of the old timecode&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This will make everything nice and linear. The process only has to be carried out if the sequence is kind of out of order. Either way, this fixes a few issues with a couple MKV files that were giving me grief.&lt;/p&gt;

&lt;p&gt;You can download this new release on Github today &lt;a href=&quot;https://github.com/hilts-vaughan/UnlinkMKV-GUI/releases/tag/0.2.0&quot;&gt;here&lt;/a&gt; which contains quite a few of the bugfixes. I hope in the future, every player can just support the segmented format and we won’t have any need for software like this. For now, if you find any bugs please leave an issue open on Github.&lt;/p&gt;

&lt;p&gt;To use the new “Native Mode”, just tick the “Native Mode” in the GUI.&lt;/p&gt;

&lt;p&gt;Any feedback? Experienced a similar issue? Feel free to post about it below in the comments.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Experimentation with Reverse Engineering - Trails in the Sky (FC / SC) Extracting Sprite Data w/ Unix Tools & Kaitai Struct</title>
   <link href="http://vaughanhilts.me/blog/2016/11/16/reverse-engineering-trails-in-the-sky-ed-6-game-engine.html"/>
   <updated>2016-11-16T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2016/11/16/reverse-engineering-trails-in-the-sky-ed-6-game-engine</id>
   <content type="html">&lt;p&gt;I recently began and finished the great &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Legend_of_Heroes:_Trails_in_the_Sky&quot;&gt;Trails in the Sky&lt;/a&gt; series
and was amazed at some of the technical skill that was used in such an old game (developed originally in 2001) and remastered for the English release.
At the same time, I was interested in the internals of reverse engineering and how such things were performed. After reading an article I found on Reddit
that covered the process of decompiling a &lt;a href=&quot;https://hackernoon.com/reverse-engineering-visual-novels-101-d0bc3bf7ab8#.hmxrond8d&quot;&gt;Japanese visual novel game&lt;/a&gt;, I decided that now would be as good of a time as ever to give it a try.&lt;/p&gt;

&lt;p&gt;The below post chronicles what I had to do to get it prepared for examination, including unpacking and my thoughts while reverse-engineering the file format(s)
provided by the game. I’ll be doing this all on Arch Linux with the aid of a Windows VM for limited functionality but you all the information here should be applicable on any UNIX system and most of it should apply to Windows with some substitution.&lt;/p&gt;

&lt;h1 id=&quot;examining-the-game-folder-and-the-data-files-within&quot;&gt;Examining the game folder and the data files within&lt;/h1&gt;

&lt;p&gt;The first thing we should do when examining a piece of software we want to decompile is to see what we have to work with and what seems interesting. I’m going to work with Trails in the Sky (FC) in this case but the sequel shares a lot of traits it would seem. After installing the game from the Steam client, I entered the directory and ran a quick &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt; to figure out what I had to work with.&lt;/p&gt;

&lt;pre&gt;touma@setsuna:common/Trails in the Sky FC $ ls -la
total 1986388
drwxr-xr-x  5 touma touma      4096 Oct 20 23:19 .
drwxr-xr-x 10 touma touma      4096 Nov  5 20:43 ..
drwxr-xr-x  2 touma touma      4096 Nov  5  2015 BGM
drwxr-xr-x  4 touma touma      4096 Nov  5  2015 _CommonRedist
-rwxr-xr-x  1 touma touma    787968 Feb  7  2016 Config.exe
drwxr-xr-x  2 touma touma      4096 Nov  5  2015 dll
-rw-r--r--  1 touma touma    165311 Oct 20 20:08 dump
-rw-r--r--  1 touma touma  35621809 Feb  7  2016 ED6_DT00.dat
-rw-r--r--  1 touma touma     18448 Feb  7  2016 ED6_DT00.dir
-rw-r--r--  1 touma touma   2468101 Dec 16  2015 ED6_DT01.dat
-rw-r--r--  1 touma touma     36880 Dec 16  2015 ED6_DT01.dir
-rw-r--r--  1 touma touma    199759 Nov  5  2015 ED6_DT02.dat
-rw-r--r--  1 touma touma      9232 Nov  5  2015 ED6_DT02.dir
-rw-r--r--  1 touma touma   8696670 Nov  5  2015 ED6_DT03.dat
-rw-r--r--  1 touma touma     18448 Nov  5  2015 ED6_DT03.dir
-rw-r--r--  1 touma touma  18093622 Nov  5  2015 ED6_DT04.dat
-rw-r--r--  1 touma touma      9232 Nov  5  2015 ED6_DT04.dir
-rw-r--r--  1 touma touma  24291816 Nov  5  2015 ED6_DT05.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT05.dir
-rw-r--r--  1 touma touma  11260428 Nov  5  2015 ED6_DT06.dat
-rw-r--r--  1 touma touma     18448 Nov  5  2015 ED6_DT06.dir
-rw-r--r--  1 touma touma  66609144 Nov  5  2015 ED6_DT07.dat
-rw-r--r--  1 touma touma     72016 Nov  5  2015 ED6_DT07.dir
-rw-r--r--  1 touma touma 226823581 Nov  5  2015 ED6_DT08.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT08.dir
-rw-r--r--  1 touma touma 152468135 Nov  5  2015 ED6_DT09.dat
-rw-r--r--  1 touma touma     46096 Nov  5  2015 ED6_DT09.dir
-rw-r--r--  1 touma touma 222776216 Nov  5  2015 ED6_DT0A.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT0A.dir
-rw-r--r--  1 touma touma 121100311 Nov  5  2015 ED6_DT0B.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT0B.dir
-rw-r--r--  1 touma touma  26658261 Nov  5  2015 ED6_DT0C.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT0C.dir
-rw-r--r--  1 touma touma   6742488 Nov  5  2015 ED6_DT0D.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT0D.dir
-rw-r--r--  1 touma touma     91156 Nov  5  2015 ED6_DT0E.dat
-rw-r--r--  1 touma touma      9232 Nov  5  2015 ED6_DT0E.dir
-rw-r--r--  1 touma touma   1164468 Nov  5  2015 ED6_DT0F.dat
-rw-r--r--  1 touma touma      9232 Nov  5  2015 ED6_DT0F.dir
-rw-r--r--  1 touma touma    221582 Nov  5  2015 ED6_DT10.dat
-rw-r--r--  1 touma touma     18448 Nov  5  2015 ED6_DT10.dir
-rw-r--r--  1 touma touma    189950 Nov  5  2015 ED6_DT11.dat
-rw-r--r--  1 touma touma     18448 Nov  5  2015 ED6_DT11.dir
-rw-r--r--  1 touma touma    441915 Nov  5  2015 ED6_DT12.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT12.dir
-rw-r--r--  1 touma touma  13191634 Nov  5  2015 ED6_DT13.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT13.dir
-rw-r--r--  1 touma touma 428173213 Nov  5  2015 ED6_DT14.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT14.dir
-rw-r--r--  1 touma touma 254700304 Nov  7  2015 ED6_DT15.dat
-rw-r--r--  1 touma touma     73708 Nov  7  2015 ED6_DT15.dir
-rw-r--r--  1 touma touma  15105502 Nov  5  2015 ED6_DT16.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT16.dir
-rw-r--r--  1 touma touma  77669890 Nov  5  2015 ED6_DT17.dat
-rw-r--r--  1 touma touma  85893124 Nov  5  2015 ED6_DT18.dat
-rw-r--r--  1 touma touma      9011 Nov  5  2015 ED6_DT19.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT19.dir
-rw-r--r--  1 touma touma  47053132 Nov  5  2015 ED6_DT1B.dat
-rw-r--r--  1 touma touma     73708 Nov  5  2015 ED6_DT1B.dir
-rw-r--r--  1 touma touma   3992401 Nov  5  2015 ED6_DT1C.dat
-rw-r--r--  1 touma touma     18448 Nov  5  2015 ED6_DT1C.dir
-rw-r--r--  1 touma touma    581636 Nov  5  2015 ed6_logo.avi
-rw-r--r--  1 touma touma 176822844 Nov  5  2015 ed6_op.avi
-rwxr-xr-x  1 touma touma   2019776 Feb  7  2016 ed6_win.exe
-rw-r--r--  1 touma touma    215120 Feb  7  2016 steam_api.dll
-rw-r--r--  1 touma touma     81768 Nov 27  2015 xinput1_3.dll&lt;/pre&gt;

&lt;hr /&gt;
&lt;p&gt;There’s a few interesting files in here for sure, but the one we’ll cover first off are the &lt;em&gt;ED6_DTXX.(DAT|DIR)&lt;/em&gt; files as they’re the most interesting to us off a glance. Looking at the file size, it looks like these are probably archives for a bunch of game files. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DIR&lt;/code&gt; files also sound like a case of some kind of &lt;a href=&quot;https://en.wikipedia.org/wiki/Virtual_file_system&quot;&gt;virtual filesystem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For those who were not familiar for the reason this is done, it’s a very popular strategy in PC and console games. You can read a great answer on the Game Development Stack Exchange &lt;a href=&quot;http://gamedev.stackexchange.com/a/20248/17541&quot;&gt;right here&lt;/a&gt;. To briefly summarize:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Faster loading times since there’s less seek&lt;/li&gt;
  &lt;li&gt;Full control of data, no OS&lt;/li&gt;
  &lt;li&gt;Compression can be more effective, especially if data is packed tightly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A few Google queries reveals that the company who originally developed the game, FALCOM, has been known to use a specific archive format for a while and there are well known decompression programs available. Unfortunately, I was not be able to find much in the way of documentation. One of interest for us in particular is the “Falcom Data Archive Conversion Utility”, or just &lt;a href=&quot;http://www.pokanchan.jp/dokuwiki/software/falcnvrt/start&quot;&gt;falcnvrt&lt;/a&gt; for short.&lt;/p&gt;

&lt;p&gt;As it would turn out, this application can decompress the DAT files into directories:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/re/trails_001/falcncnvrt.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If we go ahead and instruct it to encode them into PNGs for us, we will have them converted to a friendly format. This is because as it turns out, Falcom uses a custom raster bitmap format that isn’t readable by standard programs. Since we’re mostly interested in data right now and not the raster format, we’ll skip over how this is done and just chalk it up to the good work of the community.&lt;/p&gt;

&lt;p&gt;With that, let’s dive deep…&lt;/p&gt;

&lt;h1 id=&quot;locating-some-sprites-and-their-metadata&quot;&gt;Locating some sprites and their metadata&lt;/h1&gt;

&lt;p&gt;Let’s take a look at what we would get from unpacking:&lt;/p&gt;

&lt;pre&gt;touma@setsuna:~/unpacked $ find . -name &quot;*.png*&quot; | grep -E -o &quot;ED6_DT..&quot; | sort | uniq
ED6_DT06
ED6_DT07
ED6_DT09
ED6_DT20
ED6_DT23
ED6_DT24
ED6_DT25
ED6_DT26
ED6_DT27
ED6_DT29
ED6_DT2F
ED6_DT33
ED6_DT35
ED6_DT36
ED6_DT3A
ED6_DT3C&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;OK, looks like these are some PNGs in those directories for us to take a look at. If we poke around at some of these files, we’ll find
some interest things but what we can start with is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ED6_DT07/CH00000.png&lt;/code&gt; which represents the sprite of our Heroine, Estelle. More importantly, there seems to be an accompanying file named aptly &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CH00000P.SCP&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s get some metrics on these files:&lt;/p&gt;

&lt;pre&gt;touma@setsuna:unpacked $ file CH00000.png
CH00000.png: PNG image data, 256 x 16384, 8-bit/color RGBA, non-interlaced
touma@setsuna:unpacked $ file CH00000._CH
CH00000._CH: data
touma@setsuna:unpacked $ &lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;The latter is not very interesting but the former has some information to use in the way of sizing that would be informative to us. Using a little bit of knowledge of spritesheets we can guess that each frame is 256x256. This is because often in video games we use textures and sub textures that are powers of two and square because traditionally, GPUs can render these kinds of textures better and more efficiently. There’s no science to this guess then aside from some educated guesses.&lt;/p&gt;

&lt;p&gt;Let’s verify this claim by loading it up into an image editor and setting some grids. I will be using Photoshop as it is a tool I am familiar with but you could really use anything that you have handy. By setting up sub-grids of 256x256 across the entire sprite sheet, we can visually determine if the spritesheet would have a high likelihood of satisfying our guess.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/re/trails_001/estelle.png&quot; alt=&quot;estelle&quot; /&gt;
&lt;em&gt;The above is done by using Photoshop “Grid &amp;amp; Slices” set to 256x256 to visualize the boundaries.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yep, the frames seem to fit snuggly.&lt;/p&gt;

&lt;p&gt;Before going forward, it helps to know characteristics of the file we are attacking and what we might look for. In the case of a sprite file, there are a few desirable characteristics that we should fine.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A definition file will likely define the width and height of a frame if it’s not fixed&lt;/li&gt;
  &lt;li&gt;The number of frames may be present somewhere in the file&lt;/li&gt;
  &lt;li&gt;Timing and animation information may also be present&lt;/li&gt;
  &lt;li&gt;Misc headers. which may / may not be useful to us&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can keep this in mind when examining the file.&lt;/p&gt;

&lt;h1 id=&quot;extracting-metadata&quot;&gt;Extracting metadata&lt;/h1&gt;

&lt;p&gt;OK, next up… let’s dump the metadata and see what we can gleam on first glance. Most files start with a header, so let’s begin there to see what we can see:&lt;/p&gt;

&lt;pre&gt;touma@setsuna:unpacked/ED6_DT07 $ hexdump CH00000P.SCP | head -n 4
0000000 0040 ffff ffff ffff ffff ffff ffff ffff
0000010 ffff ffff ffff ffff ffff ffff ffff ffff
*
00000b0 0000 0001 ffff ffff ffff ffff ffff ffff&lt;/pre&gt;

&lt;p&gt;OK, let’s keep in mind that list from before. I would expect a number of frames to be near the start of a file if it was going to be declared because it’s easy to read immediately and determine how many frame blocks in this file may potentially follow. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x004&lt;/code&gt; is interesting immediately because it is 64 in decimal – remember “16384” from the height? Pick your favourite calculator – I use the Python IDLE / REPL and compute 16384/256 … which is 64, which would make sense. So, our first 8-bit block here is clearly the number of frames (note: there is no rigorous proof for this – it’s an assumption I’ve made given the information available to me. Disassembly would be the only way to know for sure.)&lt;/p&gt;

&lt;p&gt;We should record this information. If you’re trying to follow along, you might consider installing &lt;a href=&quot;http://kaitai.io/&quot;&gt;Kaitai Struct&lt;/a&gt; now as I will be using it to browse data. However, you can record your notes in whatever you want – including markdown. I use Kaitai Struct because the visualizer allows me to view my assumptions and visualize the hexdump in a DSL that makes it easy to browse and test definitions. Then, when it comes time to import them into a programming language to manipulate, the compiler can take the DSL and generate an object definition for most major programming languages I use on a daily-basis. This makes it easy to interact with my new model.&lt;/p&gt;

&lt;p&gt;You may also be interested in browsing the &lt;a href=&quot;https://github.com/kaitai-io/kaitai_struct/wiki&quot;&gt;wiki here&lt;/a&gt; to be briefly familiar, though this is not required as all definitions are provided.&lt;/p&gt;

&lt;p&gt;So, here’s what our notes will look like for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sprite.yml&lt;/code&gt; that we will create. This will be a definition file that is used by the Kaitai Struct Compiler and the Visualizer. By writing our notes and observations of the game data inside of Kaitai Struct, we gain the ability to visualize it quickly. For example, here is what we’re aiming to build here:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/re/trails_001/ksv.png&quot; alt=&quot;kaitai&quot; /&gt;
&lt;em&gt;Note: Yukino in the background is my terminal background – not part of KSV&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can navigate a tree of data in semantic blocks that make sense to us rather than some homogeneous data blob. Yes, some hex editors have this ability but none of them are human readable like this and capable of generating object definitions from their DSL.&lt;/p&gt;

&lt;p&gt;And you have to pay for a lot of them. So, what would a definition for this look like?&lt;/p&gt;

&lt;pre&gt;
meta:
  id: scp
  application: TiTS Engine - Sprite Format
  endian: le
seq:
  - id: header
    type: header
types:
  header:
    seq:
      - id: frame_count
        type: u1
      - id: magic_zero
        contents: [0]&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;How does this work? Meta is mostly describing ceremony. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application&lt;/code&gt; are user-defined fields and do not affect parsing.  Endianess is declared for how the bytes should be read. If you do not understand why we picked “le”, read the notes below and read up on Little Endian vs Big Endian.&lt;/p&gt;

&lt;p&gt;After this, we really get into the meat of the definition. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seq&lt;/code&gt; is declaring that are about to declare a bunch of sequential blocks from the current point in the file. Since this is the outter-most level of the YAML, it is the “root”. We declare something with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; of header, which is the name which will appear on object defintions and the visualizer, and the type. A type is analogous to a class or struct. It is a container and defintion for the block of data. In our case, we know for sure the file starts with some kind of header. It also probably contains some “frame data” as the screenshot before alluded to, so to make things easier to read we declare a type of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;types&lt;/code&gt; below. Then, we just declare the nested &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seq&lt;/code&gt; block and we’re good to go.&lt;/p&gt;

&lt;p&gt;With this, you would have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;header&lt;/code&gt; portion of the above screenshot if you ran the following command:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksv CH00000P.SCP sprite.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And you should see 64 listed  as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame_count&lt;/code&gt;. We could even compile with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksc&lt;/code&gt; now to get a working class but we don’t have anything worthwhile to compile just yet.&lt;/p&gt;

&lt;p&gt;A couple of notes of other notes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;We use Little-Endian here because this is an x86 processor game – which happen to use Little-Endian.&lt;/li&gt;
  &lt;li&gt;We declared the frame_count as 8-bits and then some “magic zero” afterwards which we state is always zero. This very well could be
some 16-bit number so that frame counts can exceed 2^8… but we’re not sure on that yet without looking at more files so we play this safe.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then, there’s the rest of these huge blocks of data. If we load this into a hex editor or just use  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hexdump&lt;/code&gt; we see a lot of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FF&lt;/code&gt; indicating empty space in the file. It would be unlikely for a header be padded with a huge amount of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FF&lt;/code&gt; so we can assume that perhaps the header is just 2 bytes long. Hm… looks like no frame height or width information? It seems unlikely that it’s encoded here.&lt;/p&gt;

&lt;p&gt;If we run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find . -name &quot;*.png*&quot; | xargs file {}&lt;/code&gt; we’ll notice a lot of 256 wide PNG files. Actually, all of them in this folder seem to be like this. Furthermore, if we run our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksv&lt;/code&gt; tool and markup against some of these &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SCP&lt;/code&gt; files all their frame counts seem to match the heights, for example a small output:&lt;/p&gt;

&lt;pre&gt;./CH01593.png: PNG image data, 256 x 2048, 8-bit/color RGBA, non-interlaced
./CH00435.png: PNG image data, 256 x 8192, 8-bit/color RGBA, non-interlaced
./CH01033.png: PNG image data, 256 x 2048, 8-bit/color RGBA, non-interlaced
./CH02280.png: PNG image data, 256 x 16384, 8-bit/color RGBA, non-interlaced
./CH02130.png: PNG image data, 256 x 16384, 8-bit/color RGBA, non-interlaced
./CH00128.png: PNG image data, 256 x 14848, 8-bit/color RGBA, non-interlaced
...&lt;/pre&gt;

&lt;p&gt;OK, probably safe to assume that this data is hard-coded into the game engine somewhere and not stored here. Or it’s stored somewhere else.&lt;/p&gt;

&lt;p&gt;That leaves us with a large file with some sparse data, though. When you see a lot of sparse data like this, you should think &lt;a href=&quot;http://www.cs.sfu.ca/CourseCentral/354/zaiane/material/notes/Chapter10/node15.html&quot;&gt;fixed length records&lt;/a&gt; … and I bet some frame data is encoded in these records. However, we should verify that this seems plausible and where it starts and ends.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stat&lt;/code&gt; the file to get a size and get started. i.e: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stat CH00000P.SCP&lt;/code&gt; to get a size of 32770, in bytes. Now, it’s time to think.. if there was a record for each frame, how big would each record have to be? (32770-2)/64 in this case (remember: we sliced off two bytes for the header) which is a nice, round, 512. Remember &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CH01593&lt;/code&gt; above? If we &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stat&lt;/code&gt; this file we get 4098… if we use the same logic then we get (4098-2)/8 = 512. It’s likely, but maybe not completely true, that we are looking at 512 byte records if we follow this train of thought. Let’s draft it out in Kaitai Struct and see what it would look like:&lt;/p&gt;

&lt;pre&gt;meta:
  id: scp
  application: TiTS Engine - Sprite Format
  endian: le
seq:
  - id: header
    type: header
  - id: frame_entries
    type: frame_entries
    repeat: eos

types:
  header:
    seq:
      - id: frame_count
        type: u1
      - id: magic_zero
        contents: [0]
  frame_entries:
    seq:
      - id: junk
        size: 174
      - id: data1
        type: u1
        repeat: expr
        repeat-expr: 4
      - id: junk2
        size: 334&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;A couple new syntax elements here. The most important in my opinion is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repeat: eos&lt;/code&gt; which is just saying create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frame_entries&lt;/code&gt; until the file ends. This makes sense since we asserted that after the header, it would be all frame data. I have filled in some &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;junk&lt;/code&gt; and  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; fields which might not make sense right now but they will once we load things up in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksv&lt;/code&gt;. I arrived at these offsets through dumping and examination but it will be more obvious where they come from once you load it up…&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksv CH00000P.SCP sprite.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/re/trails_001/ksv_expand.png&quot; alt=&quot;expand&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Huh. Do you notice incrementing sequence of numbers in each block that are the same “offsets” apart? There’s a bunch of increasing sequences in the data actually if you look at it through the visualizer like this. The visualizer is really handy in letting you scope your search to what you believe to be localized data. I wonder what those could be for… :) On first glance, it feels like they could frame numbers or some kind of counters. Considering they’re the only data in here, one would have to imagine that perhaps they layout the sequence of the frames when played back. There’s a lot of possibilities – to figure it out, we will need to do one of two things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Once again, consider the characteristics of this file and what we think it might contain&lt;/li&gt;
  &lt;li&gt;Disassemble the executable and read the resulting ASM code to how a loading routine for this file would marshal data around&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When reverse engineering, it is a good idea to examine other test subjects time to time as well to verify claims. In this case, if we run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ksv&lt;/code&gt; against &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CH01593P.SCP&lt;/code&gt; we’ll actually realize that “data1” is full of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FF&lt;/code&gt;. Doh! And there are sequential clusters as well again but they do not start from 0 like the other definition. To learn more, we should study the makeup of each spritesheet and image how it would need to jump from frame to frame to be able to visualize this properly.&lt;/p&gt;

&lt;p&gt;However, this post is getting pretty long as it stands, however, so we will wrap things up here. I wanted to provide a practical way of reverse-engineering data structures in Trails in the Sky using UNIX tools and Kaitai Struct and for that, I think I have succeeded. In the future, we may load these sheets up into an image editor to examine what is different and similar between them and their data files. (Hint: Things that move in all four directions like a PC Avatar are represented the same but different than say, a spell animation which flows in one linear sequence rather than jumping around in one of four directions like a PC Sprite.)&lt;/p&gt;

&lt;p&gt;For a follow-up, would you prefer to see us reason this out again with more UNIX tools or an attempt to attack this file with static analysis by disassembly? Let me know in the comments – or feel free to just leave feedback or questions.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Scraping the web with X-Ray utilizing Node.js - An example using Google</title>
   <link href="http://vaughanhilts.me/blog/2016/06/04/scraping-the-web-with-xray-under-nodejs-a-google-example.html"/>
   <updated>2016-06-04T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2016/06/04/scraping-the-web-with-xray-under-nodejs-a-google-example</id>
   <content type="html">&lt;p&gt;I recently was working on a project for a client that required going through some
data on the web and extracting some information, known in most circles as &lt;a href=&quot;https://en.wikipedia.org/wiki/Data_scraping&quot;&gt;data scraping&lt;/a&gt;.
Normally when I need to do something like this, I will use &lt;a href=&quot;https://github.com/cheeriojs/cheerio&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cheerio&lt;/code&gt;&lt;/a&gt; alongside something like &lt;a href=&quot;https://github.com/visionmedia/superagent&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Superagent&lt;/code&gt;&lt;/a&gt; or just &lt;a href=&quot;https://github.com/request/request&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;request&lt;/code&gt;&lt;/a&gt; to download pages and then extract information with a jQuery-like API. This is normally great for dealing with single pages or a list of similar pages that I want to get information from. For example, consider scraping some Wikipedia articles from a known list. Then, we can just run requests to grab the HTML contents and then use Cheerio to pick out what we want. However, I had some extra requirements on this project that made this approach not as straight-forward:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I needed to be able follow links on pages given some criteria and then easily
  extract information out from&lt;/li&gt;
  &lt;li&gt;I needed to be able to paginate these pages, that is follow a series of links
  until my results were exhausted&lt;/li&gt;
  &lt;li&gt;I needed it to do the heavy lifting for me (Cheerio is purely a DOM-API library) to
  save time and get the job done.&lt;/li&gt;
  &lt;li&gt;I needed rate-limited, which I have built before in the past, but it would be nice
  if something handled it for me.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s where &lt;a href=&quot;https://github.com/request/request&quot;&gt;X-Ray&lt;/a&gt; comes in – it so happens that
  it uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cheerio&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;request&lt;/code&gt; as dependencies, as well. It’s an abstraction against these
  two and makes scraping the web easy. Below, I’m going to illustrate how to scrape Google
  search results and follow their links for more information.
—&lt;/p&gt;

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

&lt;p&gt;Getting started is pretty easy, just download the package using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install x-ray@2.0.2 --save&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And then, inside of your Node.js file just do:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var Xray = require('x-ray')
var x = new Xray()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’re set!&lt;/p&gt;

&lt;h2 id=&quot;why-202&quot;&gt;Why 2.0.2?&lt;/h2&gt;

&lt;p&gt;At the time writing, there is an open issue for the newer versions (&lt;a href=&quot;https://github.com/lapwinglabs/x-ray/issues/65&quot;&gt;Issue #65&lt;/a&gt;) that prevents some of the things
we want to do. You should try the later versions if you are reading this in the future.&lt;/p&gt;

&lt;h1 id=&quot;querying-google&quot;&gt;Querying Google&lt;/h1&gt;

&lt;p&gt;You can read the syntax on the X-Ray page to get a better idea of what is going on but I will try to explain below, what is going on.  First, our goal:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/google_results.png&quot; alt=&quot;the goal&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We want to be able to programmatically run a Google Search and extract the URL of each of those links, and then in turn, we want to be able to visit each of them and extract:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt; of the page it links to, after viewing it&lt;/li&gt;
  &lt;li&gt;The very first link on each page, that is the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; tag and it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;href&lt;/code&gt; attribute&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Surprisingly, this is pretty easy to in X-Ray, we can do it like so:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;x(&quot;https://www.google.ca/search?site=&amp;amp;source=hp&amp;amp;q=spice+and+wolf&amp;amp;oq=spice+and+wolf&quot;, '.g', [{
   link: 'a@href',
 }]).paginate('#pnnext@href').limit(5)
 ((err, obj) =&amp;gt; {
   if(err) {
     callback(err);
   }
   else {
     obj.forEach((item) =&amp;gt; {
       var start = item.link.indexOf('q=')
       var end = item.link.indexOf('&amp;amp;sa')
       item.link = item.link.substring(start + 2, end)
     })
     callback(null, obj) // do something with the objects?
   }   
 })
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A couple interesting observations here:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;There is no explicit request code, no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;load&lt;/code&gt; or anything l ike that into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cheerio&lt;/code&gt; object.&lt;/li&gt;
  &lt;li&gt;There are no temporary variables or forming of an object manually, like we may do with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cheerio&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;All the error handling code for elements is missing. As it would turn out, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X-Ray&lt;/code&gt; handles this and forwards it to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;err&lt;/code&gt; parameter in the callbacks.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.paginate&lt;/code&gt; is present and so is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.limit&lt;/code&gt;. These are actually part of the fluent API that is provided to us – we can simply provide a selector to the “clickable next button” on the page and x-ray will internally paginate the results, iterating over the next 5 pages in this case, adding even more results to our internal array.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The 2nd parameter in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; function is just the scope in which selections should be done on. The 3rd is kind of strange – it’s an array of objects wrapped. By wrapping in square brackets, we are instructing X-Ray to iterate once for each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.g&lt;/code&gt;, without the brackets, it would execute once. So, the flow goes something like this.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  Download the page
  For each element in the set of .g ...
    Extract the first *a* element's href
  Return the result
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The only annoying portion is the link stripping and that is because of the way Google formatted the links at the time of writing. It’s actually kind of a hack but I am sure there is a better way to extract it out if you want to.&lt;/p&gt;

&lt;p&gt;Then, the only step left is to visit the links and process them. As it would turn out, you can compose in X-Ray to make this a snap as well. Consider the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;x(&quot;https://www.google.ca/search?site=&amp;amp;source=hp&amp;amp;q=spice+and+wolf&amp;amp;oq=spice+and+wolf&quot;, '.g', [{
   link: 'a@href',
   details: x('a@href', {
      title: 'title',
      link: 'a@href',
      linkText: 'a@text'
   })
 }]).paginate('#pnnext@href').limit(5)
 ((err, obj) =&amp;gt; {
   if(err) {
     callback(err);
   }
   else {
     callback(null, obj) // do something with the objects?
   }   
 })
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;details&lt;/code&gt; section? This will execute for each page and extract out:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;title&lt;/code&gt; tag&lt;/li&gt;
  &lt;li&gt;The first link location of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; tag&lt;/li&gt;
  &lt;li&gt;The first link &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; tag’s text&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We’d have to write a lot of boilerplate spaghetti to do this without our framework. So,
if we then go ahead and print out of some this using a basic loop, (printing title and link URLs for now), we get something like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Watch Spice and Wolf Anime Episodes Streaming on FUNimation :::: http://www.funimation.com/loadModal/index/forgot_password_modal
Spice &amp;amp; Wolf Wiki - Wikia :::: http://spiceandwolf.wikia.com/#WikiaArticle
http://www.google.com/ :::: https://www.youtube.com/watch%3Fv%3DI4Ztnt5ej20#
Ookami to Koushinryou (Spice and Wolf) - MyAnimeList.net :::: http://myanimelist.net/
Page not found :::: http://hachettebookgroup.com/
Spice and Wolf (TV) - Anime News Network :::: http://www.animenewsnetwork.com/
Ookami to Koushinryou - Anime - AniDB :::: https://anidb.net/animedb.pl?show=main
Ôkami to kôshinryô (TV Series 2008– ) - IMDb :::: http://pubads.g.doubleclick.net/gampad/...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cool! We could evidently extract more information from the pages if we needed to. Since we decided to maintain a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;link&lt;/code&gt; on the top-level of each object as well, we could run this through another X-ray parser to fetch site specific data depending on the URL, if we needed to. For example, if we detected a YouTube video / a video site, we might also be interested in, say it’s view count.&lt;/p&gt;

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

&lt;p&gt;So, if you have some requirements that I had – you should definitely check out X-Ray. Specifically, if you need pagination, easy robust requests, rate limiting and a nice execution flow you will get it here. If you want to see an example of this code and chaining requests, you can find it on my &lt;a href=&quot;https://github.com/hilts-vaughan/x-ray-google&quot;&gt;Github page&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Setting up zeroRPC on Windows with Node.js</title>
   <link href="http://vaughanhilts.me/blog/2016/05/30/setting-up-zero-rpc-on-windows.html"/>
   <updated>2016-05-30T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2016/05/30/setting-up-zero-rpc-on-windows</id>
   <content type="html">&lt;p&gt;zeroRPC is a really cool messaging system for distributed communication between server and client applications. In the past, I have used it to have my Node.js applications offload their workload
to other machines. You can already do this with &lt;a href=&quot;https://nodejs.org/api/cluster.html&quot;&gt;Cluster&lt;/a&gt; in Node.js land or something like &lt;a href=&quot;https://github.com/rvagg/node-worker-farm&quot;&gt;Node Workers&lt;/a&gt; – but the super cool part about RPC libraries such as zeroRPC is that it’s just a protocol in the end. One handy feature of this is that the client and servers not need be written in the same language – only speak the same protocol.&lt;/p&gt;

&lt;p&gt;You can read more about zeroRPC and why you might want to use it on their site &lt;a href=&quot;http://www.zerorpc.io/&quot;&gt;here&lt;/a&gt;. On this post, I am going to focus on a much more sinister issue I had to deal with when setting it up on Windows. I typically run a Linux workstation, but recently a few collaborators I was working with were on Windows machines. This machines I had to make the install and build process iron-clad with Windows machines, too. zeroRPC probably was one of the more tricky packages to install. Below is a small series of memo’s to myself and any future users who may need to get this working.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;setup-instructions&quot;&gt;Setup Instructions&lt;/h1&gt;

&lt;h2 id=&quot;install-zeromq&quot;&gt;Install zeroMQ&lt;/h2&gt;

&lt;p&gt;zeroMQ is a messaging library and zeroRPC is built on top of it. You’re going to need the latest windows installer and use that. You can grab the latest windows installer &lt;a href=&quot;http://zeromq.org/distro:microsoft-windows&quot;&gt;here&lt;/a&gt;. You will probably want “x64 build for Vista, 7, 8, Windows Server 2008 R2 and newer.”&lt;/p&gt;

&lt;h2 id=&quot;install-a-connector-of-your-choice&quot;&gt;Install a connector of your choice&lt;/h2&gt;

&lt;p&gt;On the &lt;a href=&quot;http://www.zerorpc.io/&quot;&gt;offical site&lt;/a&gt;, there is a couple options, mostly Python and Node.js. If you plan on using Node.js like I did, then just run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install zerorpc --save
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;installing-visual-studio-2015-for-messagepack&quot;&gt;Installing Visual Studio 2015 for MessagePack&lt;/h2&gt;

&lt;p&gt;zeroRPC uses MessagePack and this is not documented very well on the home-page (most NIX* systems would just pull this as a dependency). Windows users will need Visual Studio 2015 with C++ installed in order to be able to build it during the Node.js connector &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt; &lt;em&gt;Important&lt;/em&gt;: Visual Studio 2015 does not install C++ by default. You will need to select it manually during the install process.&lt;/p&gt;

&lt;h2 id=&quot;migrating-from-older-nodejs-versions&quot;&gt;Migrating from older Node.js versions&lt;/h2&gt;

&lt;p&gt;If you are using an older box like I was with some other installs and an older version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-gyp&lt;/code&gt;, it is likely you will need to reconfigure your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-gyp&lt;/code&gt; to point to compiling with the latest MSVS. Some native libraries will require you compile with a newer compiler to work. To do this, execute the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install -g --msvs_version=2015 node-gyp rebuild
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;python-bindings&quot;&gt;Python Bindings&lt;/h1&gt;

&lt;p&gt;zeroRPC is usually used to talk and communicate with other applications. If you plan on using the Python version and you are running Windows, you will likely find this link at Stackoverflow
a neccessity, as I did: http://stackoverflow.com/questions/13395458/how-to-install-zerorpc-python-on-windows/28386060#28386060&lt;/p&gt;

&lt;h1 id=&quot;and-that-should-be-it&quot;&gt;And that should be it…&lt;/h1&gt;

&lt;p&gt;That’s what it took for me. I hope this helps somebody out!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Unlinking MKVs on Windows, OSX, and Linux</title>
   <link href="http://vaughanhilts.me/blog/2015/04/30/unlinking-mkvs-on-windows-osx-linux.html"/>
   <updated>2015-04-30T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2015/04/30/unlinking-mkvs-on-windows-osx-linux</id>
   <content type="html">&lt;p&gt;For the longest time, the video format of choice was XVID or other types of encodings held in AVI containers. Howevever, more and more internet content is being distributed in Matroska (MKV) containers. While being more efficent and typically being used with some very good codecs like H264; there has been a price to pay for some slashing file sizes. A large trend of late has been to cut media files into several files and make use of the MKV linking feature to insert segments of video into mutliple files, while only storing it on the disk once. This sounds pretty great in theory but some of my media players of choice like &lt;a href=&quot;https://plex.tv/&quot;&gt;Plex&lt;/a&gt; do not support that part of the spec.&lt;/p&gt;

&lt;p&gt;So, I set out for a way to unlink and put these files back together. There’s a great project called &lt;a href=&quot;https://github.com/gnoling/UnlinkMKV&quot;&gt;UnlinkMKV&lt;/a&gt; written in Perl that did what I wanted to do. It does not run on Windows or OSX properly completely at time of writing, so I set out to port it and create a pull request. I didn’t want to settle for just some command line script port, though so I went overkill.&lt;/p&gt;

&lt;p&gt;I developed a full GUI interface overtop that can be used by anyone to solve this pesky linking problem. Details on how to use it below.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;using-unlinkmkv-gui&quot;&gt;Using UnlinkMKV-GUI&lt;/h1&gt;

&lt;p&gt;It’s a portable application running on the .NET Framework / Mono, you can grab the latest release &lt;a href=&quot;https://github.com/hilts-vaughan/UnlinkMKV-GUI/releases&quot;&gt;here&lt;/a&gt; and read the setup requirements &lt;a href=&quot;https://github.com/hilts-vaughan/UnlinkMKV-GUI/blob/master/README.md&quot;&gt;here&lt;/a&gt; for your operating system. Setup basically boils down to having Mono, a working Perl install, and MKVToolNix. If you know you have these already, you can move along. Otherwise, feel free to follow the guide for your operating system in the README.&lt;/p&gt;

&lt;p&gt;If you’re on OSX or Linux, after downloading the release you can just run it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mono UnlinkMKV-GUI.exe&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;using-the-application&quot;&gt;Using the application&lt;/h2&gt;

&lt;p&gt;If everything is good, you should see a screen like below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/unlinkmkv/start.png&quot; alt=&quot;interface&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Select the folder where your segments (linked video, along with the connecting segments) are for the “input folder” and then select “output folder” to be the folder where you want the merged files to be output. Then, just click &lt;strong&gt;“Unlink”&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;With any luck, just a bit of waiting will be all that is required to have your files waiting in output. If it has some problems, the following options below are available and described. If they still cannot fix your problem, cut me an issue on GitHub and I will try and get it fixed up.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Fix Audio/Fix Video: These will transcode the video into a new format. This isn’t really reccomended and only required in a few cases. The unlinking will take a long time and you will lose some quality.&lt;/li&gt;
  &lt;li&gt;Fix subtitles: If the subtitles don’t appear in the finished product, try ticking this.&lt;/li&gt;
  &lt;li&gt;Ignore default flag: Same as above, try ticking this.&lt;/li&gt;
  &lt;li&gt;Ignore missing segments: You can use this if you’re sure you want to skip missing segments&lt;/li&gt;
  &lt;li&gt;Verbose Output: You should use this mode when attaching a log for a bug report, will include important developer information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to Garret Gnoling for the original release. Pending pull request approval, the original script should be updated for cross platform, too.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Installing Jekyll on Windows with Ruby 2.2.2</title>
   <link href="http://vaughanhilts.me/blog/2015/04/15/installing-jekyll-on-windows-with-ruby-2-2.html"/>
   <updated>2015-04-15T00:00:00+00:00</updated>
   <id>http://vaughanhilts.me/blog/2015/04/15/installing-jekyll-on-windows-with-ruby-2-2</id>
   <content type="html">&lt;p&gt;Before migrating my blog over to Jekyll, I did some research and found Jekyll was probably a fairly matured static
generator that had a fair degree of running on Windows with no issues. Actually, it was &lt;a href=&quot;http://jekyll-windows.juthilo.com/1-ruby-and-devkit/&quot;&gt;this guide in particular&lt;/a&gt; that
I followed mostly. Though, if you have as much bad luck as me sometimes, well you’ll probably run into a snag using the latest version of Ruby; for me that’s the 2.2.x revisions.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;issues-with-hitimers&quot;&gt;Issues with Hitimers&lt;/h1&gt;

&lt;h2 id=&quot;the-issue&quot;&gt;The issue&lt;/h2&gt;

&lt;p&gt;If you receive the following error when trying to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll serve&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:/Ruby22/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in 'require': cannot load such file -- hitimes/hitimes (
LoadError)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, chances are you just need to run the following commands in your command prompt:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem uni hitimes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem ins hitimes -v 1.2.1 --platform ruby&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;explanation&quot;&gt;Explanation&lt;/h2&gt;

&lt;p&gt;It would turn out that typically, there is a fat binary that is rolled into the gem installation of hitimes. However, hitimes has only been around since January and
the &lt;a href=&quot;https://github.com/copiousfreetime/hitimes/issues/40&quot;&gt;authour hasn’t yet released&lt;/a&gt; a &lt;a href=&quot;http://en.wikipedia.org/wiki/Fat_binary&quot;&gt;fat binary&lt;/a&gt; for it yet. Basically, there is no Windows support.
Running the above code, we’ll get around the issue until hitimers has an update.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/28985481/hitimes-require-error-when-running-jekyll-serve-on-windows-8-1&quot;&gt;(Credit to this Stackoverflow answer for the solution.&lt;/a&gt;)&lt;/p&gt;
</content>
 </entry>
 
 
</feed>
