<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Andy Roche</title>
    <description></description>
    <link>https://roche.io/</link>
    <atom:link href="https://roche.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 25 Mar 2023 18:21:56 -0400</pubDate>
    <lastBuildDate>Sat, 25 Mar 2023 18:21:56 -0400</lastBuildDate>
    <generator>Jekyll v4.2.1</generator>
    
      <item>
        <title>ASCII Tabs Release</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://asciitabs.com/&quot;&gt;ASCII Tabs&lt;/a&gt; is a website to learn guitar and basic music theory; enough to jam with anyway. Today it is considered fully released, and should have no bugs. 🤞&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/2018/06/asciitabs-mobile.png&quot; alt=&quot;ASCII Tabs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Features added since the beta release:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Polished mobile device interface&lt;/li&gt;
  &lt;li&gt;HTTPS / SSL support&lt;/li&gt;
  &lt;li&gt;Allow for random tabs that only use single notes&lt;/li&gt;
  &lt;li&gt;Allow for open notes in random tabs with fret limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unless better ideas are surfaced through feedback, the next feature I plan to add is optional highlighting of roots / thirds / fifths.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
        <pubDate>Wed, 13 Jun 2018 00:00:00 -0400</pubDate>
        <link>https://roche.io/2018/06/asciitabs-release</link>
        <guid isPermaLink="true">https://roche.io/2018/06/asciitabs-release</guid>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Quake Timer</title>
        <description>&lt;h3 id=&quot;download-on-github&quot;&gt;&lt;a href=&quot;https://github.com/rocheio/quake-timer&quot;&gt;&lt;strong&gt;Download on Github&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;In the game &lt;a href=&quot;https://en.wikipedia.org/wiki/Quake_Champions&quot;&gt;Quake Champions&lt;/a&gt;, powerful items spawn around the map at fixed intervals. Collecting these items is the key to victory in higher-level games.&lt;/p&gt;

&lt;p&gt;Unfortunately, the game only provides a thirty-second callout for the most powerful items (Quad Damage and its inverse – Protection), and does not provide any callout for the lesser items (Mega Health and Heavy Armor).&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/rocheio/quake-timer&quot;&gt;Quake Timer App&lt;/a&gt; allows players to set their own timers to work around this. While playing, you can hit a key combination like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ALT + 1&lt;/code&gt; whenever a valuable item is picked up. The timer will then provide voiced callouts (e.g. “Mega Health in ten seconds”) before the items respawn.&lt;/p&gt;
</description>
        <pubDate>Mon, 11 Jun 2018 00:00:00 -0400</pubDate>
        <link>https://roche.io/2018/06/quake-timer</link>
        <guid isPermaLink="true">https://roche.io/2018/06/quake-timer</guid>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Asciitabs Alpha</title>
        <description>&lt;p&gt;A month ago I released the alpha version of &lt;a href=&quot;http://www.asciitabs.com&quot;&gt;asciitabs.com&lt;/a&gt;.
This post covers how the site started, how it was launched, what I learned from that launch, and where it will go from here.&lt;/p&gt;

&lt;p&gt;I don’t really consider the launch to be successful, but it was a good learning experience. I believe with a few more features and market research it has potential to be a useful website.&lt;/p&gt;

&lt;h2 id=&quot;how-asciitabs-started&quot;&gt;How Asciitabs started&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/media/2018/05/asciitab-cli.png&quot; alt=&quot;Asciitabs CLI prototype&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I have always found tablature to be the most approachable way to learn guitar and share amateur compositions online. There is a lot lost in translation between tabs and standard notation, but it seems like the difference between Markdown and LaTeX: both have a place and purpose.&lt;/p&gt;

&lt;p&gt;I wanted to practice my basic music theory, and my Go programming, so I created &lt;a href=&quot;https://github.com/rocheio/asciitab&quot;&gt;a command-line tool&lt;/a&gt; to generate random tabs given a key and a scale. I got this to a point where it could make random tabs and basic ascending scales before deciding to see if I could turn it into a more accessible website.&lt;/p&gt;

&lt;h2 id=&quot;creating-the-website&quot;&gt;Creating the website&lt;/h2&gt;

