<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  
  <title type="text" xml:lang="en">jazzychad's blog</title>
  <link type="application/atom+xml" href="http://blog.jazzychad.net/feed/index.xml" rel="self"/>
  <link type="text" href="http://blog.jazzychad.net" rel="alternate"/>
  <updated>2014-01-03T12:29:05-08:00</updated>
  <id>http://blog.jazzychad.net/</id>
  <author>
    <name>Chad Etzel</name>
    </author>
  <rights>Copyright (c) 1984-2011, Chad Etzel; all rights reserved.</rights>
  
  
  <entry>
    <title>Announcing Tetra</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2013/08/22/announcing-tetra.html">http://blog.jazzychad.net/2013/08/22/announcing-tetra.html</link>
    <updated>2013-08-22T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2013/08/22/announcing-tetra.html</id>
    <guid>http://blog.jazzychad.net/2013/08/22/announcing-tetra.html</guid>
    <content type="html">&lt;p&gt;Today I am very pleased to announce the launch of
&lt;a href=&quot;http://tetragame.com&quot;&gt;Tetra&lt;/a&gt; - a new iPhone and iPad game app that I
have been working on over the last three months.&lt;/p&gt;




&lt;p&gt;Tetra is a 2-player puzzle board game. The goal is to get 4-in-a-row
on the board, but it's not as simple as it seems...&lt;/p&gt;

&lt;p&gt;For more information, and to see the full set of
&lt;a href=&quot;http://tetragame.com/rules.html&quot;&gt;rules&lt;/a&gt; you can check out
&lt;a href=&quot;http://tetragame.com&quot;&gt;http://tetragame.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Tetra is available on the &lt;a href=&quot;https://itunes.apple.com/us/app/tetra-board-game/id648252454?ls=1&amp;amp;mt=8&quot;&gt;App Store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra_medium.jpg&quot; width=&quot;512&quot; height=&quot;384&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;br/&gt;


&lt;p&gt;&lt;img src=&quot;/images/tetra_table_medium.jpg&quot; width=&quot;512&quot;height=&quot;384&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>Implementing Letterpress UI in UIKit</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2013/07/30/implementing-letterpress-uikit.html">http://blog.jazzychad.net/2013/07/30/implementing-letterpress-uikit.html</link>
    <updated>2013-07-30T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2013/07/30/implementing-letterpress-uikit.html</id>
    <guid>http://blog.jazzychad.net/2013/07/30/implementing-letterpress-uikit.html</guid>
    <content type="html">&lt;p&gt;&lt;em&gt;&lt;strong&gt;Good artists copy. Great artists steal.&lt;/strong&gt;&lt;/em&gt;  &amp;mdash; Steve Jobs, (mis)quoting Pablo Picasso.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.atebits.com/letterpress/&quot;&gt;Letterpress&lt;/a&gt; is a fantastic
game. I remember how magical and fun the UI felt when I first played
it. Letterpress was released when I was in the midst of completely
rewriting the &lt;a href=&quot;http://iamexec.com/blog/how-we-built-the-new-exec-iphone-app&quot;&gt;Exec Errands
app&lt;/a&gt;,
which involved a &lt;em&gt;lot&lt;/em&gt; of custom UI components. I learned a lot about
custom UI for iOS during that project, but Letterpress had some super
advanced mojo happening in its UI. I wondered if I would ever be good
enough to create something quite so magical as that. I was also
shocked to learn that the entire UI of Letterpress is written using
OpenGL instead of UIKit. I guess that's why they say, &quot;&lt;a href=&quot;https://twitter.com/Jury/status/360137750940360705&quot;&gt;You never go
full Brichter.&lt;/a&gt;&quot;&lt;/p&gt;




&lt;p&gt;For quite a long time I have wanted to write a 2-player turn-based
game using Apple's Game Center infrastructure. Recently I was inspired
by a board game that my family enjoys playing, and I decided it was
just the right kind of game to turn into an app and experiment with
turn-based game development.&lt;/p&gt;

&lt;p&gt;I gave myself two challenges while developing the app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an abstractable turn-based game library that could be used
to create subsequent game apps. All I would need to do in the
future is write the game specific logic and interface, then the
library would take care of the rest of the game-state and
turn-based logic for free. Other boilerplate things like Themes and
Sharing actions would also be handled by this library. This turned
into a library of code called &lt;strong&gt;CCCGameKit&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;See how much of the Letterpress aesthetic I could achieve using my
newfound custom UI chops, but I could only use UIKit, Core
Graphics, and Quartz Core. This should also be a library that could
be used in any app. Rewritten components like Alert Views and
Action Sheets should have drop-in API and delegate protocols so
that, as much as possible, standard UIKit components could just be
replaced with these custom implementations without much code
changing. This library of code eventually turned into &lt;strong&gt;CEKit&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;&lt;strong&gt;CEKit&lt;/strong&gt; turned out to be pretty compact:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/cekit.png&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;...while &lt;strong&gt;CCCGameKit&lt;/strong&gt; was a bit more complex:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/cccgamekit.png&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/cccgamekit2.png&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With the combination of CEKit and CCCGameKit, I produced an app that
is pretty darn close to the look and feel of Letterpress. Thus, &lt;a href=&quot;http://tetra.jazzychad.net&quot;&gt;Tetra
for iOS&lt;/a&gt; was born.&lt;/p&gt;

&lt;p&gt;Below are some screenshots and gifs of parts of the game, especially
demonstrating some of the similarities betwen the Letterpress and
Tetra UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; gifs are displayed at 15 frames per second, but rest
assured that the app runs at a full 60 fps rate on hardware all the
way back to iPhone 3GS.&lt;/p&gt;

&lt;p&gt;Launching the game:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/welcome.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&quot;How to Play&quot; prompt on first launch:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/onboard_alert.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;...which leads to the game instructions:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/how_to_play.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The list of current games and turn states:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/list.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Swipe to remove a game (I am most proud of this interaction because it
was the most difficult to get working correctly; sample of some of
the code at the end of this post):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/remove.gif&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Game board view controller:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/board.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Menu action sheet spawned by the Hamburger Button in the top right of
the screen (in Letterpress all menus are alert views, however I still
like action sheets for many-choice menus):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/action_sheet.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Alert View with flat pill buttons:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/alert.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The alert view animates in from the top of the screen and falls off
the bottom when dismissed. Each time it appears the amount and
direction of rotation are random so each alert is unique:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/alert.gif&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Bubble labels pop open and closed to display ephemeral messages:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/won2.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Animated bubble label (sample of code at the end of this post):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/bubble_label.gif&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When the game ends in a tie (which is very rare), the board does
something a bit whimsical, just for fun:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/tied.gif&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One new view controller I created for the app was a custom Matchmaker
View Controller for starting a new game. The standard Apple Game
Center matchmaking interface is quite cumbersome and can take up to 5
taps to start a game with a friend. I decided it could be done in 1
tap:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/matchmaker.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There is also a theme system in the app which will re-skin all the
components with different colors:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/themes.png&quot; class=&quot;centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The second hardest thing to accomplish while trying to achieve
Letterpress-level UI exactness was implementing the navigation bar
which adds a slight shadow when the content below is scrolled up
underneath the navigation bar:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/theme_header_light.gif&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Somewhat more difficult is also animating the navigation bar color to
a lighter shade when a dark theme is in use (sneak peak of code at the
end of this post):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/theme_header2.gif&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;h1&gt;Graphics&lt;/h1&gt;

&lt;p&gt;With the exception of the pre-loaded screenshots for the &quot;How To Play&quot;
view controller, there are only four graphic assets in the app. All of
the other visual elements (including all of the game pieces,
disclosure indicators, hamburger buttons, etc) are drawn
programmatically using Core Graphics and Quartz Core and cached as
UIImages. The only graphics that are fetched remotely are the player
avatars from Game Center.&lt;/p&gt;

&lt;h1&gt;Results&lt;/h1&gt;

&lt;p&gt;Overall I am really happy with how things turned out. This has been
the most challenging software product I have built as a
&lt;a href=&quot;/2012/12/31/year-in-review-side-projects.html&quot;&gt;side-project&lt;/a&gt;. I
started the app on May 14, 2013 and have been working on it during
random hours on nights and weekends. In total it has been about 100
hours of work. Making this app has been extremely satisfying because
it forced me to learn many new things about UI code and forced me to
think about how to abstract and generalize functionality from the
beginning so that the code may be reused in future apps.&lt;/p&gt;

&lt;p&gt;This has certainly been the culmination of my 3 years of professional
Objective-C programming. I don't think I went &lt;em&gt;Full Brichter&lt;/em&gt;, but
maybe I was able to go &lt;em&gt;Half Brichter&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Some stats according to &lt;a href=&quot;http://cloc.sourceforge.net/&quot;&gt;cloc&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4707 lines of code in CCCGameKit&lt;/li&gt;
&lt;li&gt;2158 lines of code in CEKit&lt;/li&gt;
&lt;li&gt;4498 lines of code in Tetra-specific files&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Frame rates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;60 fps on iPhone 5&lt;/li&gt;
&lt;li&gt;60 fps on iPhone 3gs&lt;/li&gt;
&lt;li&gt;60 fps on iPod Touch 5th gen&lt;/li&gt;
&lt;li&gt;50+ fps on iPad Mini&lt;/li&gt;
&lt;li&gt;50+ fps on iPhone 4&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I'm sure if I worked a bit more on image caching and compositing I
could get the iPhone 4 and iPad Mini up to 60 fps. Perhaps in v2.&lt;/p&gt;

&lt;h1&gt;Things I didn't implement for v1&lt;/h1&gt;

&lt;p&gt;There were a few things I purposefully did not implement for v1
because of time constraints (or more likely, they are just out of my
grasp to implement in UIKit, for now...)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Drag panning alert views&lt;/strong&gt; - In Letterpress, you can drag alert
views up and down the screen with your finger. You can dismiss
alert views by pressing a button &lt;em&gt;or&lt;/em&gt; by flinging them off the
screen by pulling them down quickly. This feature didn't seem
strictly necessary to me, however now that I have a handle on
UIPanGestureRecognizers from getting the &quot;Swipe to Remove&quot;
interaction right, I think I know how to implement this in v2.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swipeable view controller navigation&lt;/strong&gt; - Much like Windows
Phone's Metro UI framework, Letterpress allows you to move between
screens in the navigation stack by swiping across the screen to
move between them. For now I am just using a stock
UINavigationController to handle view navigation (and doing my own
navigation bar magic within the stack). Swipe navigation was not
something I wanted to tackle in v1. I suppose this could be
accomplished using a custom Container View Controller, but this
seemed beyond the scope of the app for now. Maybe this was
something that was easier to implement in OpenGL.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Game-preview-to-game-board-zoom&lt;/strong&gt; - When you tap on a game in
the main game list in Letterpress, the game preview (represented by
colored squares) magically zooms from the preview frame to the full
screen while also fading the letters and rest of the game chrome
into view. I also render a preview of the current game-state,
however for now I just do a simple push to the game board. I plan
to make this transition more magical in v2.&lt;/li&gt;
&lt;/ol&gt;


&lt;h1&gt;Sneak Peek of the Code&lt;/h1&gt;

&lt;p&gt;For the curious, here are a few glimpses into the codebase.&lt;/p&gt;

&lt;p&gt;The logic that handles adding/removing the shadow (and changing the
color) of the navigation bar when content scrolls beneath it:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/scroll_did_scroll.png&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After setting all of the properties, the creation of the pill buttons
UI happens almost exclusively in the layoutSubviews method:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/pill_layout.png&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Similarly, the hamburger menu button is rendered in code during
layoutSubviews:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/bun_layout.png&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Everytime I see a bubble label appear it makes me smile because it
reminds me of &lt;a href=&quot;http://en.wikipedia.org/wiki/Pop-Up_Video&quot;&gt;Pop-Up
Video&lt;/a&gt;. Here is some of the
animation code responsible for displaying a bubble label:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/bubble_show.png&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In order to correctly implement the Swipe to Remove in the game list
cells, I had to implement part of the UIGestureRecognizerDelegate
protocol. I learned that UITableViewCells also implement this
protocol, so I had to be careful to call super in the case my
recognizer was not the one being triggered by scroll or swipe
gestures:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tetra/pangesture.png&quot; class=&quot;shadow centered&quot; /&gt;&lt;/p&gt;

