Jekyll2020-01-01T21:21:32-05:00https://grant.ai/feed.xmlgrant.aiGrant H. ParkNotes on Data@Scale 20182018-10-25T14:00:00-04:002018-10-25T14:00:00-04:00https://grant.ai/keyboards/2018/10/25/notes-on-data-at-scale<p>The following notes are quick thoughts and summarizations of various talks at the Data@Scale conference I attended today. The full schedule of events along with some videos of the presentations are found <a href="https://atscaleconference.com/events/data-scale-2018/">here</a>.</p>
<p><strong>Lessons and Observations Scaling a Timeseries Database</strong> <em>by</em> <strong>Ryan Betts</strong><em>, Director of Platform Engineering at InfluxData</em></p>
<ul>
<li>Timeseries Database</li>
<li>LSM</li>
</ul>
<p><strong>Leveraging Sampling to Reduce Data Warehouse Resource Consumption</strong> <em>by</em> <strong>Gabriela Jacques Da Silva</strong><em>, Software Engineer at Facebook; and</em> <strong>Donghui Zhang</strong><em>, Software Engineer at Facebook</em></p>
<ul>
<li>Various research papers and a closed form error estimate</li>
</ul>
<p><strong>Voting with Witnesses the Apache Cassandra Way</strong> <em>by</em> <strong>Ariel Weisberg</strong><em>, PMC Member at Apache Cassandra</em></p>
<ul>
<li>Quorums</li>
<li>Merkle Tree</li>
<li>Consistent Hashing (Hash Rings)</li>
<li>Visible / Witness</li>
</ul>
<p><strong>Deleting Data @ Scale</strong> <em>by</em> <strong>Ben Strahs</strong><em>, Software Engineer, Privacy & Data Use at Facebook</em></p>
<ul>
<li>Schemas</li>
<li>Widespread testing</li>
<li>Restoration (Continuous)</li>
</ul>
<p><strong>Scaling Data Plumbing at Wayfair</strong> <em>by</em> <strong>Ben Clark</strong><em>, Chief Architect at Wayfair</em></p>
<ul>
<li>Sliding Window on Pipeline</li>
<li>Leaky Bucket</li>
<li>ETL</li>
</ul>
<p><strong>Presto: Pursuit of Performance</strong> <em>by</em> <strong>Andrii Rosa</strong><em>, Software Engineer at Facebook and</em> <strong>Matt Fuller</strong><em>, VP of Engineering at Starburst</em></p>
<ul>
<li>Cost-based optimizer</li>
<li>Fast SQL querying</li>
<li>Use of coefficients to determine cost of three things: storage usage, CPU usage, and complexity</li>
</ul>
<p><strong>Building Highly Reliable Data Pipelines at Datadog</strong> <em>by</em> <strong>Jeremy Karn</strong><em>, Staff Data Engineer at Datadog</em></p>
<ul>
<li>Spot Instances</li>
<li>On-demand instances</li>
<li>Isolate issues via preventatively running multiple pipelines</li>
</ul>The following notes are quick thoughts and summarizations of various talks at the Data@Scale conference I attended today. The full schedule of events along with some videos of the presentations are found here.State of Mutation Testing on Android2018-10-07T14:34:17-04:002018-10-07T14:34:17-04:00https://grant.ai/keyboards/2018/10/07/state-of-mutation-testing-on-android<p>Mutation testing is unit test testing. If your unit tests are full of false-positives, meaning that there are pointless or absent assertions, and your test coverage is misleadingly high; it is probably time for you to maintain your test suite with mutation testing.</p>
<p>This is how it works:</p>
<ul>
<li>Take a piece of code along with its unit tests.</li>
<li>Mutate the code in a fundamental way, e.g. change a <code class="highlighter-rouge"><</code> to <code class="highlighter-rouge">></code>.</li>
<li>If your unit tests still <em>pass</em>*, then the mutation test has failed.</li>
<li>Otherwise, try the above steps exhaustively until all possible mutations are tested.</li>
<li>If your unit tests <em>kill</em>* all the mutations, then your code coverage result for the tested piece of code is accurate and meaningful.</li>
</ul>
<p>* <em>If the units test pass without having reached the changed code, the mutated code behaves similarly to the original code despite all different inputs, or if the propogated symptoms of the mutated code are never acknowledged by the unit tests, then the mutation test is considered failed. Otherwise, the unit tests will have “killed” the mutants and pass the mutation test.</em></p>
<p>Here is a simple example of some code and a test suite that passes mutation testing:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">boolean</span> <span class="nf">sampleCode</span><span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">x</span> <span class="o"><</span> <span class="n">y</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="mi">1</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">return</span> <span class="mi">2</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">assertTrue</span><span class="o">(</span><span class="n">sampleCode</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span><span class="mi">2</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="mi">1</span><span class="o">));</span>
<span class="n">assertTrue</span><span class="o">(</span><span class="n">sampleCode</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="mi">1</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="mi">2</span><span class="o">));</span>
<span class="n">assertTrue</span><span class="o">(</span><span class="n">sampleCode</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span><span class="mi">1</span><span class="o">).</span><span class="na">equals</span><span class="o">(</span><span class="mi">2</span><span class="o">));</span>
</code></pre></div></div>
<p>The above code would produce mutants in which <code class="highlighter-rouge"><</code> is replaced with one of <code class="highlighter-rouge">></code>, <code class="highlighter-rouge">==</code>, <code class="highlighter-rouge">>=</code>, or <code class="highlighter-rouge"><=</code>. The test suite would have a unique result consisting of at least one failed assertion for each mutant case, acknowledging the different state produced by each mutant via <code class="highlighter-rouge">.equals()</code>. Thus, the test suite would pass mutation testing.</p>
<p>A couple of months ago at work, I was introduced to the Gradle code coverage tool and its use case in our development cycle and CI. I really questioned it after having figured out that coverage means nothing if you game the assertions in tests. You can effectively call code and make unnecessary or absolutely no assertions in your unit tests, still achieving coverage for that code.</p>
<p>Such a possibility for abuse indicates that it is important for my team to scrutinize unit tests in each code review, which is not always the case (given that there is an informal assumption that no one would try to game the tests). I think there is a lot of time, trust, and comfort to be gained from mutation testing – and I imagine that in some industries, it is an unquestionable
requirement for large teams.</p>
<p>Unfortunately, mutation testing is not in high demand for Android development. There is a <a href="http://pitest.org/">popular mutation testing library called PIT</a> which happens to have a great Gradle plugin – but because of how different Google’s Java environment is from the “standard”, it is not easy to port over to Android. There is an <a href="https://github.com/koral--/gradle-pitest-plugin">experimental fork</a> of the Gradle plugin by @koral–, which works for basic tests using <a href="http://robolectric.org/">Roboelectric</a>, but it is not yet up to speed for enterprise testing. I also hear rumors of certain large companies having their own internal tools for mutation testing on Android but are too stingy to share such a power with the rest of the world.</p>
<p>The only solution I can think of to address the limitations for Android, is to decouple all environmental implementations from business logic. That is, ensure that all code to be tested can be compiled without the ADK – essentially just sticking to POJO code. My team does a good job of this for the most part and tries maintain the status quo for the reason above. Ironically, there are a small number of components in our project that do not have tests because it would be a pain to mock the environmental requirements – so tech debt’s a thing.</p>Mutation testing is unit test testing. If your unit tests are full of false-positives, meaning that there are pointless or absent assertions, and your test coverage is misleadingly high; it is probably time for you to maintain your test suite with mutation testing.Introducing the Micro322018-09-24T14:34:17-04:002018-09-24T14:34:17-04:00https://grant.ai/keyboards/2018/09/24/introducing_the_micro_32<p>I’ve been piloting a 32-key layout for a year now, primarily for LaTeX and essay writing. Since I’ve graduated and no longer have homework, I now only type for work.</p>
<p>My layout is in reach of all the fingers and I can do any combo or config that I can think of with ease. On <a href="">10fastfingers</a>, my WPM is comfortably 144 on the normal test and 110 on the advanced test. On <a href="">speedcoder.net</a>, my WPM is 64 for the C++ test.</p>
<p><img src="https://grant.ai///assets/img/keymap_micro_32.png" alt="result" /></p>
<p><strong>Some notes</strong>:</p>
<ul>
<li>
<p>I have modifers on the homerow because I will accidentally activate them elsewhere from lagging my fingers during fast typing.</p>
</li>
<li>
<p>My modifiers form symmetries with each other on both halves of the layout so that I can always form a combo.</p>
</li>
<li>
<p>I have all my macros and layouts implemented via QMK. You probably get the point about how many combos you can form with just 32 keys so I won’t be pedantic with the math here.</p>
</li>
<li>
<p><a href="https://gist.github.com/grant-park/13990d95307ea56e2c5f95a35234efcb">Here is a snapshot of my QMK keymap.</a></p>
</li>
</ul>
<p>Meanwhile, I’ve handwired a prototype as shown below:</p>
<p><img src="https://grant.ai///assets/img/micro_32.jpg" alt="result" /></p>
<p>The halves are flashed with <a href="https://github.com/qmk/qmk_firmware/tree/master/keyboards/lets_split">Let’s Split firmware</a> and communicate via I2C over a TRRS cable. The switches are Gateron silent black, have O-Rings, and have Krytox-lubed springs and stems. They’re pretty silent so I like using them at work.</p>
<p>I am prototyping a PCB and some case designs for a new keyboard with my layout – I’m calling it the micro_32 since it’s a tiny-ass keyboard with 32 keys and it coincidentally sounds like a combination of ProMicro and Atmega32u4. Originally I wanted to name it the “Micro32”, but I realized it was <a href="https://www.favero.com/en2_billiard_electronic_digital_controller_to_time_accounting_system_for_billiard-59-22.html">already taken and trademarked</a> – hence the casing and added underscore.</p>
<p><a href="mailto:granthpark@gmail.com">Email me</a> if you would like to get your hands on one.</p>
<p>Here is a snapshot of my keymap in QMK:</p>
<noscript><pre>400: Invalid request
</pre></noscript>
<script src="https://gist.github.com/13990d95307ea56e2c5f95a35234efcb.js"> </script>I’ve been piloting a 32-key layout for a year now, primarily for LaTeX and essay writing. Since I’ve graduated and no longer have homework, I now only type for work.Deep Black PBT Keycaps2018-03-13T14:34:17-04:002018-03-13T14:34:17-04:00https://grant.ai/keyboards/2018/03/13/keycaps<p>Final result first:</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-result.jpg" alt="result" /></p>
<p>Before and After:</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-before_after.jpg" alt="result" /></p>
<p>I bought “Blank Black PBT Keycaps” from <a href="https://mechanicalkeyboards.com/shop/index.php?l=product_detail&p=1652">mechanicalkeyboards.com</a>.</p>
<p>Unfortunately, they were dark grey in color. I really like deep black, and I’ve had to dye my own Cherry ML keycaps in the past because no one makes blank black ML keycaps nowadays. I didn’t document my past dyeing process, so this is my chance to do it now.</p>
<p>This isn’t a do-while-read guide. If you’re going to follow in my footsteps, read everything here first.</p>
<p>Before dyeing, we clean the caps thoroughly with a q-tip and rubbing alcohol.</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-cleaning_cap.jpg" alt="cleaning_caps" /></p>
<p>All 46 done.</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-clean_array_of_caps.jpg" alt="done_cleaning_caps" /></p>
<p>Now we get ready to boil using this. We boil for about 30 minutes.</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-dye.jpg" alt="dye_closeup" /></p>
<p>Don’t forget to use something to suck in toxic fumes while boiling. An open window isn’t enough. This shit smells like gasoline and can leave your area smelling nauseating for a couple days. I use a <a href="https://www.amazon.com/Xytronic-0608426DLX-426DLX-Fume-Extractor/dp/B0007ZLH4Q/ref=sr_1_7?ie=UTF8&qid=1521116905&sr=8-7&keywords=fume+extractor&dpID=311CqKVeKsL&preST=_QL70_&dpSrc=srch">carbon filter fume-extractor</a> that I have on hand usually for soldering.</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-boiling.jpg" alt="dye_closeup" /></p>
<p>Strain the caps afterwards.</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-strain.jpg" alt="dye_closeup" /></p>
<p>They’re bronze colored, but don’t be alarmed. It’s because there is a lot of sticky excess dye stuck on them.</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-bronze.jpg" alt="dye_closeup" /></p>
<p>To get rid of the excess, soap and water isn’t enough. We need to soak them in isopropyl alcohol for 24 hours, changing them out every 6-12 hours.</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-soak.jpg" alt="dye_closeup" /></p>
<p>Once all is done, they should be pitch black save for a bit of residue here and there. The residue can be cleaned off with soap and water or another bathing session in alcohol. I got a little excited and put the caps on my keyboard before I could finish cleaning them all (I’ll get to it later).</p>
<p><img src="https://grant.ai///assets/img/deep_black_keycaps-impurity.jpg" alt="dye_closeup" /></p>Final result first:Arch Linux on the Macbook Pro (Retina, 13-inch, Early 2015)2018-02-11T13:00:00-05:002018-02-11T13:00:00-05:00https://grant.ai/keyboards/2018/02/11/archlinux-on-the-macbook-pro<p>I have been playing Whac-A-Mole with Arch Linux issues on my early-2015 Macbook Pro with Retina display since moving to it from Ubuntu-GNOME a month ago. That is not to say I’m complaining about this distro. A lot of these fires have been put out for good and I’m enjoying Arch. I’ll just be summarizing most of what I’ve come across as solutions to these issues in addition to providing my own notes.</p>
<p><img src="https://grant.ai///assets/img/archlinux_notes-screenshot.png" alt="screenshot" /></p>
<h1 id="wifi">WiFi</h1>
<p>You need either an ethernet-thunderbolt adapter or a tethered mobile network to jumpstart connectivity in order to download the necessary drivers for your network card. Once you have that, thankfully, you only need the single <code class="highlighter-rouge">brcmfmac</code> driver which you can get via <code class="highlighter-rouge">sudo pacman -S brcm80211</code>.</p>
<p>You can use a variety of programs at this point to handle network detection and configuration. I started out using <code class="highlighter-rouge">wicd</code> and <code class="highlighter-rouge">wicd-curses</code>, but found that <code class="highlighter-rouge">NetworkManager</code> was the most robust service. You can install it via <code class="highlighter-rouge">sudo pacman -S networkmanager</code> and configure your network via the gui <code class="highlighter-rouge">nmtui</code>.</p>
<p>Afterwards, the following script at startup takes care of everything.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#! /bin/sh</span>
<span class="nb">sudo </span>modprobe brcmfmac
<span class="nb">sudo </span>NetworkManager
</code></pre></div></div>
<h1 id="hidpi">HiDPI</h1>
<p>HiDPI works out of the box. I have been experimenting with <code class="highlighter-rouge">AwesomeWM</code> and <code class="highlighter-rouge">i3WM</code>, both window managers for X. As such, I have to fiddle with <code class="highlighter-rouge">XRandR</code> often and I find that <code class="highlighter-rouge">ARandR</code> makes life easier. I work with <code class="highlighter-rouge">2560x1600</code> by default and <code class="highlighter-rouge">1920x1200</code> when my old-man eyes get tired.</p>
<h1 id="disabling-keyboard">Disabling Keyboard</h1>
<p><code class="highlighter-rouge">xinput disable "Apple Inc. Apple Internal Keyboard / Trackpad"</code></p>
<h1 id="natural-scrolling">Natural Scrolling</h1>
<p><code class="highlighter-rouge">sudo xinput set-prop bcm5974 275 1</code></p>
<h1 id="yaourt">Yaourt</h1>
<p>I like not having to type in passwords, not having to type in exact package names, and auto-compilation. Install <code class="highlighter-rouge">yaourt</code> via adding</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[archlinuxfr]
SigLevel = Never
Server = http://repo.archlinux.fr/$arch
</code></pre></div></div>
<p>to <code class="highlighter-rouge">/etc/pacman.conf</code>
and then <code class="highlighter-rouge">sudo pacman -Sy yaourt</code>. Afterwards, you can <code class="highlighter-rouge">yaourt -s <vague-package-name or some-keyword></code> to install things stress free.</p>
<h1 id="bluetooth">Bluetooth</h1>
<p><code class="highlighter-rouge">yaourt -s bluez</code> and use <code class="highlighter-rouge">blueman-manager</code> for out-of-the-box success. Use <code class="highlighter-rouge">bluetoothctl</code> cli as a fallback solution for finnicky devices. Works flawlessly with my custom keyboards and my bluetooth LSTN Bolt earphones.</p>
<h1 id="high-fidelity-playback-a2dp-on-bluetooth">High Fidelity Playback (A2DP) on Bluetooth</h1>
<p>Bluetooth audio sounds like shit for the first time on any pair of headphones/earphones. It’s most likely that the device sink is set to HSP/HFP (Headset Head Unit). To get around this, use <code class="highlighter-rouge">bluetoothctl</code> cli and <code class="highlighter-rouge">connect <mac-address></code> instead of going through something like <code class="highlighter-rouge">blueman-manager</code>. If you use <code class="highlighter-rouge">pavucontrol</code>, the device will auto-appear afterwards and you can select A2DP for the sink.</p>
<h1 id="media-keys">Media Keys</h1>
<p>Play/Pause and Next/Prev don’t magically work without binding them to commands in your environment. I don’t know of any popular CLIs, but <a href="https://github.com/acrisci/playerctl">playerctl</a> has worked very well for me. I use it with Spotify and QMPlay2. Example of usage:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>playerctl play-pause
playerctl next
playerctl previous
</code></pre></div></div>
<h1 id="webcam">Webcam</h1>
<p>Nope, doesn’t work out of the box. This <a href="https://github.com/patjak/bcwc_pcie/wiki/Get-Started">experimental driver</a> works pretty well for me. Make sure you unload <code class="highlighter-rouge">bdc_pci</code> before inserting the kernel module via <code class="highlighter-rouge">modprobe -r bdc_pci</code>.</p>
<h1 id="urxvt-and-ranger">Urxvt and Ranger</h1>
<p>Images can’t be previewed if <code class="highlighter-rouge">preview_images_method</code> is set in addition to <code class="highlighter-rouge">preview_images</code>. I keep my config a one-liner: <code class="highlighter-rouge">set preview_images true</code></p>
<h1 id="urxvt-vs-vim-colors">Urxvt vs Vim Colors</h1>
<p>If you are facing this common issue (which has a million misleading solutions online) you can fix all your problems by adhering to the community that uses base16. So far, I default to using <code class="highlighter-rouge">.Xdefaults</code> and <code class="highlighter-rouge">.Xresources</code> with base16-xresources and vim reads its colors from that as well. If you stick with base16, you won’t end up with unexpected colors that result from mixed offsets. I currently use the Base16 Material Theme which looks like:</p>
<p><img src="https://grant.ai///assets/img/archlinux_notes-vim.png" alt="vim_screenshot" /></p>
<p>You can demo a bunch of base16 themes <a href="http://chriskempson.com/projects/base16/">here</a>.</p>
<h1 id="my-dotfiles-and-autosetup">My Dotfiles and Autosetup</h1>
<p>You can find my configs here.</p>
<p>Basic setup for new machines:</p>
<p><code class="highlighter-rouge">pacman -S git htop fzf fd-rs bc ntfs-3g sudo tmux zsh zsh-syntax-highlighting rofi feh firefox awesome imagemagick networkmanager rsync scrot thunar ranger</code></p>I have been playing Whac-A-Mole with Arch Linux issues on my early-2015 Macbook Pro with Retina display since moving to it from Ubuntu-GNOME a month ago. That is not to say I’m complaining about this distro. A lot of these fires have been put out for good and I’m enjoying Arch. I’ll just be summarizing most of what I’ve come across as solutions to these issues in addition to providing my own notes.Old Portfolio Show & Tell2018-01-17T15:56:19-05:002018-01-17T15:56:19-05:00https://grant.ai/jekyll/update/2018/01/17/old-portfolio-show-n-tell<p>This is my old portfolio built with good old AngularJS.</p>
<p><img src="https://grant.ai///assets/img/old_portfolio_show_n_tell-screenshot.png" alt="screenshot_of_old_portfolio1" /></p>
<p>Every time someone pulled it up, a websocket connection would start transmitting and saving to MongoDB their conversation with my bot along with their IP. Its responses came from a loaded Google Spreadsheet via Tabletop.js.</p>
<p><img src="https://grant.ai///assets/img/old_portfolio_show_n_tell-screenshot_2.png" alt="screenshot_of_old_portfolio2" /></p>
<p>There was also a webhook for Telegram that kept track of who was visiting my sites from where. It allowed me to pick and communicate with a site visitor after turning off the bot and outputting my own responses from the Telegram app on my phone or my laptop.</p>
<p>If you want to check it out, it’s <a href="https://grant.ai/oldsite">right here</a>.</p>
<p>Here is the source code for the <a href="https://github.com/grant-park/oldsite">client</a> and the <a href="https://github.com/grant-park/grantbot">server</a>.</p>This is my old portfolio built with good old AngularJS.How to Make Your Terminal an IDE2016-08-20T14:00:00-04:002016-08-20T14:00:00-04:00https://grant.ai/programming/2016/08/20/how-to-make-your-terminal-an-ide<p>Toss Sublime, WebStorm, Atom, or whatever you’re using. I’m going to teach you the way of terminal IDE-ing in a bash environment (with fuzzy file finding and goto function searching).</p>
<p>As a concession, I only use my terminal as an IDE for small projects. If I’m dealing with a lot of code (i.e. frameworks and other large codebases), I use dedicated software.</p>
<p>You should be using a terminal based editor for this to work. If not, I recommend that you dive into one before trying to make your terminal an IDE. <br />
My ingredients (asterisked means optional):</p>
<ol>
<li>Vim/Emacs/Nano, or any other terminal based text editor</li>
<li>Zsh Shell (for plugins galore and tabbed autocompletion)</li>
<li>Tmux (split your terminal into a dozen windows especially for those node projects)</li>
<li>iTerm2 (pretty UI and scattered candies)</li>
<li>fzf (fuzzy file searching)</li>
<li>ack (easy grepping for finding any text)</li>
<li>Exuberant Ctags (goto function functionality)</li>
</ol>
<p>We’ll use Homebrew to install our tools, save for Zsh. If you don’t have it already, just run the following line and restart your shell and terminal for good measure.</p>
<p><code class="highlighter-rouge">/usr/bin/ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"</code></p>
<p>To install Zsh, run this curl:</p>
<p><code class="highlighter-rouge">sh -c “$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"</code></p>
<p>For Tmux:
<code class="highlighter-rouge">brew install tmux</code></p>
<p>For iTerm2, install the application from their website: http://www.iterm2.com/</p>
<p>For fzf:
<code class="highlighter-rouge">brew install fzf</code></p>
<p>For ack:
<code class="highlighter-rouge">brew install ack</code></p>
<p>For Exuberant Ctags:
<code class="highlighter-rouge">brew install ctags</code></p>
<p>Create and save in your ~/.ctags file the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>recurse=yes
exclude=.git
exclude=vendor/*
exclude=node_modules/*
exclude=db/*
exclude=log/*
</code></pre></div></div>
<p>You can create a ctags file by running ctags along with the directory you want. For example, the following will make a ctags file for your current directory: <code class="highlighter-rouge">ctags .</code></p>
<p>You’ll have to manually updated your ctags for every new file, method, or variable name you want indexed unless you use automatic indexing. I personally use https://github.com/craigemery/vim-autotag.</p>
<p>Make sure to update your editor’s configuration file to recognize your ctags file. For example, my vim configuration file, ~/.vimrc, contains the following line:</p>
<p><code class="highlighter-rouge">set tag =./tags,tags;$HOME</code></p>
<p>The next step is figuring out the key bindings for goto functionality. For Vim, the following bindings are available by default:
Jump to definition: <code class="highlighter-rouge">^]</code></p>
<p>Jump back from definition: <code class="highlighter-rouge">^t</code></p>
<p>Preview definition: <code class="highlighter-rouge">^w }</code></p>
<p>See all definitions: <code class="highlighter-rouge">g]</code></p>
<p>And that’s it. You’ve got the essentials for IDEing on the terminal. Happy hacking!</p>Toss Sublime, WebStorm, Atom, or whatever you’re using. I’m going to teach you the way of terminal IDE-ing in a bash environment (with fuzzy file finding and goto function searching).$19 Table + $22 Arm = $41 Adjustable Standing Desk2016-04-09T14:00:00-04:002016-04-09T14:00:00-04:00https://grant.ai/misc/2016/04/09/19-table-22-arm-equals-41-adjustable-standing-desk<ol>
<li>
<p><a href="http://www.walmart.com/ip/Mainstays-Coffee-Table-Black-Oak-Finish/17126589">Buy a coffee table from Walmart</a>. As I’m writing this, it’s $19 online. Use this on top of your regular desk.</p>
</li>
<li>
<p>If you want to switch easily between sit/stand, <a href="http://www.monoprice.com/Product?p_id=5402&gclid=CjwKEAjw86e4BRCnzuWGlpjLoUcSJACaHG55zlqv5I3b8FXHIzbjyQ1SuBD2vG0_VMiCdzELNc7SEhoCwFLw_wcB">buy a monitor mount</a> and clamp it to the edge of the coffee table mentioned above. Depending on your monitor, the arm can cost anywhere from $25 to $100. You can then raise or lower the mount whenever you need to sit or stand.</p>
</li>
</ol>
<p>You can buy an IKEA coffee table for considerably less, but it doesn’t have the same edges you can clamp a monitor arm on and could potentially tip over.</p>
<p>Enjoy your cost effective alternative! It works really well for me and I’m 5’9, but results may vary for others. I’ll see if I can post pictures of myself using this later.</p>Buy a coffee table from Walmart. As I’m writing this, it’s $19 online. Use this on top of your regular desk.Welcome to the World of Xcode Plugins2016-02-01T13:00:00-05:002016-02-01T13:00:00-05:00https://grant.ai/programming/2016/02/01/welcome-to-the-world-of-xcode-plugins<p>Prior to using Alcatraz, I didn’t realize how much of my productivity was going to waste. I mean, I always knew there were Xcode plugins that could make life easier; it’s just that I didn’t realize how much easier. Please don’t make the same mistake I did. Take advantage of plugins.</p>
<p>Alcatraz is a popular package manager for Xcode. It’s easy to install and it has a very nice GUI window for picking/downloading a variety of cool plugins.</p>
<p>I’m only using two plugins right now, and they’re amazing: Fuzzy Autocomplete and XVim.</p>
<p>Fuzzy Autocomplete extends the functionality of Xcode’s default autocompletion when you type in prefixes of certain keywords.</p>
<p>e.g. Say you’re writing methods for UITableViewDataSource; by default, Xcode’s autocomplete will show you the following ONLY if you type in “func tableView…”:</p>
<p><code class="highlighter-rouge">func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell</code></p>
<p>However, with Fuzzy Autocomplete, you can type in “cellForRow…” and it will recognize the same function for you. No more scrolling endlessly through Xcode’s autocompletions!</p>
<p><img src="https://grant.ai///assets/img/welcome_to_the_world_of_xcode_plugins-screenshot.png" alt="screenshot" /></p>
<p>XVim is a plugin to simulate the Vim interface on Xcode. It’s totally badass and I never thought I could achieve this functionality before. If you’re into Vim, this is definitely the plugin for you.</p>
<p>Additionally, I’m running a custom script from SwiftLint that’s improved my coding style via providing warnings whenever my code seems messy or dangerous. I never knew about this sort of on-the-fly linting until SwiftLint, so it’s made my coding experience a lot more interesting.</p>
<p>You can say for sure that I’m really happy with my development environment right now :) If you’re comfortable and bored with the Xcode environment, go spice it up with plugins!</p>Prior to using Alcatraz, I didn’t realize how much of my productivity was going to waste. I mean, I always knew there were Xcode plugins that could make life easier; it’s just that I didn’t realize how much easier. Please don’t make the same mistake I did. Take advantage of plugins.Completion Handlers in Swift2016-01-31T14:00:00-05:002016-01-31T14:00:00-05:00https://grant.ai/programming/2016/01/31/completion-handlers-in-swift<p>I’m currently learning the MVVM design pattern and I’ve noticed that a lot of asynchronous code manipulation/organization requires the basic creation of completion handling functions.</p>
<p>Before, I always made messy code in my view controllers that looked sort of like this:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">kidQuery</span> <span class="o">=</span> <span class="kt">PFQuery</span><span class="p">(</span><span class="nv">className</span><span class="p">:</span> <span class="err">“</span><span class="n">_User</span><span class="err">”</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">theseKids</span> <span class="o">=</span> <span class="n">kidQuery</span><span class="o">.</span><span class="nf">whereKey</span><span class="p">(</span><span class="err">“</span><span class="n">parent</span><span class="err">”</span><span class="p">,</span> <span class="nv">containsString</span><span class="p">:</span> <span class="p">(</span><span class="kt">PFUser</span><span class="o">.</span><span class="nf">currentUser</span><span class="p">()?</span><span class="o">.</span><span class="n">objectId</span><span class="o">!</span><span class="p">)</span><span class="o">!</span> <span class="k">as</span> <span class="kt">String</span><span class="p">)</span>
<span class="n">theseKids</span><span class="o">.</span><span class="n">findObjectsInBackgroundWithBlock</span> <span class="p">{</span> <span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">error</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Void</span> <span class="k">in</span>
<span class="k">if</span> <span class="n">error</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">kidArray</span> <span class="o">=</span> <span class="n">result</span><span class="o">!</span> <span class="k">as</span> <span class="p">[</span><span class="kt">PFObject</span><span class="p">]</span> <span class="p">??</span> <span class="p">[]</span>
<span class="kt">Kids</span><span class="o">.</span><span class="n">sharedData</span><span class="o">.</span><span class="n">array</span> <span class="o">=</span> <span class="k">self</span><span class="o">.</span><span class="n">kidArray</span> <span class="k">as!</span> <span class="p">[</span><span class="kt">PFObject</span><span class="p">]</span>
<span class="k">if</span> <span class="k">self</span><span class="o">.</span><span class="n">kidArray</span> <span class="o">==</span> <span class="p">[]</span> <span class="p">{</span>
<span class="nf">print</span><span class="p">(</span><span class="err">“</span><span class="n">empty</span><span class="o">!!</span><span class="err">”</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">self</span><span class="o">.</span><span class="n">tableView</span><span class="o">.</span><span class="nf">reloadData</span><span class="p">()</span>
<span class="k">self</span><span class="o">.</span><span class="n">refreshCtrl</span><span class="o">.</span><span class="nf">endRefreshing</span><span class="p">()</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">dispatch_async</span><span class="p">(</span><span class="nf">dispatch_get_main_queue</span><span class="p">(),</span> <span class="p">{</span> <span class="p">()</span> <span class="o">-></span> <span class="kt">Void</span> <span class="k">in</span>
<span class="k">let</span> <span class="nv">alert</span> <span class="o">=</span> <span class="kt">UIAlertController</span><span class="p">(</span><span class="nv">title</span><span class="p">:</span> <span class="err">“</span><span class="kt">Error</span><span class="err">”</span><span class="p">,</span> <span class="nv">message</span><span class="p">:</span> <span class="n">error</span><span class="p">?</span><span class="o">.</span><span class="n">localizedDescription</span><span class="p">,</span> <span class="nv">preferredStyle</span><span class="p">:</span> <span class="o">.</span><span class="kt">Alert</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">cancel</span> <span class="o">=</span> <span class="kt">UIAlertAction</span><span class="p">(</span><span class="nv">title</span><span class="p">:</span> <span class="err">“</span><span class="kt">Close</span><span class="err">”</span><span class="p">,</span> <span class="nv">style</span><span class="p">:</span> <span class="o">.</span><span class="kt">Default</span><span class="p">,</span> <span class="nv">handler</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="n">alert</span><span class="o">.</span><span class="nf">addAction</span><span class="p">(</span><span class="n">cancel</span><span class="p">)</span>
<span class="k">self</span><span class="o">.</span><span class="nf">presentViewController</span><span class="p">(</span><span class="n">alert</span><span class="p">,</span> <span class="nv">animated</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nv">completion</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="p">})</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>After I moved my code around, the same function in my view controller looks a lot cleaner:</p>
<p><code class="highlighter-rouge">Tools.kidQuery(self, senderTableView: theTableView, senderRefresh: refreshCtrl, completionHandler: nil)</code></p>
<p>Essentially, I went from 20 lines of code to just 1 for this function, making my view controller less cluttered. I also have all of my data logic contained in their own separate classes. This makes debugging, testing, and adding new app features much easier for me. More importantly, it improves the readability of my project.</p>
<p>To make a lot of these changes to my code, I ran into creating functions with completion handlers. Now I’ll show you how to make your own.</p>
<p>Create a new .swift file. Let’s call it Toolbox.swift and put inside the following function:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="nf">testCompletionHandler</span><span class="p">(</span><span class="nv">input</span><span class="p">:</span> <span class="kt">String</span><span class="p">?,</span> <span class="nv">completionHandler</span><span class="p">:</span> <span class="p">((</span><span class="nv">result</span><span class="p">:</span> <span class="kt">String</span><span class="p">?)</span> <span class="o">-></span> <span class="kt">Void</span><span class="p">)?)</span> <span class="p">{}</span>
<span class="kt">Note</span> <span class="n">that</span> <span class="n">the</span> <span class="err">“</span><span class="n">input</span><span class="err">”</span> <span class="n">and</span> <span class="err">“</span><span class="n">completionHandler</span><span class="err">”</span> <span class="n">arguments</span> <span class="k">in</span> <span class="n">this</span> <span class="n">function</span> <span class="n">are</span> <span class="kd">optional</span><span class="p">;</span> <span class="n">you</span> <span class="n">could</span> <span class="n">call</span> <span class="n">this</span> <span class="n">function</span> <span class="n">with</span> <span class="kc">nil</span> <span class="k">for</span> <span class="n">both</span> <span class="n">arguments</span> <span class="n">and</span> <span class="n">it</span> <span class="n">could</span> <span class="n">still</span> <span class="k">do</span> <span class="nf">something</span> <span class="p">(</span><span class="n">or</span> <span class="k">do</span> <span class="n">nothing</span> <span class="n">at</span> <span class="n">all</span><span class="p">)</span><span class="o">.</span> <span class="kt">The</span> <span class="err">“</span><span class="n">completionHandler</span><span class="err">”</span> <span class="n">argument</span> <span class="k">is</span> <span class="n">actually</span> <span class="n">a</span> <span class="kt">Swift</span> <span class="n">block</span> <span class="n">that</span> <span class="n">can</span> <span class="n">execute</span> <span class="n">something</span> <span class="n">along</span> <span class="n">with</span> <span class="n">a</span> <span class="n">parameter</span> <span class="n">called</span> <span class="err">“</span><span class="n">result</span><span class="o">.</span><span class="err">”</span> <span class="kt">Right</span> <span class="n">now</span><span class="p">,</span> <span class="n">this</span> <span class="n">function</span> <span class="n">does</span> <span class="n">nothing</span><span class="p">,</span> <span class="n">so</span> <span class="kd">let</span><span class="err">’</span><span class="n">s</span> <span class="n">add</span> <span class="n">some</span> <span class="nv">logic</span><span class="p">:</span>
<span class="kd">func</span> <span class="nf">testCompletionHandler</span><span class="p">(</span><span class="nv">input</span><span class="p">:</span> <span class="kt">String</span><span class="p">?,</span> <span class="nv">completionHandler</span><span class="p">:</span> <span class="p">((</span><span class="nv">result</span><span class="p">:</span> <span class="kt">String</span><span class="p">?)</span> <span class="o">-></span> <span class="kt">Void</span><span class="p">)?)</span> <span class="p">{</span>
<span class="k">if</span> <span class="k">let</span> <span class="nv">aString</span> <span class="o">=</span> <span class="n">input</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">aString</span> <span class="o">==</span> <span class="err">“</span><span class="kt">I</span> <span class="n">want</span> <span class="n">a</span> <span class="n">completion</span> <span class="n">handler</span><span class="o">!</span><span class="err">”</span> <span class="p">{</span>
<span class="k">if</span> <span class="k">let</span> <span class="nv">aHandler</span> <span class="o">=</span> <span class="n">completionHandler</span> <span class="p">{</span>
<span class="nf">aHandler</span><span class="p">(</span><span class="nv">result</span><span class="p">:</span> <span class="err">“</span><span class="kt">Here</span> <span class="k">is</span> <span class="n">the</span> <span class="n">completion</span> <span class="n">handler</span><span class="o">!</span><span class="err">”</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">if</span> <span class="k">let</span> <span class="nv">aHandler</span> <span class="o">=</span> <span class="n">completionHandler</span> <span class="p">{</span>
<span class="nf">aHandler</span><span class="p">(</span><span class="nv">result</span><span class="p">:</span> <span class="kc">nil</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The moment “aHandler” is called inside of this function, the caller of this function will receive the completion block and can do anything they want with “result” unless it’s nil of course.</p>
<p>As an example, let’s look at ViewController.swift (a different source file):</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="kt">ViewController</span><span class="p">:</span> <span class="kt">UIViewController</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">myToolbox</span> <span class="o">=</span> <span class="kt">Toolbox</span><span class="p">()</span>
<span class="nf">viewDidLoad</span><span class="p">()</span> <span class="p">{</span>
<span class="k">super</span><span class="o">.</span><span class="nf">viewDidLoad</span><span class="p">()</span>
<span class="n">myToolbox</span><span class="o">.</span><span class="nf">testCompletionHandler</span><span class="p">(</span><span class="s">"I want a completion handler!"</span><span class="p">)</span> <span class="p">{</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Void</span> <span class="k">in</span>
<span class="k">if</span> <span class="k">let</span> <span class="nv">aString</span> <span class="o">=</span> <span class="n">result</span> <span class="p">{</span> <span class="nf">print</span><span class="p">(</span><span class="n">aString</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>When we call our created completion handler function in viewDidLoad, we should receive “Here is the completion handler!” in the console. We’ve successfully created a completion handler function and now you can use this same pattern to move all your asynchronous logic to specialized classes for ultimately cleaner, more readable code!</p>I’m currently learning the MVVM design pattern and I’ve noticed that a lot of asynchronous code manipulation/organization requires the basic creation of completion handling functions.