&lt;p&gt;I marked my prototype as complete and left it up &lt;a href=&quot;https://github.com/rocheio/asciitab&quot;&gt;on Github&lt;/a&gt; for the curious. The repo was copied to a private Bitbucket repo for future work, which I hope maintains some semblance of a competitive advantage if the website ever gains traction. I hope to open source the core music-definition and tab-generation libraries once they have matured.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/2018/05/asciitab-alpha-home.png&quot; alt=&quot;Asciitabs Alpha Home Page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I built out a very basic web interface using the Go &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;html/template&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net/http&lt;/code&gt; standard libraries. The website is hosted on a single EC2 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t2.micro&lt;/code&gt; instance and is deployed using Docker and ECR. I managed to get 50% test coverage on the core tab-generation library but had no testing on the CLI or website code at this point.&lt;/p&gt;

&lt;p&gt;I released a pre-alpha to some of my friends and got an initial round of feedback, bug reports, and feature requests. By the end of that round, the website was in a minimally styled but fairly robust state, supporting: random tabs, scales, flats / sharps, majors / minors, guitar, and ukulele.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/2018/05/asciitab-alpha-random.png&quot; alt=&quot;Asciitabs Alpha Random Tab Page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There were dozens of tweaks and features that I still wanted to add, but I decided to test the waters as early as possible, hoping that would help me decide what to focus on next.&lt;/p&gt;

&lt;h2 id=&quot;alpha-launch-and-early-feedback&quot;&gt;Alpha launch and early feedback&lt;/h2&gt;

&lt;p&gt;I put the finishing touches on the site, made sure people knew how to contact me for feedback / bug reports, and posted it &lt;a href=&quot;https://news.ycombinator.com/item?id=16788557&quot;&gt;to Hacker News&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The early feedback was minimal, but was thankfully helpful, positive, and diverse. I got website feedback of the following nature:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Mobile support was broken (easy fix - remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;viewport&lt;/code&gt; settings)&lt;/li&gt;
  &lt;li&gt;Request for plectrum / pick-centric tabs (easy feature)&lt;/li&gt;
  &lt;li&gt;Request for in-browser audio output of the generated tabs (medium-hard feature)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My favorite comment was one not about my website, but about my future progression as a musician. The user recommended that I learn standard notation and not rely so much on tablature because of how limiting it is. I took this to heart in my practicing by trying to play songs from standard notation that I have already mostly memorized. It’s slow going, but sure to pay off in the long run.&lt;/p&gt;

&lt;p&gt;The next day, I also submitted the site to Reddit at &lt;a href=&quot;https://www.reddit.com/r/UsefulWebsites/comments/8b2f8r/asciitabs_a_random_tablature_generator_for_guitar/&quot;&gt;/r/UsefulWebsites&lt;/a&gt;. This got some more visitors and analytics data, but sadly no more direct user feedback.&lt;/p&gt;

&lt;h3 id=&quot;analytics-data-from-launch&quot;&gt;Analytics data from launch&lt;/h3&gt;

&lt;p&gt;I wish I had more time to figure out a locally-hosted or privacy-centric analytics tool, but Google Analytics is just so good and free and easy. I’m sorry everyone. I assume most people that are offended by tracking have blocked those requests anyway, which also means that the data below is not 100% complete and accurate. Take this section as you will.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/2018/05/asciitabs-analytics-users.png&quot; alt=&quot;Asciitabs Alpha User Rates&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I got just under 1,000 visitors in 3 days, and have only seen at most 5 a day since then. I have not done any continued marketing since the two initial posts, and was curious to see if there was any latent virality in this idea. The answer was clear. I need to make the site more useful and catchy, and probably also need to consider some direct marketing if I ever monetize the site.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/2018/05/asciitabs-analytics-channels.png&quot; alt=&quot;Asciitabs Alpha User Rates&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The source metrics show that most of my traffic came from the Hacker News post, but most of those users just toyed with a couple pages then left. The Reddit group stayed around a bit longer and seemed to show more interest in it, but there were a lot fewer of them.&lt;/p&gt;

&lt;p&gt;All in all, not much useful data here other than that I clearly need to do more work if I want the website to be found by and useful to a wider audience.&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;The site needs more features
    &lt;ul&gt;
      &lt;li&gt;More tab customization options&lt;/li&gt;
      &lt;li&gt;Rhythm in tabs (spacing of chords)&lt;/li&gt;
      &lt;li&gt;Custom instruments&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;The site needs a way for people to share tabs easily&lt;/li&gt;
  &lt;li&gt;The site needs monetization and direct marketing
    &lt;ul&gt;
      &lt;li&gt;Only after further validation of base idea&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;The site needs a better landing page
    &lt;ul&gt;
      &lt;li&gt;Way to experience the app for non-musicians&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;updates-since-launch&quot;&gt;Updates since launch&lt;/h2&gt;