&lt;h1&gt;Coming Soon&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://tetra.jazzychad.net&quot;&gt;Tetra&lt;/a&gt; should be available on the App Store by the end of August. I
just need to clean up a few bits of UI here and there, and then I can
ship it.&lt;/p&gt;

&lt;p&gt;Thanks to Loren Brichter, Karen Cheng, Eric Florenzano, Jason
Kozemczak, Dan Loewenherz, Chris Mitra, Paul Stamatiou, and Cristian
Strat for proofreading this post.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>2013 Resolutions</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2013/01/01/2013-resolutions.html">http://blog.jazzychad.net/2013/01/01/2013-resolutions.html</link>
    <updated>2013-01-01T00:00:00-08:00</updated>
    <id>http://blog.jazzychad.net/2013/01/01/2013-resolutions.html</id>
    <guid>http://blog.jazzychad.net/2013/01/01/2013-resolutions.html</guid>
    <content type="html">&lt;p&gt;&amp;bull; Earn 1 Bridge Master Point&lt;/p&gt;

&lt;p&gt;&amp;bull; Drop 20 pounds&lt;/p&gt;

&lt;p&gt;&amp;bull; Read the &lt;em&gt;A Song of Ice and Fire&lt;/em&gt; series&lt;/p&gt;

&lt;p&gt;&amp;bull; Read 3 graphic novels&lt;/p&gt;

&lt;p&gt;&amp;bull; Walk 1000 miles (~20mi/week)&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>2012 Year in Review: Side-Projects</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/12/31/year-in-review-side-projects.html">http://blog.jazzychad.net/2012/12/31/year-in-review-side-projects.html</link>
    <updated>2012-12-31T00:00:00-08:00</updated>
    <id>http://blog.jazzychad.net/2012/12/31/year-in-review-side-projects.html</id>
    <guid>http://blog.jazzychad.net/2012/12/31/year-in-review-side-projects.html</guid>
    <content type="html">&lt;p&gt;One of my favorite pastimes as a programmer is to work on personal
projects outside of work. I use side-projects as a creative outlet to
work on new and interesting things. I also use them as a learning
exercise. If I start a side-project, there must be &quot;one new thing&quot;
about the project I don't know how to do already. This can mean
learning a new language, API, framework, algorithm, whatever. The end
result is that I level up my skillset with each project. I recommend
this system for every programmer.&lt;/p&gt;

&lt;p&gt;Here is a list of side-projects that I started, developed, and shipped
in 2012:&lt;/p&gt;




&lt;hr /&gt;

&lt;h1&gt;BankersBox&lt;/h1&gt;

&lt;p&gt;I wanted to learn about HTML localStorage for storing local
preferences in internal web apps at Twilio. After finding the
localStorage APIs a bit lacking, I wanted to write a Redis-like
wrapper around localStorage to make it easier to handle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: March 05, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://www.twilio.com/engineering/2012/03/05/open-sourcing-bankersbox&quot;&gt;http://www.twilio.com/engineering/2012/03/05/open-sourcing-bankersbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href=&quot;https://github.com/twilio/BankersBox&quot;&gt;https://github.com/twilio/BankersBox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: javascript (for source), coffeescript (for testing)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: HTML localStorage&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: I consider this a side-project because it was never an
  official task inside of Twilio. I worked on it around my other
  assignments after hours on nights and weekends. Since I developed
  BankersBox to help with internal apps, it was open-sourced under
  Twilio's umbrella.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;Mailblog&lt;/h1&gt;

&lt;p&gt;I wanted to know how difficult it would be to create your own
Posterous-like &quot;blog-by-email&quot; system. Combining a few puzzle pieces
made it fairly easy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: March 12, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://blog.jazzychad.net/2012/03/12/create-your-own-posterous.html&quot;&gt;http://blog.jazzychad.net/2012/03/12/create-your-own-posterous.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;:
  &lt;a href=&quot;https://github.com/jazzychad/mailblog&quot;&gt;https://github.com/jazzychad/mailblog&lt;/a&gt;,
  &lt;a href=&quot;https://github.com/jazzychad/mailblog-files&quot;&gt;https://github.com/jazzychad/mailblog-files&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: php, ruby (jekyll), mailgun, S3&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: Learning to use Mailgun's webhook system&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: I worked on this project over a weekend. I published the
  post describing it Monday morning, and later that day Posterous
  announced it had been &lt;a href=&quot;http://blog.posterous.com/big-news&quot;&gt;acquired by
  Twitter&lt;/a&gt;. The timing was purely coincidental.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;ExportMyPosts&lt;/h1&gt;

&lt;p&gt;After Posterous was acquired, it occurred to me that there was no easy
way to export your blog data. People were worried what would happen to
their blogs during the transition to Twitter. I built ExportMyPosts in
response to provide a simple one-click export tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: March 20, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://exportmyposts.com/&quot;&gt;http://exportmyposts.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: php, Redis, S3, Posterous API, Stripe API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: Using Stripe to take online payments&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: I built this site in the four days between my departure
  from Twilio and &lt;a href=&quot;http://blog.jazzychad.net/2012/03/16/joining-exec.html&quot;&gt;starting at
  Exec&lt;/a&gt;. I
  published a post describing &lt;a href=&quot;http://blog.jazzychad.net/2012/03/21/launching-exportmyposts-in-four-days.html&quot;&gt;the making of the
  website&lt;/a&gt;
  shortly after it launched. There have been ~$550 revenue on ~50
  sales so far. At this point it is about break-even with the server
  costs. I may take it offline soon as the rate of sales has slowed way
  down.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;dcpubin&lt;/h1&gt;

&lt;p&gt;When Notch announced his new game, &lt;em&gt;0x10c&lt;/em&gt;, he released information
about a in-game computer called the &lt;em&gt;dcpu&lt;/em&gt; which players could program
to affect their environment. The dcpu programming spec was in its own
assembly language. I love assembly, so writing an emulator sounded
like a fun project. I also thought that players might want to share
code back and forth in an easy manner, so I created a specialized
pastebin for dcpu code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: April 07, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://www.dcpubin.com/&quot;&gt;http://www.dcpubin.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href=&quot;https://github.com/jazzychad/dcpubin&quot;&gt;https://github.com/jazzychad/dcpubin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: node.js, mongodb, heroku&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: &lt;a href=&quot;http://dcpu.com/&quot;&gt;dcpubin spec&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: Around the same time, another dcpu emulator pastebin
  appeared at &lt;a href=&quot;http://0x10co.de/&quot;&gt;http://0x10co.de/&lt;/a&gt;. It had more
  features and took off much more quickly with the 0x10c community. I
  abandoned the dcpubin project, and it is mostly filled with spam at
  this point.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;node-heroku-express&lt;/h1&gt;

&lt;p&gt;I was starting to write several node/mongodb/heroku apps in my spare
time, and each time I had to jump through the same hoops to get it up
and running. Finaly I just decided to create a boilerplate starting
point repo for these types of projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: April 25, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href=&quot;https://github.com/jazzychad/heroku-node-express&quot;&gt;https://github.com/jazzychad/heroku-node-express&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: node.js, mongodb, heroku&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;StepStats&lt;/h1&gt;

&lt;p&gt;I had a Fitbit for about six months, but I was not extremely motivated
by the data because the default graphs on their website are not very
insightful. I wanted graphs with longer bigger data sets and
trendlines, so I created the graphs I wanted using the Fitbit API and
set it up as a website anyone with a Fitbit could use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: April 30, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://stepstats.com/&quot;&gt;http://stepstats.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: node.js, mongodb, heroku, Fitbit API, flot.js (graphing)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: Fitbit API, flot.js (ok, that's two new things)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: I have asked to be added to the Fitbit app gallery several
  times, but each time I have had no response.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;Pixit&lt;/h1&gt;

&lt;p&gt;During a vacation in June, I ran into a problem I'm sure many people
have when out and about with friends. People were taking fun pictures
with their phones that I wanted to post to Facebook or Twitter. Asking
them to send me the pictures from their phone is somewhat cumbersome
and takes many steps. I thought up an app that would make it extremely
easy to send many pictures to a group of friends in one go.&lt;/p&gt;

&lt;p&gt;I wrote a beta version of the app that I use with my family, and it
works great. It just isn't polished enough for mass release. I'm not
sure if it would be worth the time and effort to wrap it up and ship
it. The monetization model is not clear (probably ads?) and the
hosting costs for photos would be non-trivial. It is extremely useful,
though.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: June 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: Objective-C, Parse, Facebook API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: Parse framework&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;Adian&lt;/h1&gt;

&lt;p&gt;When app.net released their API, I decided to throw my hat into the
ring of iOS clients. I took my codebase from TweetFire and refactored
it into an app.net specific client. It was the second app.net client
available in the App Store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: August-September 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;https://directory.app.net/app/32/adian/&quot;&gt;https://directory.app.net/app/32/adian/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: Objective-C, app.net API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: app.net API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: Adian has sold ~1,000 copies since release. Once Tapbots
  released Netbot (their port of TweetBot) it decimated sales of just
  about every other client on the market. I dropped the price from
  US$5.99 to US$1.99 and now it sells maybe 1 copy every few days.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;AdianBugs&lt;/h1&gt;

&lt;p&gt;During development of Adian, I was getting too much user feedback to
keep up ad hoc. So, I built a bug report/feature request system for
users to give structured feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: August 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://bugs.adianapp.com/&quot;&gt;http://bugs.adianapp.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: node.js, mongodb, heroku, app.net API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: Create a custom ticket system&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;TunesPost&lt;/h1&gt;

&lt;p&gt;I wanted to learn about the Apple Scripting Bridge system in OSX, so I
thought up a little task bar utility app that could read the currently
playing song in iTunes and then post it to app.net.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: September 01-03, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://longposts.com/1226802&quot;&gt;http://longposts.com/1226802&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: Objective-C, app.net API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: iTunes Scripting Bridge&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;SpotCast&lt;/h1&gt;

&lt;p&gt;Someone suggested I build a system that would allow someone to be a DJ
using Spotify. One person would play music, and others could &quot;tune-in&quot;
to their channel and their Spotify app would change songs along with
the DJ. Just like turntable.fm, but using Spotify to supply the music
instead. I thought, sounds cool - why not? It works incredibly well,
and I love having someone else queue up my music throughout the day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: September 03-05, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://gist.io/3625870&quot;&gt;http://gist.io/3625870&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: Objective-C, Tornado framework (for real-time message bus)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: Spotify Scripting Bridge&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: I did not realize that there was already a Spotify app
  called Soundrop that did exactly this. Oh well.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;LongPosts&lt;/h1&gt;

&lt;p&gt;Over the app.net Weekend Hackathon, I created an &quot;instant blogging
platform&quot; for app.net users. Since app.net posts support annotations
of up to 8k characters (still waiting, Twiter... lol), it seemed like
a good way to store longer-form blog post data. So, I cooked up an
annotation format to support blog posts and just store them in app.net
post objects. I found that longposts.com was available, so I grabbed
it and built a frontend website around the annotations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: October 20-21, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://longposts.com&quot;&gt;http://longposts.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href=&quot;https://github.com/jazzychad/longposts&quot;&gt;https://github.com/jazzychad/longposts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: node.js, mongodb, heroku, app.net API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: Use app.net post annotations&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: So far ~170 posts have been written on LongPosts. On
  December 20 I &lt;a href=&quot;http://longposts.com/2120058&quot;&gt;open-sourced LongPosts&lt;/a&gt;
  so that others can contribute to its ongoing development.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;CEGuideArrow&lt;/h1&gt;

&lt;p&gt;As part of the Pixit app, I created a custom UI arrow control that
would point at different parts of the interface during the
onboarding/tutorial phase of the app. Pixit was never released (yet?),
but I thought others might enjoy the arrow control, so I cleaned it up
and open-sourced it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: November 04, 2012&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://www.cocoacontrols.com/platforms/ios/controls/ceguidearrow&quot;&gt;http://www.cocoacontrols.com/platforms/ios/controls/ceguidearrow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href=&quot;https://github.com/jazzychad/CEGuideArrow&quot;&gt;https://github.com/jazzychad/CEGuideArrow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: Objective-C&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: CoreAnimation framework&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: Gained 74 stars and 7 forks on GitHub after being published
  on CocoaControls.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1&gt;Bridge Trainer&lt;/h1&gt;

&lt;p&gt;At some point I looked around and decided &lt;a href=&quot;http://longposts.com/1560733&quot;&gt;I was doing too many
side-projects&lt;/a&gt;. I wanted to improve my
life skills in some other fashion than programming. I have always
wanted to learn how to play
&lt;a href=&quot;http://en.wikipedia.org/wiki/Contract_bridge&quot;&gt;Bridge&lt;/a&gt;, and so I
decided to make that my next long term side-project. However, while
learning about the bidding system, I needed a way to train myself
since there are many rules to learn. So, what do I do? I break my rule
of no more programming and write my own training software (at least it
is Bridge related, right?).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Date&lt;/strong&gt;: November 2012 - Present&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt;: &lt;a href=&quot;http://bridge.jazzychad.net&quot;&gt;http://bridge.jazzychad.net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href=&quot;https://github.com/jazzychad/bridge-trainer&quot;&gt;https://github.com/jazzychad/bridge-trainer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt;: BankersBox, coffeescript, Bootstrap, S3&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One New Thing&lt;/strong&gt;: model the game of Bridge in code, create a
  completely client-side web app&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;: Currently only opening bids are covered by the trainer. Once
  I feel confident in my abilities there, I will move on to adding
  responses and rebids. Then will come the defensive bids. During the
  course of development I also got a &lt;a href=&quot;http://blog.jazzychad.net/2012/12/04/better-makefile-for-bootstrap.html&quot;&gt;Makefile
  update&lt;/a&gt;
  accepted to Bootstrap.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;So there you have it. 2012 was a busy year. Hopefully 2013 will be a
bit slower with non work-related programming, and I will start earning
my first Bridge Master Points.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>A Better Makefile for Bootstrap</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/12/04/better-makefile-for-bootstrap.html">http://blog.jazzychad.net/2012/12/04/better-makefile-for-bootstrap.html</link>
    <updated>2012-12-04T00:00:00-08:00</updated>
    <id>http://blog.jazzychad.net/2012/12/04/better-makefile-for-bootstrap.html</id>
    <guid>http://blog.jazzychad.net/2012/12/04/better-makefile-for-bootstrap.html</guid>
    <content type="html">&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; Bootstrap's
&lt;a href=&quot;https://github.com/twitter/bootstrap/blob/3b3dd3ac3c7b69d02406ede69bffcc4ee8a1ed6b/Makefile&quot;&gt;Makefile&lt;/a&gt;
is not so good. So I'm starting to make it
&lt;a href=&quot;https://github.com/jazzychad/bootstrap/blob/60e1a55dae8aaf6f0fdebe9c9c8a9fb97fef6c43/Makefile&quot;&gt;better&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A little bit of backstory:&lt;/p&gt;

&lt;p&gt;My current side-project is learning how to play
&lt;a href=&quot;http://en.wikipedia.org/wiki/Contract_bridge&quot;&gt;Bridge&lt;/a&gt;. To help learn
about the bidding process, I am making a simple static site web app
out of a &lt;a href=&quot;https://github.com/jazzychad/coffee-cards&quot;&gt;coffeescript playing card
library&lt;/a&gt;,
&lt;a href=&quot;https://github.com/jazzychad/BankersBox&quot;&gt;BankersBox&lt;/a&gt; for client-side
storage, and of course
&lt;a href=&quot;https://github.com/twitter/bootstrap&quot;&gt;Bootstrap&lt;/a&gt; for layout and
styling. The project is called
&lt;a href=&quot;https://github.com/jazzychad/bridge-trainer&quot;&gt;bridge-trainer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since each component has a compile step, I decided to take a
Jekyll-like approach by compiling the overall site into a &lt;code&gt;_site&lt;/code&gt;
directory which I then sync to S3 as a hosted bucket.&lt;/p&gt;




&lt;p&gt;You can see the &lt;a href=&quot;https://github.com/jazzychad/bridge-trainer&quot;&gt;github
repo&lt;/a&gt;, but the general
setup is an html, js, and css folder with BankersBox, and Bootstrap
living as &lt;code&gt;git submodules&lt;/code&gt; underneath their respective directories.&lt;/p&gt;

&lt;p&gt;When I'm ready to test a change, I background emacs with ^Z and
type &lt;code&gt;make&lt;/code&gt; to compile the site into a &lt;code&gt;_site&lt;/code&gt; directory which I can
load locally in my browser. You can see the &lt;a href=&quot;https://github.com/jazzychad/bridge-trainer/blob/1c11fe5d30b9c21ae765e8446ed53ff9c19aab80/Makefile&quot;&gt;first version of the
Makefile&lt;/a&gt;
which compiled the site.&lt;/p&gt;

&lt;p&gt;The Makefile would create the &lt;code&gt;_site&lt;/code&gt; directory, compile the
coffeescript files, run the Bootstrap make file, then copy all the
necessary files into the &lt;code&gt;_site&lt;/code&gt; hierarchy.&lt;/p&gt;

&lt;p&gt;Trouble was, Bootstrap would compile from scratch each time I ran
&lt;code&gt;make&lt;/code&gt;. This seemed rather unnecessary as none of the source files for
Bootstrap were changing between site builds.&lt;/p&gt;

&lt;p&gt;Here you can see near the top of Bootstrap's Makefile:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/bsmkold.png&quot; title=&quot;Original Makefile&quot; alt=&quot;Original Makefile&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/twitter/bootstrap/blob/3b3dd3ac3c7b69d02406ede69bffcc4ee8a1ed6b/Makefile#L14&quot;&gt;Original Makefile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bootstrap's Makefile is being used as a glorified shell script to run
a bunch of commands and not using make's real power: &lt;strong&gt;a compilation
asset dependency graph&lt;/strong&gt;. Also, there is no &lt;code&gt;all&lt;/code&gt; target, so if you
just run a normal &lt;code&gt;make&lt;/code&gt; command, the first target is run by
default. In this case the first target is &lt;code&gt;build&lt;/code&gt; which builds the
docs for Bootstrap. This takes about 2.4 seconds each time.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;make build

&lt;span class=&quot;c&quot;&gt;##################################################&lt;/span&gt;
Building Bootstrap...
&lt;span class=&quot;c&quot;&gt;##################################################&lt;/span&gt;

Running JSHint on javascript...             Done
Compiling LESS with Recess...               Done
Compiling documentation...                  Done
Compiling and minifying javascript...       Done

&lt;span class=&quot;c&quot;&gt;##################################################&lt;/span&gt;
Bootstrap successfully built at 06:17PM.
&lt;span class=&quot;c&quot;&gt;##################################################&lt;/span&gt;

Thanks &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;using Bootstrap,
&amp;lt;3 @mdo and @fat

real    0m2.480s
user    0m2.299s
sys     0m0.170s
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Run the same command immedately afterward, and you get the same thing.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;make build

&lt;span class=&quot;c&quot;&gt;##################################################&lt;/span&gt;
Building Bootstrap...
&lt;span class=&quot;c&quot;&gt;##################################################&lt;/span&gt;

Running JSHint on javascript...             Done
Compiling LESS with Recess...               Done
Compiling documentation...                  Done
Compiling and minifying javascript...       Done

&lt;span class=&quot;c&quot;&gt;##################################################&lt;/span&gt;
Bootstrap successfully built at 06:17PM.
&lt;span class=&quot;c&quot;&gt;##################################################&lt;/span&gt;

Thanks &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;using Bootstrap,
&amp;lt;3 @mdo and @fat

real    0m2.440s
user    0m2.271s
sys     0m0.172s
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Another 2.4 seconds down the drain even though no input sources were
changed.&lt;/p&gt;

&lt;p&gt;At this point I decided I didn't want to wait 2.4 seconds each time I
changed one line of html for my site and recompile to test it in my
browser. At first I modified my project's Makefile to deal with
Bootstrap's compilation dependencies &lt;a href=&quot;https://github.com/jazzychad/bridge-trainer/blob/311ed5f968b250818257460d53926e8cfeda5808/Makefile#L29&quot;&gt;as can be seen in this
commit&lt;/a&gt;,
but I thought it was a bit silly that I had to worry about that in
&lt;em&gt;my&lt;/em&gt; Makefile.&lt;/p&gt;

&lt;p&gt;So, I did what any insane person would do. I &lt;a href=&quot;https://github.com/jazzychad/bootstrap&quot;&gt;forked
Bootstrap&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is the updated Bootstrap Makefile using proper make target dependencies:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/bsmknew.png&quot; title=&quot;New Makefile&quot; alt=&quot;New Makefile&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/jazzychad/bootstrap/blob/60e1a55dae8aaf6f0fdebe9c9c8a9fb97fef6c43/Makefile#L81&quot;&gt;New Makefile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After running a &lt;code&gt;make clean&lt;/code&gt; to start from scratch, running &lt;code&gt;make
bootstrap&lt;/code&gt; again takes 2.x seconds to compile.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;make bootstrap

real   0m2.711s
user   0m2.552s
sys    0m0.168s
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;But now if you run it again, nothing needs to happen because nothing
changed! Voil&amp;agrave;!&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;make bootstrap
make: Nothing to be &lt;span class=&quot;k&quot;&gt;done for&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;bootstrap&lt;span class=&quot;err&quot;&gt;&amp;#39;&lt;/span&gt;.

real  0m0.032s
user  0m0.029s
sys   0m0.002s
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This allowed me to have a &lt;a href=&quot;https://github.com/jazzychad/bridge-trainer/blob/8e1bc37816f1d4592ee0efd2da124da03c408f2f/Makefile#L29&quot;&gt;much cleaner Makefile in my project's
repo&lt;/a&gt;
now that Bootstrap was worrying about itself.&lt;/p&gt;

&lt;p&gt;Now if I cd back to my repo's root, compiling the site from a fresh
start takes ~6 seconds while Bootstrap is compiled and BankersBox is
minified by Google's &lt;a href=&quot;http://closure-compiler.appspot.com/home&quot;&gt;closure
compiler&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;make site

real   0m6.111s
user   0m2.567s
sys    0m0.236s
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;However, after I make an edit to one of the repo's files (like my
playing card coffeescript) and recompile, it is lightning quick because
all of the Bootstrap and BankersBox dependencies are already
fulfilled.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;touch js/coffee/cards.coffee
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;make site

real   0m0.248s
user   0m0.217s
sys    0m0.030s
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Mission accomplished. If I do decide to customize the look of the site
by editing Bootstrap's .less files, my project's Makefile will
automatically trigger a Bootstrap rebuild (but only the css files!)
because of the build dependencies.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;make&lt;/code&gt; can be a very powerful tool. It was designed to save
developers' time by not repeating unnecessary compilation steps
between builds of large programs. Use it wisely in your projects, and
you just might save valuable seconds of your fellow developers' lives.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>The New Exec iPhone App</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/11/27/new-exec-iphone-app.html">http://blog.jazzychad.net/2012/11/27/new-exec-iphone-app.html</link>
    <updated>2012-11-27T00:00:00-08:00</updated>
    <id>http://blog.jazzychad.net/2012/11/27/new-exec-iphone-app.html</id>
    <guid>http://blog.jazzychad.net/2012/11/27/new-exec-iphone-app.html</guid>
    <content type="html">&lt;p&gt;Three months of intense work later, the new
&lt;a href=&quot;https://iamexec.com/&quot;&gt;Exec&lt;/a&gt; iPhone app is here! I did a full overview
of the development process on the &lt;a href=&quot;http://blog.iamexec.com/post/36088710407/how-we-built-the-new-exec-iphone-app&quot;&gt;Exec
blog&lt;/a&gt;. Hopefully
I will be able to do some deep-dive technical posts about actual
implementation of some of the custom UI classes at some point. In the
mean time, enjoy the new app!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://blog.iamexec.com/post/36088710407/how-we-built-the-new-exec-iphone-app&quot;&gt;Read the overview writeup here!&lt;/a&gt;&lt;/p&gt;