&lt;p&gt;Since the original launch, I have begun to make progress on the lessons learned from above.&lt;/p&gt;

&lt;h4 id=&quot;index-page&quot;&gt;Index Page&lt;/h4&gt;

&lt;p&gt;The &lt;a href=&quot;http://www.asciitabs.com&quot;&gt;index page&lt;/a&gt; still retains above-the-fold simplicity and big call-to-action buttons, but also has a small description and GIF of the major “Random” and “Scale” features.&lt;/p&gt;

&lt;h4 id=&quot;sharing-modal&quot;&gt;Sharing Modal&lt;/h4&gt;

&lt;p&gt;I added a sharing modal on the tab page that includes a link to the exact tab the user is viewing.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/2018/05/asciitabs-share-modal.png&quot; alt=&quot;Asciitabs Share Modal&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This was pretty easy to implement in Go by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rand.Seed&lt;/code&gt; for each tab generated, and passing that seed through to the page in case the user wants to share it. The final URL looks 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;http://www.asciitabs.com/random?instrument=guitar&amp;amp;key=Bb&amp;amp;measures=8&amp;amp;scale=minor&amp;amp;seed=53gw5f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I might make a small internal shortening service for that if it becomes too unwieldy.&lt;/p&gt;

&lt;h4 id=&quot;more-options&quot;&gt;More Options&lt;/h4&gt;

&lt;p&gt;I split the tab button bar from the options box, and now have a lot of room to grow out the options section without overwhelming a first-time user.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/2018/05/asciitabs-option-box.png&quot; alt=&quot;Asciitabs Option Box&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I knocked out a new feature here too for supplying a minimum and maximum fret for tabs - previously it would always just use frets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4&lt;/code&gt; for random tabs and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root + 4&lt;/code&gt; for scales.&lt;/p&gt;

&lt;h4 id=&quot;programming-stuff&quot;&gt;Programming Stuff&lt;/h4&gt;

&lt;p&gt;I added an official &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CHANGELOG&lt;/code&gt; and started doing git tags on releases. I also started unit testing my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cli&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;web&lt;/code&gt; libraries and raised overall coverage to 60%. It’s not much, but sometimes it’s the little things that help you sleep at night.&lt;/p&gt;

&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h2&gt;

&lt;p&gt;The alpha launch of Asciitabs didn’t have the virality or continued usage that I was hoping for, but it has been one of my most successful sites so far. I’m going to keep building features and fixing bugs as I have time, but my mind is starting to wander off to other, possibly better, ideas.&lt;/p&gt;

&lt;p&gt;Check out the site at &lt;a href=&quot;http://www.asciitabs.com&quot;&gt;asciitabs.com&lt;/a&gt;. If you have any feedback, feature requests, or bug reports, please send me an email at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;andy@asciitabs.com&lt;/code&gt;.&lt;/p&gt;

</description>
        <pubDate>Sun, 06 May 2018 00:00:00 -0400</pubDate>
        <link>https://roche.io/2018/05/asciitabs-alpha</link>
        <guid isPermaLink="true">https://roche.io/2018/05/asciitabs-alpha</guid>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Haiku News Bot</title>
        <description>&lt;p&gt;This week I released my first bot on Twitter – &lt;a href=&quot;https://twitter.com/HaikuNewsBot&quot;&gt;HaikuNewsBot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s built in Python, and gets news from over 50 English sources using the free &lt;a href=&quot;https://newsapi.org/&quot;&gt;News API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/HaikuNewsBot&quot;&gt;&lt;img src=&quot;/media/2017/07/haikunewsbot-post.png&quot; alt=&quot;HaikuNewsBot tweet&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s not 100% accurate or super useful but it’s a cute proof of concept for future bots and parsing programs. I’ll add small updates over time as I receive feedback and notice bugs.&lt;/p&gt;

&lt;h2 id=&quot;parsing-a-haiku&quot;&gt;Parsing a Haiku&lt;/h2&gt;

&lt;p&gt;I settled on making this an English-only news bot, so I could use consistent (and familiar) language parsing techniques for every article title.&lt;/p&gt;