</content>
    </entry>
  
  <entry>
    <title>Dreaming of Space</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/10/19/dreaming-of-space.html">http://blog.jazzychad.net/2012/10/19/dreaming-of-space.html</link>
    <updated>2012-10-19T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/10/19/dreaming-of-space.html</id>
    <guid>http://blog.jazzychad.net/2012/10/19/dreaming-of-space.html</guid>
    <content type="html">&lt;p&gt;After reading the post &lt;a href=&quot;http://blog.alexmaccaw.com/small&quot;&gt;Small&lt;/a&gt; by
Alex MacCaw I was moved to recount a dream I had recently because the
experience was similar to that described in the post.&lt;/p&gt;




&lt;p&gt;Two nights ago while I slept, for the first time I had a dream about
going into space on the shuttle. I have wanted to go into space since
I was a child, so in my dream I was extremely excited about going into
space.&lt;/p&gt;

&lt;p&gt;I dreamt of the launch, the G-Forces, the adrenaline rush, and finally
the sky turning from blue to black as we escaped the atmosphere.&lt;/p&gt;

&lt;p&gt;Then the shuttle turned over so we could see the Earth. As the cockpit
window rotated and Earth came into view, the feeling of &lt;em&gt;sheer terror&lt;/em&gt;
washed over me as I saw how small the planet looked. I had a panic
attack in my dream from looking back down at Earth.&lt;/p&gt;

&lt;p&gt;I woke up a few minutes later as if from a nightmare. It was the
strangest experience, and the imagery and feelings are extremely vivid
in my memory. I wonder if humans have an innate emotional response to
this size perspective, but this seems somewhat related to the
&lt;a href=&quot;http://en.wikipedia.org/wiki/Overview_effect&quot;&gt;Overview Effect&lt;/a&gt;
described in the article.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>Adian for App.Net Update</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/10/12/adian-update.html">http://blog.jazzychad.net/2012/10/12/adian-update.html</link>
    <updated>2012-10-12T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/10/12/adian-update.html</id>
    <guid>http://blog.jazzychad.net/2012/10/12/adian-update.html</guid>
    <content type="html">&lt;p&gt;Apple just approved the v1.0.28 update of &lt;a href=&quot;http://get.adianapp.com/jcblog&quot;&gt;Adian for
App.Net&lt;/a&gt;! This update includes many
updates requested by users, but here are two updates which might be
nice for most people to know about.&lt;/p&gt;




&lt;h2&gt;Push Notifications for Netbot&lt;/h2&gt;

&lt;p&gt;Since Netbot does not have push notifications, Adian has added a
setting which will redirect its push notifications to open Netbot to
the specified post instead. You can set it from the Accounts page by
tapping on the blue arrow next to your username.&lt;/p&gt;

&lt;h2&gt;Temporary Price Drop&lt;/h2&gt;

&lt;p&gt;Adian is now US$1.99 for a limited time so new users can get in on the
fun and current Netbot users can grab a great utility app to add push
notifications without having to spend another giant sum of money
(slight sarcasm added). The price change is propagating through the
App Store, so keep checking if you don't see it.&lt;/p&gt;

&lt;h2&gt;Many Other Updates&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;iOS 6 support&lt;/li&gt;
&lt;li&gt;iPhone 5 screen support&lt;/li&gt;
&lt;li&gt;Reposts&lt;/li&gt;
&lt;li&gt;Stars&lt;/li&gt;
&lt;li&gt;User Search&lt;/li&gt;
&lt;li&gt;Hashtag Search&lt;/li&gt;
&lt;li&gt;Tons of bug fixes&lt;/li&gt;
&lt;li&gt;See more: &lt;a href=&quot;http://bugs.adianapp.com/&quot;&gt;Adian Bug Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Go Get It!&lt;/h2&gt;

&lt;p&gt;You can get &lt;a href=&quot;http://get.adianapp.com/jcblog&quot;&gt;Adian for App.Net&lt;/a&gt; on the
App Store now!&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>IFTTT Needs Webhooks, Stat</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/08/05/ifttt-needs-webhooks-stat.html">http://blog.jazzychad.net/2012/08/05/ifttt-needs-webhooks-stat.html</link>
    <updated>2012-08-05T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/08/05/ifttt-needs-webhooks-stat.html</id>
    <guid>http://blog.jazzychad.net/2012/08/05/ifttt-needs-webhooks-stat.html</guid>
    <content type="html">&lt;p&gt;If This Then That (&lt;a href=&quot;http://ifttt.com/&quot;&gt;IFTTT&lt;/a&gt; for short) is a cool web
service that lets users manipulate and react to events on different
websites by taking other actions in response.&lt;/p&gt;

&lt;p&gt;For example, I can tell IFTTT: &lt;strong&gt;IF&lt;/strong&gt; I post a new photo to
Instagram &lt;strong&gt;THEN&lt;/strong&gt; take that photo and store a copy in my Dropbox
folder.&lt;/p&gt;

&lt;p&gt;IFTTT currently has 50 channels (or services) that you can wire
together in similar fashion to create all sorts of interesting
combinations of events.&lt;/p&gt;

&lt;p&gt;However, one output channel is sorely missing: &lt;strong&gt;Webhooks.&lt;/strong&gt;&lt;/p&gt;




&lt;!--
The event driven web (or evented web) is all about telling interested
parties (users, servers, whoever) about events that happen inside of a
system by using a push mechanism instead of making the interested
parties poll for new data all the time.

Webhooks are the most open-ended way of getting this done by just
POSTing data to an endpoint to notify the user of new data. This POST
can either say &quot;Hey, there's new data you need to fetch,&quot; or it can
just include the data itself.
--&gt;


&lt;p&gt;Granted, webhooks are not for the general user. This is why IFTTT is
great, because it is trying to solve the webhook case for most
consumer needs.&lt;/p&gt;

&lt;p&gt;But, as a developer I want access to my event data so I can use it
however I please. In this way, webhooks would be the perfect solution
as an output channel for IFTTT.&lt;/p&gt;

&lt;p&gt;When IFTTT &lt;a href=&quot;http://blog.ifttt.com/post/25506427600/thenewifttt&quot;&gt;announced its
partnership&lt;/a&gt; with
&lt;a href=&quot;http://www.belkin.com/wemo/&quot;&gt;WeMo&lt;/a&gt; to do interesting things with
real-world hardware, I assumed IFTTT was headed in the direction of
helping to power the &lt;a href=&quot;http://en.wikipedia.org/wiki/Internet_of_Things&quot;&gt;Internet Of
Things&lt;/a&gt; and really
get it off the ground.&lt;/p&gt;

&lt;p&gt;Last night, I needed a way to be notified each time I posted a new
tweet. So, I went to IFTTT to setup a Twitter-to-webhook recipe and
found that I could not.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet tw-align-center&quot;
data-in-reply-to=&quot;232058622274834432&quot;&gt;&lt;p&gt;&lt;a
href=&quot;https://twitter.com/jazzychad&quot;&gt;&lt;s&gt;@&lt;/s&gt;&lt;b&gt;jazzychad&lt;/b&gt;&lt;/a&gt;
there's so much potential for it, it's definitely on our list for
development consideration.&lt;/p&gt;&amp;mdash; IFTTT (@IFTTT) &lt;a
href=&quot;https://twitter.com/IFTTT/status/232158548505808896&quot;
data-datetime=&quot;2012-08-05T16:58:05+00:00&quot;&gt;August 5,
2012&lt;/a&gt;&lt;/blockquote&gt;


&lt;script src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;


&lt;p&gt;Hmm, this says to me, &quot;Thanks, but it's not even on our todo list.&quot;&lt;/p&gt;

&lt;p&gt;That's unfortunate. &lt;strong&gt;IF&lt;/strong&gt; IFTTT wants to become a platform and become
the central hub for the evented web &lt;strong&gt;THEN&lt;/strong&gt; they need to make it as
appealing as possible for developers to love the system and start to
build cool things with it. Developers will be inspired to tell their
friends about it, and IFTTT will continue to gain traction in the
consumer space.&lt;/p&gt;

&lt;p&gt;Myabe I'm way off base. Maybe their consumer growth traction is fine
and they don't need to cater to the power-user/developer edge cases in
order to reach their goals.&lt;/p&gt;

&lt;p&gt;All I know is I want webhooks.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>Array Iteration Interview Problem</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/08/01/array-iteration-problem.html">http://blog.jazzychad.net/2012/08/01/array-iteration-problem.html</link>
    <updated>2012-08-01T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/08/01/array-iteration-problem.html</id>
    <guid>http://blog.jazzychad.net/2012/08/01/array-iteration-problem.html</guid>
    <content type="html">&lt;p&gt;Over the past year, I have interviewed several cadidates for
programming positions at tech startups. The following problem is a
variation of a question I have asked in each of those interviews.&lt;/p&gt;




&lt;p&gt;I say that the candidate can use any language they choose, and most
use ruby. I am not a rubyist. My background is in C and functional
languages like Lisp, so the answers I see in ruby are sometimes a
little bit strange to me.&lt;/p&gt;

&lt;p&gt;Maybe it's the Ruby Way, and I'm not used to it. So, dear internet, I
open the floor to you to show me your implementation of the following
problem statement.&lt;/p&gt;

&lt;p&gt;Implement the following function:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# add1 - increments items in an array matching specified value&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# param: arr - array of integers to manipulate&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# param: val - integer, value to increment&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# param: n   - integer, control value specifying behavior of manipulation&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   n == 0 means increment all occurrences of val&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   n &amp;gt; 0  means increment up to n occurrences of val&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#          from left-to-right (forward)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   n &amp;lt; 0  means increment up to n occurrences of val&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#          from right-to-left (backward)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# return: arr with proper values incremented&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Examples:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# add1 [1,4,1,5,1], 1, 0 -&amp;gt; [2,4,2,5,2]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# add1 [1,4,1,5,1], 1, 2 -&amp;gt; [2,4,2,5,1]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# add1 [1,4,1,5,1], 1, -2 -&amp;gt; [1,4,2,5,2]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Ok, have you done it? Right. Now here are some questions to consider
about your implementation:&lt;/p&gt;

&lt;p&gt;Are you manipulating the array in-place? If not, can you change it so
that it does (in which case I guess rubyists would say the function
name should be 'add1!')?&lt;/p&gt;

&lt;p&gt;Do you have 3 separate cases for handling the value of n (n == 0, n &gt;
0, n &amp;lt; 0)? Can you collapse it down to 2? How about only 1?&lt;/p&gt;

&lt;p&gt;Let's say that n is positive (&gt; 0) and the array has a billion
elements, but you've already incremented n values after the first 100
or so elements. Does your implementation continue to loop over the
whole array, or can it short-circuit and return early?&lt;/p&gt;

&lt;p&gt;Did you use array#reverse twice somewhere in your code? (Lots of
people do this, which is fascinating to me, to handle the negative n case)&lt;/p&gt;

&lt;p&gt;Are you using iterators like .each or .map, or are you using a
normal, index-based for loop?&lt;/p&gt;

&lt;p&gt;I find the wide variety of answers I get very interesting, but almost
all use a double reverse technique when handling negative n values
(reverse the array, use .each or similar, reverse array again before
returning it).&lt;/p&gt;

&lt;p&gt;To be clear, this is not a 'gotcha' question. I am not looking for a
particular answer which I consider correct. I care more about how the
candidate can explain the choices they made in their implementation
and how they communicate while they code. A working implementation
counts for a lot, of course, but I know there is more than one way to
skin a cat. Whether I consider their answer to be optimal or something
that I would use in production is another issue, but it is not
something that weighs much in my overall decision.&lt;/p&gt;

&lt;p&gt;My background is mainly in embedded systems programming. My main
concern when I code is for speed and efficiencey, both in runtime and
in memory consumption.&lt;/p&gt;

&lt;p&gt;Since this is the internet, and nothing is at stake, I pose the
following challenge: I want to see your most optimal implementation of
this problem. Mainly I want to see the array updated in-place and with
no wasted cycles while looping. I'm mostly curious to look at the ruby
answers.&lt;/p&gt;