&lt;p&gt;Most of the syllable counting logic is a combination of the &lt;a href=&quot;http://www.speech.cs.cmu.edu/cgi-bin/cmudict&quot;&gt;CMU Pronouncing Dictionary&lt;/a&gt; from the &lt;a href=&quot;http://www.nltk.org/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nltk&lt;/code&gt;&lt;/a&gt; package, and the &lt;a href=&quot;https://pypi.python.org/pypi/textstat&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;textstat&lt;/code&gt;&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;I wrote a custom syllable parser for numbers, so that ‘16,000’ is properly counted as four syllables (six-teen-thous-and). I also wrote a parser for acronyms, discovering that the translation of letters to syllables is wonderfully simple: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3 if letter == &apos;w&apos; else 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I’ll wait while you go through the alphabet in your head now.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before running words through the parsers, I &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.split()&lt;/code&gt; the headline on all whitespace, stripped it of non-alphanumeric characters, and analyzed each text element by itself.&lt;/p&gt;

&lt;p&gt;If an element was 3 characters or less and uppercase (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FBI&lt;/code&gt;), then assume its an acronym, and use the character parsing logic above.&lt;/p&gt;

&lt;p&gt;If an element is composed of letters and numbers (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;G20&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;patio11&lt;/code&gt;), then split the alpha part(s) from the numeric part(s), and parse each of those elements separately.&lt;/p&gt;

&lt;h2 id=&quot;collecting-and-posting-tweets&quot;&gt;Collecting and Posting Tweets&lt;/h2&gt;

&lt;p&gt;Each time the bot runs, it gets about 15 new haikus from the API. It stores these in a local SQLite database, ranking them by haiku likelihood (it has about a 70% accuracy rate).&lt;/p&gt;

&lt;p&gt;Whenever the bot is told to post a haiku, it chooses the highest-rated one from within the last day from the database. It tries to post it to Twitter, and does nothing if it fails (at the moment). Eventually I’d like to set it to email me if it fails with the error message.&lt;/p&gt;

&lt;h2 id=&quot;hosting-the-service&quot;&gt;Hosting the Service&lt;/h2&gt;

&lt;p&gt;The bot is hosted on a $5 Linode VPS with some other toy programs, and runs once an hour as a cron job (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0 * * * *&lt;/code&gt;).&lt;/p&gt;
</description>
        <pubDate>Wed, 12 Jul 2017 00:00:00 -0400</pubDate>
        <link>https://roche.io/2017/07/haikunewsbot</link>
        <guid isPermaLink="true">https://roche.io/2017/07/haikunewsbot</guid>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Where to Store API Keys</title>
        <description>&lt;p&gt;A common security issue that comes up when developing networked applications is where to store security credentials like API keys.&lt;/p&gt;

&lt;h2 id=&quot;basics&quot;&gt;Basics&lt;/h2&gt;

&lt;p&gt;One of the first steps to securing API keys is to remember to &lt;strong&gt;never check them into source code repositories&lt;/strong&gt;. If you ever commit and push code that includes a hard-coded API key, it is compromised, and you’ll need to revoke it and create a new one.&lt;/p&gt;

&lt;p&gt;One option to store these keys is to read them from files not synced to the source code repo. The problem with this is when changing machines or working with multiple developers - its hard to pin down a consistent location to store these keys.&lt;/p&gt;

&lt;p&gt;The next logical step is to store them in Environment Variables, which can be used consistently on any machine / operating system (e.g. using Python’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os.environ&lt;/code&gt;). This is what I’ve been doing until now, generally storing the keys themselves in Keepass and typing them into the shell manually using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;using-a-env-file&quot;&gt;Using a .env File&lt;/h2&gt;

&lt;p&gt;Instead of manually typing these keys each time, I found &lt;a href=&quot;https://www.learnhowtoprogram.com/javascript/ember-extended/api-keys-as-environment-variables&quot;&gt;a good convention from Epicodus&lt;/a&gt; that I’m going to start using.&lt;/p&gt;

&lt;p&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file in the Git repo of you application, and be sure to include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt; file. On each line of this file, include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export KEY=&amp;lt;VALUE&amp;gt;&lt;/code&gt; line to declare all needed environment variables.&lt;/p&gt;

&lt;p&gt;Now, at the beginning of each development session, instead of manually typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export&lt;/code&gt; for each specific key, just use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;source .env&lt;/code&gt; to load all your API keys.&lt;/p&gt;

&lt;h2 id=&quot;considerations&quot;&gt;Considerations&lt;/h2&gt;

&lt;p&gt;Please note that this method only secures against accidental key exposure in source code and version control, it &lt;a href=&quot;https://security.stackexchange.com/a/49739&quot;&gt;&lt;strong&gt;will not protect&lt;/strong&gt;&lt;/a&gt; against someone with root control to your box.&lt;/p&gt;
</description>
        <pubDate>Sun, 09 Jul 2017 00:00:00 -0400</pubDate>
        <link>https://roche.io/2017/07/where-to-store-api-keys</link>
        <guid isPermaLink="true">https://roche.io/2017/07/where-to-store-api-keys</guid>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Using a Router as a Wireless Access Point</title>
        <description>&lt;p&gt;The wireless signal in parts of my house was weak, and I wanted to improve it. I already had an &lt;a href=&quot;http://amzn.to/2uzjeRF&quot;&gt;existing router&lt;/a&gt; and modem, and figured I could improve the signal by adding &lt;a href=&quot;http://amzn.to/2sPnr6A&quot;&gt;one more router&lt;/a&gt; to the current setup.&lt;/p&gt;

&lt;p&gt;It took a few hours to research everything and get it set up properly, so I’ll document the key steps here for when I need to set it up again.&lt;/p&gt;

&lt;h2 id=&quot;research-your-network&quot;&gt;Research your network&lt;/h2&gt;

&lt;p&gt;Before touching the new router, learn about your current network setup. Navigate to your current router’s admin page (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.1&lt;/code&gt;) and log in with your username and password.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you don’t remember your username / password, try the defaults located on a sticker on the bottom of the router. If those don’t work, factory reset the router by holding a paper clip on the reset button for 10 seconds.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Advanced Settings &amp;gt; LAN &amp;gt; DHCP Server&lt;/code&gt;, and see what the ‘Starting Address’ and ‘Ending Address’ values are for the router’s IP pool (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.2&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.254&lt;/code&gt;). This is the range of IP addresses on the subnet (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.*&lt;/code&gt;) that your router can use for clients.&lt;/p&gt;

&lt;p&gt;Make sure there is room on the subnet for your new router. If you want the new router to have address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.2&lt;/code&gt;, then make sure to set the ‘Starting Address’ of the original router’s DHCP IP pool to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.3&lt;/code&gt; or higher.&lt;/p&gt;

&lt;p&gt;Restart the original router if you made any changes.&lt;/p&gt;

&lt;h2 id=&quot;set-up-the-new-router&quot;&gt;Set up the new router&lt;/h2&gt;

&lt;p&gt;Unpack the new router, and cover the single WAN port with tape. Routers configured as access points do all input and output through the 4 LAN ports instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DO NOT plug the new router into the original router until the end&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Plug the new router into a power outlet. Plug an ethernet cable into any of the 4 LAN ports of the router, and plug the other end of the cable into your computer.&lt;/p&gt;

&lt;h2 id=&quot;configure-new-router-as-an-access-point&quot;&gt;Configure new router as an access point&lt;/h2&gt;

&lt;p&gt;Look on the bottom of the new router for the default IP address, username, and password. Navigate to that address (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.0.1&lt;/code&gt;) and log in.&lt;/p&gt;

&lt;p&gt;On the admin page, navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Advanced &amp;gt; Network &amp;gt; LAN&lt;/code&gt;, and change the IP address to an open address in your original router’s subnet (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.2&lt;/code&gt;). Save this change, and restart the router.&lt;/p&gt;

&lt;p&gt;Wait a couple of minutes, then reconnect to the admin page using the new IP address.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Advanced &amp;gt; Network &amp;gt; DHCP Server&lt;/code&gt;, and disable it entirely by unchecking ‘Enable DHCP Server’. Ignore all the other settings, because its disabled.&lt;/p&gt;

&lt;h2 id=&quot;configure-wireless-network-names&quot;&gt;Configure wireless network names&lt;/h2&gt;

&lt;p&gt;Most modern devices, when presented with multiple networks using the same name and password, will juggle between those connections seamlessly based on which signal is strongest at the time.&lt;/p&gt;

&lt;p&gt;Unless you have a device that can’t handle this, keep it simple and use a single network identity for all signals.&lt;/p&gt;

&lt;p&gt;On both the old and new router, navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Basic &amp;gt; Wireless&lt;/code&gt;, and set the network name / password for both the 2.4GHz and 5GHz networks to the same values.&lt;/p&gt;