&lt;p&gt;For reference, below is my implementation written in javascript (since
I have no idea how I would do this similarly in ruby), just so you can
see how my mind thinks about this type of problem.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;c&quot;&gt;/*&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; * add1 - increments items in an array matching specified value&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; * param: arr - array of integers to manipulate&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; * param: val - integer, value to increment&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; * param: n   - integer, control value specifying behavior of&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *              manipulation&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *   n == 0 means increment all occurrences of val&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *   n &amp;gt; 0  means increment up to n occurrences of val&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *          from left-to-right (forward)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *   n &amp;lt; 0  means increment up to n occurrences of val&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *          from right-to-left (backward)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; *&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; * return: arr with proper values incremented&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt; */&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;add1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&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;n&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;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&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;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&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;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;start&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;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;stop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&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;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&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;c&quot;&gt;// n &amp;lt; 0&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&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;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;stop&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;step&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;mi&quot;&gt;1&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;count&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;o&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;step&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;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;val&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;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&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;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&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;break&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;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;o&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;p&gt;By the way, we are &lt;a href=&quot;https://iamexec.com/hiring&quot;&gt;hiring at Exec&lt;/a&gt;, so
you should come join us!&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>Startups, Fix Your Blog Links</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/05/28/startups-fix-your-blog-links.html">http://blog.jazzychad.net/2012/05/28/startups-fix-your-blog-links.html</link>
    <updated>2012-05-28T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/05/28/startups-fix-your-blog-links.html</id>
    <guid>http://blog.jazzychad.net/2012/05/28/startups-fix-your-blog-links.html</guid>
    <content type="html">&lt;p&gt;In this next installment of my &quot;&lt;a href=&quot;http://blog.jazzychad.net/2012/03/24/startups-fix-your-from-field.html&quot;&gt;Startups, fix your
X&lt;/a&gt;&quot;
series, I present another issue that has irked me for some time, but I
have finally been bothered to write it down.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Dear Startups,&lt;/strong&gt; &lt;br/&gt;
&lt;strong&gt;Please add a link to your main homepage from your blog's navigation links.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There, was that so hard? It seems so simple, yet so many companies
leave their readers stranded on their blog &lt;strong&gt;with no way to figure out
what the company actually does&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example of &lt;a href=&quot;http://blog.flattr.net&quot;&gt;Flattr's Blog&lt;/a&gt;, which I
was linked to from Hacker News:&lt;/p&gt;

&lt;center&gt; &lt;img src=&quot;/images/flattrblog.png&quot; width=&quot;500&quot; border=&quot;0&quot; /&gt;
&lt;/center&gt;


&lt;p&gt;I'm not just picking on Flattr, they are just the last in a long line
of blogs that have done this.&lt;/p&gt;

&lt;p&gt;What is flattr? I guess I should go to their homepage. Clicking on the
giant &quot;FlattrBlog&quot; logo leads me to blog.flattr.net. Ok, well, that
makes sense. So I guess I'll click &quot;Home,&quot; and that should lead me to
the homepage. Nope, just another link to blog.flattr.net. &lt;strong&gt;There is
not one link in the header of Flattr's blog that takes me to their
homepage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'm a reasonable person, I could very well deduce that the homepage is
at flattr.net, but I'm lazy and just want to click my way there, not
spend the time manually editing the URL in the address bar. I'm sure
most people are the same way.&lt;/p&gt;

&lt;p&gt;Your company's blog is usually your main PR outlet. It's how you get
links spread across the web. Articles you write are how you get linked
on news sites, Facebook, Twitter, etc. Once users are on your blog,
they are one short click away from learning more about your company or
product. How could you possibly waste that opportunity by not adding a
simple link?&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>Fixing Obfuscated Emails in Gmail with Dotjs</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/05/25/gmail-dotjs-obfuscated-emails.html">http://blog.jazzychad.net/2012/05/25/gmail-dotjs-obfuscated-emails.html</link>
    <updated>2012-05-25T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/05/25/gmail-dotjs-obfuscated-emails.html</id>
    <guid>http://blog.jazzychad.net/2012/05/25/gmail-dotjs-obfuscated-emails.html</guid>
    <content type="html">&lt;p&gt;Even though moderm email spam filters have become sufficiently good at
protecting our inboxes, people (including myself) still feel the need
to obfuscate their email addresses when listing them on public
websites so spam scrapers don't get their address. Seems reasonable.&lt;/p&gt;




&lt;p&gt;However, when I want to email someone who has done such obfuscation, I
need to copy their address, paste it into Gmail and then manually
correct the obfuscated parts so that Gmail will recognize the email
format.&lt;/p&gt;

&lt;p&gt;This became tiresome. I wondered why Gmail couldn't be smart enough to
recognize some of the common patterns and just auto-correct it
automatically.&lt;/p&gt;

&lt;p&gt;Then the thought occurred to me: maybe I could write a custom dotjs
file to do this for me. If you don't know about dotjs files, you should
check it out at
&lt;a href=&quot;https://github.com/defunkt/dotjs&quot;&gt;https://github.com/defunkt/dotjs&lt;/a&gt;. Basically
it is a Chrome extension that acts as a better version of Greasemonkey
scripts that can customize any webpage.&lt;/p&gt;

&lt;p&gt;The script itself is pretty simple:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&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;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;// automatically fix obfuscated email addresses pasted into&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;// to/cc/bcc fields                                                                                                                                                              &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;s2&quot;&gt;&amp;quot;textarea[name=to], textarea[name=cc], textarea[name=bcc]&amp;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;live&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;blur&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&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;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;text&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;val&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;o&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;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot; at &amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;@&amp;quot;&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;o&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;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;_at_&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;@&amp;quot;&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;o&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;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;[at]&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;@&amp;quot;&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;o&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;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot; dot &amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&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;o&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;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;_dot_&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&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;o&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;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;[dot]&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&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;o&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;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot; daught &amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&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;o&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;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;_daught_&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&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;o&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;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;[daught]&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&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;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;It can also be found in my .js repo on github:
&lt;a href=&quot;https://github.com/jazzychad/.js/blob/master/mail.google.com.js&quot;&gt;https://github.com/jazzychad/.js/blob/master/mail.google.com.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you paste in an obfuscated address, the script will automatically
look for common patterns and replace them with the appropriate
characters when you tab or click to the next field. So, pasting in
emails like this:&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/images/gmail_to_before.png&quot; border=&quot;0&quot;&gt;
&lt;/center&gt;


&lt;p&gt;...become this:&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/images/gmail_to_after.png&quot; border=&quot;0&quot;&gt;
&lt;/center&gt;


&lt;p&gt;Piece of cake!&lt;/p&gt;

&lt;!--&lt;a
href='javascript:window.location=&quot;http://news.ycombinator.com/submitlink?u=&quot;+encodeURIComponent(document.location)+&quot;&amp;t=&quot;+encodeURIComponent(document.title)'&gt;Submit
to Hacker News&lt;/a&gt;--&gt;

</content>
    </entry>
  
  <entry>
    <title>Startups, Fix Your "From" Field</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/03/24/startups-fix-your-from-field.html">http://blog.jazzychad.net/2012/03/24/startups-fix-your-from-field.html</link>
    <updated>2012-03-24T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/03/24/startups-fix-your-from-field.html</id>
    <guid>http://blog.jazzychad.net/2012/03/24/startups-fix-your-from-field.html</guid>
    <content type="html">&lt;p&gt;A short rant. I have seen this problem happen too many times to stay
quiet anymore. I have reached out in private when this happens, but
I'm going to write a public rant so I can stop repeating myself.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Dear Startups,&lt;/strong&gt; &lt;br/&gt;
&lt;strong&gt; Put your company's name in the From field of your notification emails.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There, was that so hard? It seems so simple, yet so many companies
fire off bacn email without letting me know who they are in the From
or Subject lines, &lt;strong&gt;and it just looks like spam&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example from a new startup whose website I joined
yesterday:&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/images/notifemail.png&quot; /&gt;
&lt;/center&gt;


&lt;p&gt;I have no idea what these emails are about or where they came from. Do
you?&lt;/p&gt;

&lt;p&gt;Here is the fix. Format your From address like so:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&quot;Company Name&quot; &amp;lt;notification@company.com&amp;gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This will show &lt;strong&gt;Company Name&lt;/strong&gt; in the From section of GMail, Outlook,
and literally every other email inbox service. Then I know why I got
your email at a glance without having to open it and be mad at you.&lt;/p&gt;

&lt;p&gt;If you just use &lt;strong&gt;notification@company.com&lt;/strong&gt;, most inboxes will either
show the part before the @ symbol (like GMail), or if you are lucky it
will show the entire email address, but now you are forcing the user
to parse the email address for your domain name. Blech.&lt;/p&gt;

&lt;p&gt;There is a corollary to this rant:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you use a person's name as the From address to make your company
  look more personable, then put your company name in the Subject line
  somewhere.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have seen several companies send out newsletters using a person's
name as the sender (founder, head of marketing, etc), but the Subject
line is meaningless without more context if I don't recognize your
name as being associated with a company I know.&lt;/p&gt;

&lt;p&gt;Just sneak it in somewhere. Any of these will do:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[Company Name] Check out our new features!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hi from Company! How do you like us so far?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your order from Company has shipped!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Please fix this. Please let me know who you are while I skim my inbox
so that I don't glance over it, or worse, hit the delete or spam
button without reading it.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>Behind the Scenes: Launching ExportMyPosts.com in 4 Days</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/03/21/launching-exportmyposts-in-four-days.html">http://blog.jazzychad.net/2012/03/21/launching-exportmyposts-in-four-days.html</link>
    <updated>2012-03-21T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/03/21/launching-exportmyposts-in-four-days.html</id>
    <guid>http://blog.jazzychad.net/2012/03/21/launching-exportmyposts-in-four-days.html</guid>
    <content type="html">&lt;p&gt;In the time between finishing at Twilio and starting at Exec, I had
four days off. A few days prior, &lt;a href=&quot;http://blog.posterous.com/big-news&quot;&gt;Posterous had been acquired by
Twitter&lt;/a&gt;. This gave me an idea,
and it was one I knew I could build in those four days. This post will
explore how I built and launched
&lt;a href=&quot;http://exportmyposts.com/&quot;&gt;ExportMyPosts.com&lt;/a&gt; in those four days, and
what building-blocks I used to get there.&lt;/p&gt;




&lt;h1&gt;The Idea&lt;/h1&gt;

&lt;p&gt;On March 12, Posterous was acquired. This was great news for Posterous
and Twitter, but many users were left wondering about what would
happen to their blogs and their data. Posterous' response at the time
was very vague (their response since then has cleared a little bit).&lt;/p&gt;

&lt;p&gt;Their main response at the time was, &quot;If you want to export your
data, you can use our API for that.&quot; This is true, of course. It is
possible to get one's data out that way, but most users wouldn't even
know where to begin with that recommendation.&lt;/p&gt;

&lt;p&gt;However, I was familiar with Posterous' API from previous projects, so
I knew what would need to be done in order to extract all the
information and files you would want out of your blog. I thought it
would be neat to build a tool that could be used by anyone to export
their blog in the simplest way possible: the click of a button.&lt;/p&gt;

&lt;h1&gt;The &quot;New Thing&quot;&lt;/h1&gt;

&lt;p&gt;I have a rule for every personal side-project that I build. There must
be at least one &quot;new thing&quot; I have to learn that I have never done
before in other projects. I have had this rule for years. After dozens
of personal projects under my belt, I now have an entire arsenal of
skills to use on future projects. I recommend this rule to
everyone. This is how you can become &lt;a href=&quot;http://jacquesmattheij.com/The+Starter+the+Architect+the+Debugger+and+the+Finisher&quot;&gt;The Starter, The Architect, The
Debugger and The
Finisher&lt;/a&gt;
all in one person and accomplish things very quickly (though I am more
of a Starter than the other three).&lt;/p&gt;

&lt;p&gt;There were a few &quot;new things&quot; in this project, but main one was &lt;a href=&quot;https://stripe.com/&quot;&gt;using
Stripe to take payments&lt;/a&gt; on the website.&lt;/p&gt;

&lt;p&gt;I have used PayPal before and taken credit card payments with a Merchant and
Gateway account for a previous business, but I had yet to play with
Stripe to really see how easy it was. That was the &quot;new thing&quot; this
time.&lt;/p&gt;

&lt;h1&gt;Building Blocks&lt;/h1&gt;

&lt;p&gt;Here is a list of the pieces I put together to assemble the site:&lt;/p&gt;

&lt;h2&gt;Servers&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://www.rackspace.com/cloud/&quot;&gt;Rackspace Cloud&lt;/a&gt; virtual servers
running Linux. I use Apache2 as my web server, PHP as my language, and
Redis as my datastore.&lt;/p&gt;

&lt;p&gt;Dev setup: One 512mb slice which runs a web server, the export worker
and email daemons, and the redis db.&lt;/p&gt;

&lt;p&gt;Production setup: One 512mb slice to run the web server. One 512mb
slice to run the redis db. One or more (depending on load) 256mb
slices to run the export worker and email daemons.&lt;/p&gt;

&lt;h2&gt;PHP on CodeIgniter 2.x&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://twenty-somethingtravel.com/wp-content/uploads/2010/08/haters_gonna_hate.gif&quot;&gt;Haters gonna
hate&lt;/a&gt;,
but I love PHP. I learned it in 2002, and I know it backward and
forward. I know how to configure it with Apache to get maximum
performance without even thinking about it anymore. This means I can
write PHP code very fast. Believe it or not, it is actually possible
to write &lt;em&gt;good&lt;/em&gt; PHP code.&lt;/p&gt;

&lt;p&gt;A couple years ago I came across
&lt;a href=&quot;http://codeigniter.com/&quot;&gt;CodeIgniter&lt;/a&gt;, which is a pretty nice MVC
framework for PHP web apps. The community is a little devided on some
issues, but the code is nice and makes creating websites quick.&lt;/p&gt;

&lt;h2&gt;Redis&lt;/h2&gt;

&lt;p&gt;I love Redis. You love Redis. We all love Redis. Here's why:&lt;/p&gt;

&lt;p&gt;Having a schema-less datastore meant that I could iteratively tweak
and adjust my models without having to worry about updating schemas or
tables or rows or anything. Do I need to store another attribute about
this user? Great, just set another key and I'm done. Everything I need
to know about users, blogs, payments, promo codes, and jobs can be
expressed as key-value pairs, lists, and sets.&lt;/p&gt;

&lt;p&gt;(Let's not start a war about NoSQL vs RDBMS, ok? I still love SQL,
too. There is a time and place for everything. Use the right tool for
the job, and all that.)&lt;/p&gt;

&lt;p&gt;However, there is another awesome power that Redis had for me in this
project: queues. &lt;a href=&quot;http://twitter.com/antirez&quot;&gt;Antirez&lt;/a&gt; published a post about &lt;a href=&quot;http://antirez.com/post/250&quot;&gt;Redis reliable
queues&lt;/a&gt; in the middle of this project, so
I took a few pointers and tweaked my queue implementation.&lt;/p&gt;

&lt;p&gt;Because the lpush and rpop commands are atomic, it meant that I could
use a Redis list as a distributed queue to dispatch export jobs to
worker daemons. In addition, because of the atomic incr and decr
commands, I could use a Redis key as a locking mechanism between
worker processes to serialize API requests to Posterous so I would
play nice with their rate-limits.&lt;/p&gt;

&lt;h2&gt;Email&lt;/h2&gt;

&lt;p&gt;At first I hadn't even thought about adding email to the site. It's
not something that most projects need. Then I thought how strange it
would be for users to click &quot;Export&quot; and have to wait around while
their blog was queued for processing. How would they know it was done?
So, it became clear I would need some notification mechanism: email.&lt;/p&gt;

&lt;p&gt;I have configured and stood up more Postfix servers than I care to
remember. That was once a &quot;new thing&quot; that I learned, but after
dealing with it again and again, I have finally taken down the &quot;Get
Off My Lawn&quot; sign and decided to go with a shiny web 2.0 Email API
service from here on out.&lt;/p&gt;

&lt;p&gt;My personal favorite service is &lt;a href=&quot;http://mailgun.net/&quot;&gt;Mailgun&lt;/a&gt;. There
are many similar services out there, but Mailgun happens to work
really well for my use-cases, and likewise for this project. I had to
write a simple PHP wrapper for their API, but it still took about 10
minutes to start delivering email to my inbox from the app.&lt;/p&gt;

&lt;h2&gt;Stripe for Payments&lt;/h2&gt;

&lt;p&gt;I have dealt with web-based payments before. PayPal is nice, but they
are becoming increasingly scary. I have had online Merchant and
Gateway accounts. Those are a giant mess and rife with fees and shady
practices. I consider that whole world to be the seedy underbelly of
the internet.&lt;/p&gt;

&lt;p&gt;After hearing much praise about Stripe (not to mention knowing the
founders through many YC connections and events), I decided to give
them a spin to see if they lived up to the hype.&lt;/p&gt;

&lt;p&gt;The short answer is: yes. The long answer is: yes, but it still takes
lots of effort to properly integrate payments into a website. Much of
the logic and implementation is application specific, and no company
can fully remove that pain. Stripe certainly eases the pain (a lot),
but the greatest thing they provide is a one-stop service. They act as
both the Merchant and Gateway accounts. In fact, you don't even have
to know what those mean to use Stripe. All you have to know is,
&quot;people pay with their credit card on my site, money lands in my bank
account.&quot; What normally takes three separate services is rolled up
into one.&lt;/p&gt;

&lt;p&gt;The second greatest thing is that there are no monthly fees. I only
pay Stripe when I am paid. So, if I go a whole year without making a
sale, I am out nothing. I don't know of any other payment systems with
that deal.&lt;/p&gt;

&lt;p&gt;Anyway, I don't want this post to turn into a Stripe ad, but it was
the &quot;new thing,&quot; so I paid special attention to it.&lt;/p&gt;

&lt;h2&gt;Worker Daemons&lt;/h2&gt;

&lt;p&gt;I have two types of worker daemons (again, written in PHP) that run in
the background: an email daemon and an export daemon. The email daemon
is just a simple loop that pulls email jobs off another Redis queue
and sends them through Mailgun.&lt;/p&gt;

&lt;p&gt;The export daemon does the heavy lifting for the whole project. It is
responsible for communicating with the Posterous API to extract blog
data and download associated media files (images, videos, audio,
etc). Then it zips them all up into one file and uploads it to
S3. Then a link is sent to the user to let them know their blog is
ready for download.&lt;/p&gt;

&lt;p&gt;I designed the export worker to be scalable, so that more can be run
at the same time if there are many pending jobs. The only tricky part
was to serialize the Posterous API requests betwen the workers because
the API has a very strict requests per hour limit with second
granulatiry. As I mentioned before, I just use a Redis key as a mutex
to make sure that only one worker is making a request at any one time
and sleeps a bit before giving up the lock.&lt;/p&gt;

&lt;h2&gt;Bootstrap and Bootswatch&lt;/h2&gt;

&lt;p&gt;Twitter's &lt;a href=&quot;http://twitter.github.com/bootstrap/&quot;&gt;Bootstrap&lt;/a&gt; seems to
be popping up everywhere now, but for good reason. It is a great
frontend framework for non-designers (like me) to make a decent
looking website without having to worry too much. I don't begrudge
anyone using Bootstrap, but I don't like seeing the same default theme
everywhere. Thankfully, there are sites like
&lt;a href=&quot;http://bootswatch.com/&quot;&gt;Bootswatch&lt;/a&gt; which provide some different
themes and ability to customize your Bootstrap look and feel. I also
added a textured background image from &lt;a href=&quot;http://subtlepatterns.com/&quot;&gt;Subtle
Patterns&lt;/a&gt; to give the site some extra
depth.&lt;/p&gt;

&lt;h1&gt;The Four Days&lt;/h1&gt;

&lt;h2&gt;Thursday&lt;/h2&gt;

&lt;p&gt;I started work on the site. First I wrote the worker daemon to see if
it was even possible to export the blog data the way I wanted to. This
was also the first day of the NCAA Basketball Tournament, and I also
run my own &lt;a href=&quot;http://brackets.jazzychad.net/&quot;&gt;Bracket Challenge&lt;/a&gt;. So I
wrote code, setup the dev server, and watched basketball.&lt;/p&gt;

&lt;p&gt;Mostly I watched basketball.&lt;/p&gt;

&lt;h2&gt;Friday&lt;/h2&gt;

&lt;p&gt;More basketball.&lt;/p&gt;

&lt;p&gt;Started work on the website frontend. Played around with Bootstrap and
Bootswatch until I found a theme and design I liked. Then I added
enough code to be able to login via Posterous and export a blog with
the website as a GUI instead of running the worker from the command
line. At this point I integrated Mailgun emails so users would get an
email when their blog was queued, started exporting, and finished
exporting. I had a couple friends test exporting their blogs to make
sure the system was working as expected.&lt;/p&gt;

&lt;h2&gt;Saturday&lt;/h2&gt;

&lt;p&gt;More basketball.&lt;/p&gt;

&lt;p&gt;Payment integration day. If I didn't want to take payments for this
site, it would have been mostly done by now. Adding payments to a
website means inserting payment-related logic to lots of things in the
app. Is the user allowed to do this action? Have they paid for it?
Have they paid for one of these items, but not two? What items do I
display to the user based on what they have or have not already
purchased? Make sure a user can &quot;purchase&quot; the same item again, but
this time don't charge them for it. Etc, etc... All of these issues
are answered with code that isn't even related to integrating with
your payment service!&lt;/p&gt;

&lt;p&gt;Integrating with Stripe was fairly straightforward. Their test mode is
amazing, so you can try out every conceivable user interaction flow
and see how their system will respond before flipping to production.&lt;/p&gt;

&lt;h2&gt;Sunday&lt;/h2&gt;

&lt;p&gt;More basketball and a Dim Sum lunch with the Exec team.&lt;/p&gt;

&lt;p&gt;More payment integration coding. Once I was satisfied that I had all
my bases covered, I went about thoroughly testing the system. I nuked
the database and started from scratch to make sure that nothing was
dependent on data I had manually manipulated in the database. I added
a Promo Code system so that I could give away some free exports at
launch. I spun up my production servers and configured them depending
on which role they played. I added Terms of Service and a Privacy
Policy. Everything was go for launch.&lt;/p&gt;

&lt;h1&gt;The Launch&lt;/h1&gt;

&lt;p&gt;On Monday, I rested. Well, I rested from the project, but it was also
my first day at Exec, so there wasn't much rest at all!&lt;/p&gt;

&lt;p&gt;I have learned to wait an extra day between &quot;finishing&quot; a project and
launching it. There are always one or two things you think of that
need fixing, and you'll be thankful you waited. And so it was with
this site. Monday night I came home and tweaked a few things, ready to
go on Tuesday morning.&lt;/p&gt;

&lt;p&gt;Tuesday (yesterday) morning I hit the &lt;a href=&quot;http://inception.davepedu.com/&quot;&gt;Big Red Launch
Button&lt;/a&gt; by sending out a few tweets,
posting to &lt;a href=&quot;http://news.ycombinator.com/item?id=3730092&quot;&gt;Hacker News&lt;/a&gt;,
and emailing a story to TechCrunch and Mashable.&lt;/p&gt;

&lt;h1&gt;Some Stats&lt;/h1&gt;

&lt;p&gt;The initial response has been ok but not overwhelming. The HN post
only garnered a meer 34 points. I was expecting a bigger reaction
there since the original &lt;a href=&quot;http://news.ycombinator.com/item?id=3695407&quot;&gt;Posterous acquisition
thread&lt;/a&gt; got close to 600
points.&lt;/p&gt;

&lt;p&gt;After the first day, only 27 people logged into the site out of ~1500
visits.&lt;/p&gt;

&lt;p&gt;Four people actually bought export packages (all within the first hour
of launch), for a grand total of $39.00 in revenue so far. One of
those purchases came from someone who bought an upgrade after using one
of the promo codes, and that made me happy.&lt;/p&gt;