&lt;h2 id=&quot;test-and-celebrate&quot;&gt;Test and celebrate&lt;/h2&gt;

&lt;p&gt;You should now have 4 signals, broadcasting from 2 devices, that appear to most computers as 1 wireless connection. Use something like &lt;a href=&quot;http://www.speedtest.net/&quot;&gt;Speedtest.net&lt;/a&gt; to measure you connection speed and confirm it has improved.&lt;/p&gt;

&lt;p&gt;Assuming everything works, clean up your mess and organize your cables, then don’t think about your wireless network again until you move.&lt;/p&gt;
</description>
        <pubDate>Fri, 07 Jul 2017 00:00:00 -0400</pubDate>
        <link>https://roche.io/2017/07/router-access-point</link>
        <guid isPermaLink="true">https://roche.io/2017/07/router-access-point</guid>
        
        
        <category>networking</category>
        
      </item>
    
      <item>
        <title>Ubuntu 17.04 on ZenBook Pro</title>
        <description>&lt;p&gt;After a little headache and some arcane magic, I managed to get an encrypted version of &lt;a href=&quot;http://releases.ubuntu.com/17.04/&quot;&gt;Ubuntu 17.04&lt;/a&gt; installed on my laptop. The laptop is an &lt;a href=&quot;https://www.asus.com/us/Notebooks/ASUS-ZenBook-Pro-UX501VW/&quot;&gt;ASUS ZenBook Pro UX501VW&lt;/a&gt;, which is like a 15” Macbook Pro, but half the price and without some crazy touch bar.&lt;/p&gt;

&lt;p&gt;Most of my success is thanks to Peter van der Zee (qFox), who logged &lt;a href=&quot;https://qfox.nl/weblog/381&quot;&gt;his battle to install Ubuntu 16.04&lt;/a&gt; on the same laptop in 2016.&lt;/p&gt;

&lt;p&gt;Since he did most of the work already, this post is mostly a collection of links with some minor addenda in case I need to do this again.&lt;/p&gt;

&lt;h2 id=&quot;set-up-the-flash-drive&quot;&gt;Set up the flash drive&lt;/h2&gt;

&lt;p&gt;First problem I had was that the flash drive I wanted to use to install the ISO wasn’t properly formatted when I started this process. I ended up using the &lt;a href=&quot;http://gparted.org/&quot;&gt;GParted utility&lt;/a&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt install gparted&lt;/code&gt;) to reformat it completely. Other, &lt;a href=&quot;https://askubuntu.com/questions/758219/how-can-i-delete-all-partion-of-my-pen-drive-and-create-a-single-volume/758223#758223&quot;&gt;more direct&lt;/a&gt;, commands did nothing but cause more headache.&lt;/p&gt;

&lt;p&gt;Once the flash drive is ready, download the &lt;a href=&quot;http://cdimage.ubuntu.com/ubuntu-gnome/releases/17.04/release/&quot;&gt;Ubuntu 64-bit ISO&lt;/a&gt;, and install it using the &lt;a href=&quot;https://apps.ubuntu.com/cat/applications/precise/usb-creator-gtk/&quot;&gt;Startup Disk Creator&lt;/a&gt; utility.&lt;/p&gt;

&lt;h2 id=&quot;installing&quot;&gt;Installing&lt;/h2&gt;

&lt;p&gt;Basically, I just followed &lt;a href=&quot;https://qfox.nl/weblog/381&quot;&gt;qFox’s 16.04 guide&lt;/a&gt;, but used the Ubuntu Gnome 17.04 image. Unlike previous versions of Ubuntu, I was able to encrypt the installation without hassle just by following the wizard (previous versions were unable to locate the partition after installing).&lt;/p&gt;

&lt;p&gt;Every time you reboot to do some part of this process, you’ll need to hit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;esc&lt;/code&gt; to get to the boot select menu, then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; to set grub parameters. Change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;quiet splash&lt;/code&gt; on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt; line to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i951.preliminary_hw_support=1 nogpumanager&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the installer still hangs after changing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;quiet splash&lt;/code&gt; in the grub parameters, drop into the root shell, and download the &lt;a href=&quot;http://ubuntuhandbook.org/index.php/2017/02/how-to-install-nvidia-375-39-378-13-via-ppa-in-ubuntu/&quot;&gt;proprietary Nvidia drivers&lt;/a&gt; before installing. Use whichever ones are the newest if the above are outdated.&lt;/p&gt;