&lt;p&gt;I gave out a Promo Code on HN good for the first 25 people to use
it. So far, only 14 have claimed it. Same story with a promo code I
gave on Twitter several times. Only 3 of 10 claimed. It's somewhat
frustrating to think that I can't even give this service away.&lt;/p&gt;

&lt;h1&gt;The Future?&lt;/h1&gt;

&lt;p&gt;I'm not sure if this project has legs, but it was very fun to build,
and I have very positive feedback from the people that have used it. I
think it would be a valuable service even if Posterous wasn't
acquired. Being able to export your own data has value.&lt;/p&gt;

&lt;p&gt;I could see it expanding to interface with other services that hold
users' data (blogs, photos, etc).&lt;/p&gt;

&lt;p&gt;As always, building is the easy part, marketing and finding users who
actually want your product is the tricky bit.&lt;/p&gt;

&lt;p&gt;&lt;a
href=&quot;javascript:window.location=%22http://news.ycombinator.com/submitlink?u=%22+encodeURIComponent(document.location)+%22&amp;t=%22+encodeURIComponent(document.title)&quot;&gt;Submit
to Hacker News&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>Joining Exec</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/03/16/joining-exec.html">http://blog.jazzychad.net/2012/03/16/joining-exec.html</link>
    <updated>2012-03-16T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/03/16/joining-exec.html</id>
    <guid>http://blog.jazzychad.net/2012/03/16/joining-exec.html</guid>
    <content type="html">&lt;p&gt;Once in a while, an opportunity comes along that you can't refuse. Two
weeks ago, one such opportunity came knocking. After careful thought
and deliberation, I am excited to announce...&lt;/p&gt;

&lt;p&gt;I am joining &lt;a href=&quot;https://iamexec.com/&quot;&gt;Exec&lt;/a&gt;!&lt;/p&gt;




&lt;center&gt;
&lt;img src=&quot;/images/exec_logo.png&quot; width=&quot;400&quot;&gt;
&lt;/center&gt;


&lt;p&gt;Exec is a great service that will let you outsource tasks or errands
that you might not have time for or want to do. You can check out more
info on the &lt;a href=&quot;https://iamexec.com/&quot;&gt;Exec homepage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Exec just launched &lt;a href=&quot;http://www.forbes.com/sites/tomiogeron/2012/02/29/justin-kan-launches-exec-for-real-time-mobile-jobs/&quot;&gt;a few weeks
ago&lt;/a&gt;,
and is still very young. I will be joining as the 5th member of the
team along side Justin, Daniel, Amir, and Matt. My first day is next
Monday, March 19th.&lt;/p&gt;

&lt;p&gt;I love the atmosphere of early-stage startups, and I love wearing lots
of hats to get the job done. Exec combines several areas that I am
very passionate about (real-time communication, scheduling algorithms
and logistics, mobile development, and solving hard problems), so it
feels like a natural fit. I will be mainly foucsed on developing the
mobile apps, but I'm sure that's not all I'll be doing.&lt;/p&gt;

&lt;p&gt;I have known Justin Kan from interacting with him at various Y
Combinator events and even interviewing at Justin.tv last August. He
reached out to me about the opportunity and vision of Exec, and I was
sold.&lt;/p&gt;

&lt;p&gt;I am very excited about working with Justin and team to move the
vision of Exec forward. I am also very excited about getting back into
the fray of the crazy days of an early-stage startup. I can't wait to
get started.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>Create Your Own Posterous with Jekyll, PHP, Mailgun, and S3</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/03/12/create-your-own-posterous.html">http://blog.jazzychad.net/2012/03/12/create-your-own-posterous.html</link>
    <updated>2012-03-12T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2012/03/12/create-your-own-posterous.html</id>
    <guid>http://blog.jazzychad.net/2012/03/12/create-your-own-posterous.html</guid>
    <content type="html">&lt;p&gt;A few weeks ago, I decided to create an email-powered blog that is
hosted in an Amazon s3 bucket as a website. I wanted to be able to
email new posts to the blog and have them published automatically. I
use the email subject line as the title of the post and the email
body as the text of the post (written in markdown).&lt;/p&gt;