&lt;p&gt;After fiddling with grub parameters and getting to the installation wizard, the process should be relatively easy. Install, encrypt, and update as normal.&lt;/p&gt;

&lt;p&gt;Once you’re happy with your installation, update grub permanently using qFox’s settings:&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/default/grub
// replace the &quot;quiet splash&quot; line with
// GRUB_CMDLINE_LINUX_DEFAULT=&quot;i951.preliminary_hw_support=1 acpi_osi= acpi_backlight=native&quot;
sudo update-grub
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;High DPI (4k) resolution should work out of the box after a full update and reboot. You can fiddle with the scaling settings in Gnome to get it working better with certain apps (e.g. Keepass, Skype).&lt;/p&gt;

&lt;p&gt;I’ll update this post in the future when I go through the process again with future releases.&lt;/p&gt;

</description>
        <pubDate>Sat, 29 Apr 2017 00:00:00 -0400</pubDate>
        <link>https://roche.io/2017/04/ubuntu-1704-zenbook-pro</link>
        <guid isPermaLink="true">https://roche.io/2017/04/ubuntu-1704-zenbook-pro</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Making a Huge Google Map</title>
        <description>&lt;p&gt;I recently made a 25000 x 25000 pixel &lt;a href=&quot;https://www.google.com/maps&quot;&gt;Google Map&lt;/a&gt; to hang on my wall
and track all the places I’ve explored in the city.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/2017/03/google-map-on-wall.jpg&quot; alt=&quot;Final map hanging on wall&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The final product took 30 minutes for my laptop to generate,
45 minutes to print, and cost about $50 in materials.&lt;/p&gt;

&lt;p&gt;All of the code I used is available &lt;a href=&quot;https://github.com/rocheio/huge-gmaps&quot;&gt;on GitHub&lt;/a&gt;.
I cleaned up the script a bit from the original, but don’t expect it to
work on your computer without slight modifications.&lt;/p&gt;

&lt;h2 id=&quot;creating-the-image&quot;&gt;Creating the Image&lt;/h2&gt;

&lt;p&gt;The program currently requires Python 3.5+ because I love type hints.
It uses the &lt;a href=&quot;http://selenium-python.readthedocs.io/&quot;&gt;Selenium&lt;/a&gt; library for browser automation,
and the &lt;a href=&quot;https://python-pillow.org/&quot;&gt;Pillow&lt;/a&gt; library for image manipulation.&lt;/p&gt;

&lt;p&gt;Before running, the program needs a few things from the user:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Figure out what percent to crop from each side of a screenshot to hide all
unwanted, non-map elements (taskbars, extra displays, GUI elements)&lt;/li&gt;
  &lt;li&gt;Figure out a good starting point (top-left coordinate) for the map,
and how many rows / columns should be used to capture the desired area&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once provided with that information, the program does the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Figure out how much to adjust the latitude and longitude each screenshot
so that the final grid of images will line up perfectly&lt;/li&gt;
  &lt;li&gt;Visit &lt;a href=&quot;https://www.google.com/maps&quot;&gt;Google Maps&lt;/a&gt;, wait for it to load, and take each screenshot&lt;/li&gt;
  &lt;li&gt;Loop through the grid of saved images and combine them into one huge image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rocheio/huge-gmaps/blob/master/hugegmaps.py&quot;&gt;The main script&lt;/a&gt; is only 132 lines long,
40 of which are comments, if you want to check it out for yourself.&lt;/p&gt;

&lt;h1 id=&quot;printing-and-building&quot;&gt;Printing and building&lt;/h1&gt;

&lt;p&gt;The build was fairly straightforward, and was supposed to be a trial run.
However, the results came out so well that I decided to just keep this version.&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;4 square feet of white vinyl = $8&lt;/li&gt;
  &lt;li&gt;4 square feet of ink = $20&lt;/li&gt;
  &lt;li&gt;3.5’ x 4.5’ sheet of foam board = $12&lt;/li&gt;
  &lt;li&gt;500 assorted map tacks = $7&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;img src=&quot;/media/2017/03/google-map-plotter.jpg&quot; alt=&quot;Map printing in plotter&quot; /&gt;
&lt;img src=&quot;/media/2017/03/google-map-drafting-table.jpg&quot; alt=&quot;Map on drafting table&quot; /&gt;
&lt;img src=&quot;/media/2017/03/google-map-printed-resolution.jpg&quot; alt=&quot;Map at super close 1-inch block&quot; /&gt;
&lt;img src=&quot;/media/2017/03/google-map-measuring-tape.jpg&quot; alt=&quot;Map with dog&quot; /&gt;
&lt;img src=&quot;/media/2017/03/google-map-assembly-duct-tape.jpg&quot; alt=&quot;Duct taping card stock together&quot; /&gt;
&lt;img src=&quot;/media/2017/03/google-map-on-wall.jpg&quot; alt=&quot;Hanging on the wall&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;future-considerations&quot;&gt;Future considerations&lt;/h1&gt;

&lt;p&gt;If I continue using this program for more than a one-off project,
I need to consider the following changes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Instead of using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rows&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;columns&lt;/code&gt; to determine the size of the map,
pass a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;latitude_end&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;longitude_end&lt;/code&gt; and have the program figure
out the rows and columns.&lt;/li&gt;
  &lt;li&gt;Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyscreenshot.grab&lt;/code&gt; with a hand-rolled image cropping function,
since Selenium already provides basic screenshot functionality.&lt;/li&gt;
  &lt;li&gt;Allow for adjustable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zoom&lt;/code&gt; levels, instead of hard-coding it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;18z&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Allow for Google Earth images in addition to Google Maps.&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Thu, 23 Mar 2017 00:00:00 -0400</pubDate>
        <link>https://roche.io/2017/03/huge-google-maps</link>
        <guid isPermaLink="true">https://roche.io/2017/03/huge-google-maps</guid>
        
        
      </item>
    
      <item>
        <title>Snake Rave 1.1</title>
        <description>&lt;p&gt;&lt;a href=&quot;/snakerave&quot;&gt;Snake Rave&lt;/a&gt; version 1.1 is now live. Changes since the last post include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Added ‘Loading’, ‘How to Play’, ‘About’, and ‘Settings’ screens&lt;/li&gt;
  &lt;li&gt;Added option to Settings for wrap-around to be turned on or off&lt;/li&gt;
  &lt;li&gt;Added option to Settings to change the current speed of the snake&lt;/li&gt;
  &lt;li&gt;Added option to Settings to toggle whether snake speeds up with each point&lt;/li&gt;
  &lt;li&gt;Made game pause and reset automatically on window resize / rotation&lt;/li&gt;
  &lt;li&gt;Improved ‘Game Over’ screen to show score, time, and speed&lt;/li&gt;
  &lt;li&gt;Increased speed of snake as game progresses (0.02x increase per point)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/snakerave&quot;&gt;Play now&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Screenshots:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/media/2016/12/snakerave_0_main_menu.png&quot; alt=&quot;Snake Rave Menu&quot; /&gt;
&lt;img src=&quot;/media/2016/12/snakerave_1_playing.png&quot; alt=&quot;Snake Rave Playing&quot; /&gt;
&lt;img src=&quot;/media/2016/12/snakerave_2_how_to_play.png&quot; alt=&quot;Snake Rave How to Play&quot; /&gt;&lt;/p&gt;

</description>
        <pubDate>Mon, 02 Jan 2017 00:00:00 -0500</pubDate>
        <link>https://roche.io/2017/01/snake-rave-v1-1</link>
        <guid isPermaLink="true">https://roche.io/2017/01/snake-rave-v1-1</guid>
        
        
        <category>games</category>
        
      </item>
    
      <item>
        <title>Snake Rave</title>
        <description>&lt;p&gt;I made &lt;a href=&quot;/snakerave&quot;&gt;a snake clone&lt;/a&gt; recently using &lt;a href=&quot;http://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt;. It’s fully responsive and works on desktop, laptop, tablet, or smartphone.&lt;/p&gt;

&lt;p&gt;You can use WASD, arrow keys, swiping, or tapping the screen edges to move. Movement is handled using &lt;a href=&quot;https://craig.is/killing/mice&quot;&gt;Mousetrap&lt;/a&gt; and &lt;a href=&quot;http://hammerjs.github.io/&quot;&gt;HammerJS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/snakerave&quot;&gt;Play now&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Wed, 14 Dec 2016 00:00:00 -0500</pubDate>
        <link>https://roche.io/2016/12/snake-rave</link>
        <guid isPermaLink="true">https://roche.io/2016/12/snake-rave</guid>
        
        
        <category>games</category>
        
      </item>
    
  </channel>
</rss>