&lt;p&gt;This blog (the one you're reading right now) is powered by jekyll and
hosted on s3, so I decided to reuse most of that setup and add some
extra glue to handle posts by email. It does require an extra server
to be running on the open internet (to handle incoming mail webhooks
and publish new content to s3), but it can be a small, cheap 256MB
slice since it does not have to handle any blog traffic (s3 takes care
of that).&lt;/p&gt;

&lt;p&gt;The result is
&lt;a href=&quot;http://mailblog.jazzychad.net&quot;&gt;http://mailblog.jazzychad.net&lt;/a&gt;. I am
hoping to use it when I want to quickly publish small posts or passing
thoughts.&lt;/p&gt;

&lt;h2&gt;Overview&lt;/h2&gt;

&lt;p&gt;Email is sent to a special address handled by
&lt;a href=&quot;http://mailgun.net&quot;&gt;Mailgun&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mailgun posts the email data to a webhook on my mailblog
server. PHP/Apache is running on the server to handle the incoming
data.&lt;/p&gt;

&lt;p&gt;The PHP script formats the email data into a new post markdown file,
writes it into my jekyll _posts folder, and calls a do_blog.sh script.&lt;/p&gt;

&lt;p&gt;The do_blog.sh script causes jekyll to compile the blog and then sync
the files to my s3 bucket.&lt;/p&gt;

&lt;h2&gt;DIY&lt;/h2&gt;

&lt;p&gt;The whole process took about 3 hours to complete. Most of that time
was spent struggling with RVM because ruby and multi-user rvm are
nuts. I managed to distill the commands down to the magic incantation
in this post.&lt;/p&gt;

&lt;p&gt;All of the commands required to reproduce this setup are listed
step-by-step below. I tested them in a brand new server instance, so
it should work as advertised. If not, please let me know so we can debug.&lt;/p&gt;

&lt;h2&gt;Initial Setup&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; These setup instructions are specific for setting up a
server on the &lt;a href=&quot;http://www.rackspace.com/cloud/&quot;&gt;Rackspace Cloud&lt;/a&gt;. I
used a 256MB RAM instance of Ubuntu 10.04 LTS.&lt;/p&gt;

&lt;p&gt;On Rackspace, when you create a new instance, you are given a root
account and password. This works differently on other cloud hosting
services, so your initial setup steps may be different if you use a
different provider. The goal is just to create a user account for
yourself and give yourself sudo privileges.&lt;/p&gt;

&lt;p&gt;Boot up a new server, login as root, change your password, update
the system, then reboot.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# initial root login&lt;/span&gt;
   passwd
   apt-get update
   apt-get upgrade
   &lt;span class=&quot;c&quot;&gt;# reboot&lt;/span&gt;
   shutdown -r now
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Log back in as root, add new user ('chad' in this example), and add to
sudoers file.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;   adduser chad
   apt-get install emacs22 -y
   chmod u+w /etc/sudoers
   &lt;span class=&quot;c&quot;&gt;# edit file to add new user&lt;/span&gt;
   emacs -nw /etc/suoders
   &lt;span class=&quot;c&quot;&gt;# return permissions&lt;/span&gt;
   chmod u-w /etc/sudoers
   &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Install required packages&lt;/h2&gt;

&lt;p&gt;Login as new user and install these packages.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# install stuff&lt;/span&gt;
   sudo apt-get install git-core -y
   sudo apt-get install s3cmd -y
   sudo apt-get install php5 -y
   sudo apt-get install php5-cli -y
   sudo apt-get install build-essential -y
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Install RVM and gems&lt;/h2&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#install rvm and gems&lt;/span&gt;
   curl -s -o rvm-installer https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer
   chmod u+x rvm-installer
   &lt;span class=&quot;c&quot;&gt;# install globally as sudo. VERY IMPORTANT&lt;/span&gt;
   sudo ./rvm-installer stable
   &lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; /usr/local/rvm/scripts/rvm
   sudo usermod -a -G rvm chad
   newgrp - rvm &lt;span class=&quot;c&quot;&gt;# the - is VERY important&lt;/span&gt;
   rvm pkg install zlib
   rvm install 1.9.2
   rvm use 1.9.2
   gem install compass --no-ri --no-rdoc
   gem install liquid --no-ri --no-rdoc
   gem install maruku --no-ri --no-rdoc
   gem install rdiscount --no-ri --no-rdoc
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Additional Steps&lt;/h2&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# let www-data use rvm&lt;/span&gt;
   sudo usermod -a -G rvm www-data

&lt;span class=&quot;c&quot;&gt;# /var/www/ writeable&lt;/span&gt;
   sudo chmod o+w /var/www
   sudo /etc/init.d/apache2 restart

&lt;span class=&quot;c&quot;&gt;# configure s3cmd&lt;/span&gt;
   &lt;span class=&quot;c&quot;&gt;# make sure to have aws access keys setup at:&lt;/span&gt;
   &lt;span class=&quot;c&quot;&gt;# https://aws-portal.amazon.com/gp/aws/securityCredentials&lt;/span&gt;
   s3cmd --configure
   mv .s3cfg .s3cfg_mailblog
   chmod g+r .s3cfg_mailblog

&lt;span class=&quot;c&quot;&gt;# install blog template, mailblog-files, and jekyll&lt;/span&gt;
   git clone git://github.com/jazzychad/mailblog.git blog
   chmod g+w blog
   chmod g+w blog/_posts
   mkdir -p scripts/ruby/gems
   &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;scripts/ruby/gems
   git clone git://github.com/jazzychad/jekyll.git jc-jekyll
   &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~
   git clone git://github.com/jazzychad/mailblog-files.git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Configure you S3 Bucket&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href=&quot;https://console.aws.amazon.com/s3/home&quot;&gt;https://console.aws.amazon.com/s3/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Create a bucket named exactly like desired url domain (e.g. mailblog.example.com)&lt;/li&gt;
&lt;li&gt;Click on your bucket&lt;/li&gt;
&lt;li&gt;Click on Properties button&lt;/li&gt;
&lt;li&gt;Click on Website tab&lt;/li&gt;
&lt;li&gt;Check Enabled&lt;/li&gt;
&lt;li&gt;Set Index Document: index.html&lt;/li&gt;
&lt;li&gt;Set Error Document: 404.html&lt;/li&gt;
&lt;li&gt;Click Permissions tab&lt;/li&gt;
&lt;li&gt;Click Add Bucket Policy&lt;/li&gt;
&lt;li&gt;Paste in bucket policy from mailblog-files/bucket_policy.txt,&lt;/li&gt;
&lt;li&gt;Insert proper bucket name in policy&lt;/li&gt;
&lt;li&gt;Update your domain's DNS to add CNAME to point to bucket domain&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Configure and Customize Your Blog&lt;/h2&gt;

&lt;p&gt;You will want to replace all references to 'example.com' and system
paths which have 'chad' in them. You can also customize the sass and
layout files to style your blog however you like.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# configure and customize blog directory&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/blog
   grep -rHn &lt;span class=&quot;s2&quot;&gt;&amp;quot;example\.com&amp;quot;&lt;/span&gt; .
   grep -rHn &lt;span class=&quot;s2&quot;&gt;&amp;quot;chad&amp;quot;&lt;/span&gt; .
   &lt;span class=&quot;c&quot;&gt;# edit files to customize blog, update paths in Rakefile, etc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Setup do_blog.sh and Test&lt;/h2&gt;

&lt;p&gt;The do_blog.sh script will be called by your incoming mail webhook
(this is why we added www-data to the rvm group). Place it in your
home directory. You can test that everything is working so far by
running it. This will publish your blog to your s3 bucket. If
everything was setup correctly, you should be able to go view it at
your mailblog domain (if the DNS has updated already) or the full s3
bucket url.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# get do_blog.sh&lt;/span&gt;
   &lt;span class=&quot;c&quot;&gt;# add do_blog.sh to home dir&lt;/span&gt;
   cp ~/mailblog-files/do_blog.sh ~/do_blog.sh
   chmod u+x do_blog.sh
   chmod g+x do_blog.sh
   &lt;span class=&quot;c&quot;&gt;# test setup so far&lt;/span&gt;
   ./do_blog.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Configure Mailgun&lt;/h2&gt;

&lt;p&gt;Tell Mailgun how to route incoming mail to your mailblog server. You
can choose an email address you want to use and set the webhook on
your server. You can choose any webhook address you want, just make
sure it matches the path you use in the next step.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login to &lt;a href=&quot;http://mailgun.net&quot;&gt;Mailgun.net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Go to &lt;a href=&quot;https://mailgun.net/cp/routes&quot;&gt;https://mailgun.net/cp/routes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Click Create Route&lt;/li&gt;
&lt;li&gt;Filter expr: match_recipient(&quot;mailblog@domain.tld&quot;)&lt;/li&gt;
&lt;li&gt;Add Action: forward(&quot;http://mailblogserver.domain.tld/mailgun/hook.php&quot;)&lt;/li&gt;
&lt;li&gt;Add Action: stop()&lt;/li&gt;
&lt;li&gt;Click Save&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Add Webhook to Your Server&lt;/h2&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# add mailgun hook.php&lt;/span&gt;
   mkdir -p /var/www/mailgun
   cp mailblog-files/hook.php /var/www/mailgun/hook.php
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;You're Done!&lt;/h2&gt;

&lt;p&gt;Go ahead and try to send an email to your new mailblog address. A few
seconds after sending, you should see your new post appear in your s3
bucket and your mailblog homepage update to show your new post.&lt;/p&gt;

&lt;h2&gt;Caveats&lt;/h2&gt;

&lt;p&gt;A few warnings. First, &lt;strong&gt;there is no access control&lt;/strong&gt;. This means that
anyone can post to your blog if they know your blog's email
address. You could add some basic security to this by adding a check
of the from address in the hook.php script (and also verifying the
webhook signature value to make sure the call is authentic). So, a bit
of security by obscurity (which is admittedly terrible and lazy).&lt;/p&gt;

&lt;p&gt;Second, this setup only handles text posts right now. Eventually I
would like to support handling image attachments to the emails and
using the email text as the caption or something.&lt;/p&gt;

&lt;p&gt;There are many improvements that can be made on this system, but this
is a good start. Try it, and let me know what you create!&lt;/p&gt;

&lt;h2&gt;Repos&lt;/h2&gt;

&lt;p&gt;Custom jekyll gem:
&lt;a href=&quot;https://github.com/jazzychad/jekyll&quot;&gt;https://github.com/jazzychad/jekyll&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mailblog template:
&lt;a href=&quot;https://github.com/jazzychad/mailblog&quot;&gt;https://github.com/jazzychad/mailblog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mailblog-Files:
&lt;a href=&quot;https://github.com/jazzychad/mailblog-files&quot;&gt;https://github.com/jazzychad/mailblog-files&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>March Madness Bracket Challenge 2012</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/03/11/march-madness-brackets.html">http://blog.jazzychad.net/2012/03/11/march-madness-brackets.html</link>
    <updated>2012-03-11T00:00:00-08:00</updated>
    <id>http://blog.jazzychad.net/2012/03/11/march-madness-brackets.html</id>
    <guid>http://blog.jazzychad.net/2012/03/11/march-madness-brackets.html</guid>
    <content type="html">&lt;p&gt;I have been running an NCAA March Madness bracket challenge on my
website since 2005. It's back this year!&lt;/p&gt;

&lt;p&gt;Head over to
&lt;a href=&quot;http://brackets.jazzychad.net&quot;&gt;http://brackets.jazzychad.net&lt;/a&gt; and
create as many brackets as you like.&lt;/p&gt;

&lt;p&gt;You can also create pools so that you can rank your brackets against
friends or co-workers. I know a couple of companies that use my site
to run their office pools each year. Pretty cool.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>BankersBox - A Redis-like API for localStorage</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/03/05/bankersbox.html">http://blog.jazzychad.net/2012/03/05/bankersbox.html</link>
    <updated>2012-03-05T00:00:00-08:00</updated>
    <id>http://blog.jazzychad.net/2012/03/05/bankersbox.html</id>
    <guid>http://blog.jazzychad.net/2012/03/05/bankersbox.html</guid>
    <content type="html">&lt;p&gt;Today I am happy to announce the open-sourcing of
&lt;a href=&quot;https://github.com/twilio/BankersBox&quot;&gt;BankersBox&lt;/a&gt;, a javascript
library I have been developing inside Twilio.&lt;/p&gt;




&lt;p&gt;BankersBox is a &lt;a href=&quot;http://redis.io&quot;&gt;Redis&lt;/a&gt;-like API wrapper for
javascript client-side data storage. By default it uses localStorage
as the persistence layer.&lt;/p&gt;

&lt;p&gt;I have a more detailed writeup over on the &lt;a href=&quot;http://www.twilio.com/engineering/2012/03/05/open-sourcing-bankersbox&quot;&gt;Twilio Engineering
Blog&lt;/a&gt;,
and there is extensive documentation on the &lt;a href=&quot;https://github.com/twilio/BankersBox&quot;&gt;official BankersBox
repo&lt;/a&gt; at GitHub.&lt;/p&gt;

&lt;p&gt;Here are some of the things you can do with BankersBox:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BankersBox&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;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// returns &amp;quot;bar&amp;quot;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;myobject&amp;quot;&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;greeting&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;world&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;myobject&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// returns the object&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&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;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;incr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;count&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// sets &amp;quot;count&amp;quot; to 11, returns 11&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;incr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;newcount&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// sets &amp;quot;newcount&amp;quot; to 1, returns 1&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lpush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;mylist&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lrange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;mylist&amp;quot;&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;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// returns [&amp;quot;hello&amp;quot;]&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rpush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;mylist&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;world&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lrange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;mylist&amp;quot;&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;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// returns [&amp;quot;hello&amp;quot;, &amp;quot;world&amp;quot;]&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sadd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;myset&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;apple&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sadd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;myset&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;oragne&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smembers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;myset&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// returns [&amp;quot;apple&amp;quot;, &amp;quot;orange&amp;quot;]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sismember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;myset&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;apple&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// returns true&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sismember&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;myset&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;lemon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// returns false&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;scard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;myset&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// returns 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;BankersBox has an MIT license, so please fork and contribute!&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>My Mixergy Interview</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2012/01/23/my-mixergy-interview.html">http://blog.jazzychad.net/2012/01/23/my-mixergy-interview.html</link>
    <updated>2012-01-23T00:00:00-08:00</updated>
    <id>http://blog.jazzychad.net/2012/01/23/my-mixergy-interview.html</id>
    <guid>http://blog.jazzychad.net/2012/01/23/my-mixergy-interview.html</guid>
    <content type="html">&lt;p&gt;Last week, &lt;a href=&quot;http://www.andrewwarner.com&quot;&gt;Andrew Warner&lt;/a&gt; asked to interview me on
&lt;a href=&quot;http://mixergy.com/&quot;&gt;Mixergy&lt;/a&gt; about my experience with Y Combinator and Notifo.&lt;/p&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;We recorded the 90-minute interview on Friday at noon. We had a very brief
pre-interview session in which Andrew made sure a few facts he had were
correct. Other than that, I had no prior knowledge of the questions he would ask
or where the interview would go. This made the entire dialog feel very natual
and candid. Andrew was a very professional interviewer and a pleasure to talk
to. There were many parts of the story which weren't able to be told (we ran out
of time). Someday I will write an unabridged post-mortem of the entire Notifo
story.&lt;/p&gt;

&lt;p&gt;In the mean time, &lt;a href=&quot;http://mixergy.com/etzel-notifo-interview/&quot;&gt;please enjoy my interview here&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
  
  <entry>
    <title>Fouling Out and Moving On</title>
    <link rel="alternate" href="http://blog.jazzychad.net/2011/09/08/fouling-out-moving-on.html">http://blog.jazzychad.net/2011/09/08/fouling-out-moving-on.html</link>
    <updated>2011-09-08T00:00:00-07:00</updated>
    <id>http://blog.jazzychad.net/2011/09/08/fouling-out-moving-on.html</id>
    <guid>http://blog.jazzychad.net/2011/09/08/fouling-out-moving-on.html</guid>
    <content type="html">&lt;p&gt;Today is a bittersweet day. I am closing one chapter of my life and opening a brand new one.&lt;/p&gt;

&lt;p&gt;My startup is dead.&lt;/p&gt;




&lt;p&gt;You can read the official announcement on the &lt;a href=&quot;http://blog.notifo.com/&quot;&gt;Notifo Blog&lt;/a&gt;. After 20 long months of trying to build the best notification platform for the modern, mobile web I must come to terms with the fact that I failed in one critical area: creating a viable business model. There is no money left, so the journey must end here.&lt;/p&gt;

&lt;p&gt;I am feeling alternating waves of several different emotions as the finality of this decision sinks in: anger, grief, disappointment, guilt, relief, sadness, anxiety, excitement, and fear. I honestly believe that I tried my hardest to make things work. After it looked like Notifo was not going to be the success I hoped it would, I tried creating several other apps in hopes of scoring a hit and reviving the company. No such luck. I am most disappointed in myself because even though I feel I tried my best, I must admit my best was not good enough. I have learned so much going through this process, and yet I feel as if I am letting those people who believed so strongly in me down.&lt;/p&gt;

&lt;p&gt;The gist of Paul Graham's essay &quot;&lt;a href=&quot;http://www.paulgraham.com/die.html&quot;&gt;How Not to Die&lt;/a&gt;&quot; is &quot;Don't give up.&quot; Well, sadly I give up. I'm done. After critical examination of my physical, mental, emotional, and spiritual health (not to mention for the sake of my marriage), I have decided that I cannot continue on this way. I need to reset my life and get back on track for a while before wearing the founder hat again.&lt;/p&gt;

&lt;h2&gt;Fouling Out&lt;/h2&gt;

&lt;p&gt;I was discussing my situation with a close friend a few weeks ago. I told him things were looking bad, and I was looking for my next move.&lt;/p&gt;

&lt;p&gt;He asked, &quot;So what happens when you foul out?&quot;&lt;/p&gt;

&lt;p&gt;I said, &quot;I don't know. I guess I'll find out.&quot;&lt;/p&gt;

&lt;p&gt;I still don't know exactly. I'll be dealing with the process of shutting down the company over the next couple of months as I deal with taxes, legal papers, refunding investors the little money that is left, etc...&lt;/p&gt;

&lt;p&gt;But, I liked the way he phrased that question. The world is filled with sports metaphors, and being a huge baseball fan I really enjoy that variety. Usually when people goof up or fail they are said to &quot;strike out.&quot; I played little league baseball as a young lad, and as a batter, striking out is no fun. There are two ways to strike out: looking and swinging. Striking out looking is the absolute worst feeling. It means you just watched a perfectly good ball fly by and did nothing about it. Striking out swinging is a little better because at least you made an effort to swing the bat, but you just didn't make contact.&lt;/p&gt;

&lt;p&gt;Fouling out is still hard to swallow, but it means something different. It means you stood up to the plate, swung the bat as hard as you could, and made contact with the ball. But, in the end, you're still out.&lt;/p&gt;

&lt;p&gt;This startup was my first at-bat in the major leagues. I stood up to the plate, tried as hard as I could, made contact a few times, but was never able to put the ball in play. Now my at-bat is over. The good thing is, there is more than one at-bat per game, but it might just be a while before I step up to the plate again.&lt;/p&gt;

&lt;h2&gt;Moving On&lt;/h2&gt;

&lt;p&gt;As I saw this day approaching, I starting preparing for my next role in life. During the past few weeks I spoke with several companies in the SF Bay Area about potential opportunities with them. I hope to write another post sometime about that whole process.&lt;/p&gt;

&lt;p&gt;After making some very tough decisions, I am happy to announce that I will be joining Twilio as a Senior Software Engineer working toward the betterment of the real-time web, something I am deeply passionate about. I have had a great relationship with Twilio for the past two years working with their products and getting to know people that work there. Twilio's vision of improving communication in the cloud is something I firmly believe in, and I am excited to help create the magic that they provide to improve the lives of developers the world over.&lt;/p&gt;

&lt;p&gt;A bittersweet day. One chapter closes, another one begins...&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://news.ycombinator.com/item?id=2975845&quot;&gt;Further discussion on Hacker News.&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
  
</feed>
