1. Gimme Bar: One Year Old

    Exactly one year ago, today, Gimme Bar was born.

    Gimme Bar has been the focus of my work for that entire time, and I haven't blogged about it (much).

    Ironically (sort of), I've been far too busy working on Gimme Bar to do much writing about Gimme Bar, but I thought it fitting to take a couple minutes to write a few words about it today.

    The elevator pitch for the project goes something like this: Gimme Bar is a personal utility to help you capture and collect interesting things you find in your day-to-day use of the Web.

    I'm admittedly not very good at the pitch, but my colleague (and Gimme Bar's backer) Cameron is, and we released this demo video, yesterday:

    We're in the middle of some huge changes on the technical side that I intend to blog about, and once those are released, I hope to add a lot more active users. If the video makes it sound like something you might be interested in, be sure to sign up for an invitation. We've got some really great stuff coming in the pipeline, too, for existing users.

    I'll post more, soon, I hope.

  2. Post-Advent 2010

    As I write this on Christmas Eve, Chris is putting the finishing touches on PHP Advent 2010.

    A brief search of my site indicates that I haven't actually blogged about PHP Advent since 2007, when I was lucky enough to write the first article. That first year, Chris put the advent articles up on his blog (and we do intend to copy them over to phpadvent.org, eventually). Sensing that Chris had entirely too much work to do, curating, and since we were working together by the time the season came around in 2008, I offered to help with editing and curation—I did, after all know the pain/joy of putting together a magazine.

    Chris took me up on my offer, and he enlisted Jon and Jon to design and build a proper site. We commissioned authors a little too late, but they came through and PHP Advent 2008 was a success.

    By the time 2009 came around, Chris was already deep into preparing to launch Analog, and I'd already announced (internally) that I was moving on to other things. As a result, 2009's Advent was hard. Really hard. We commissioned authors too late, didn't set solid deadlines (as much as we hate deadlines, this sort of date-sensitive project requires them), neglected to dedicate enough time to author herding and editing, and to top it all off, I was headed to Costa Rica for a much-needed vacation, leaving Chris holding the bag for the last five days of 2009's season. Things were so bad at one point, last year, that I took it upon myself to write an article just so that we didn't miss a day. Luckily, we made it through (and by we, I mean Chris, because by the time my flight to San Jose on Dec. 19th came around, I'd had quite enough of Advent for the year).

    If we learned anything from PHP Advent 2009, it was sadly not from the great articles, but instead from our own failures. If we were going to do this again in 2010, we needed to get on it early, and we needed to attack with full-force. I set my calendar to start bugging me in August, but even though I was hassled by its weekly reminders, we found ourselves at the start of November, wrecked from just having organized a conference, and in the middle of two product launches. Despite feeling like we didn't want to have the trouble of Advent again in 2010, neither of us dared say it to the other…at least not in so many words.

    Due only to the abilities and professionalism of our most excellent authors, PHP Advent 2010 was—at least in my opinion—the best year, yet. They wrote wonderful, substantial, punchy articles that informed our readers, and generated significantly more traffic than we've seen in previous years: over 70,000 views, from more than 25,000 unique visitors, so far, and data from past years tells us that these numbers drop slightly starting on the 25th as we cease to post new content, but remain strong into January, with constant, lower traffic and occasional blips throughout the year. The most popular article this year had more than 10,000 views!

    As we post the last article of 2010, I'm encouraged but all of this, and—contrary to how I felt in 2009—am actually looking forward to making PHP Advent even better in 2011.

    Thank you Chris, and thank you authors. Have a wonderful new year.

  3. Remote pbcopy

    I use the command line a lot. I'm sure many of you do, too.

    I find myself often piping things between processes:

    $ cat seancoates.com-access_log \
    > | awk {'print $1'} \
    > | sort \
    > | uniq \
    > | wc -l
    627
    $ # unique IPs

    One particularly useful tool on my Mac is the pbcopy utility, which takes standard input and puts it on the pasteboard (this is known as the "clipboard" on some other systems). Its sister application, pbpaste is also useful (it outputs your pasteboard to standard output when your pasteboard contains data that can be represented in some sort of text form—if you have image data copied, for example, pbpaste yields no output).

    $ cat seancoates.com-access_log \
    > | awk {'print $1'} \
    > | sort \
    > | uniq \
    > | pbcopy
    $ # the list of unique IPs is now on my pasteboard

    I find this particularly useful for getting information from the command line into a GUI application.

    Wouldn't it be even more useful if we could pbcopy from a remote SSH session? Indeed it is useful. Here's how.

    The first thing you need is a listener on your local machine. Luckily, Apple has provided us with launchd and its administration utility, launchctl. This is basically [x]inetd for your Mac (plus a bunch of other potentially great stuff that I simply don't understand). Put the following in ~/Library/LaunchAgents/pbcopy.plist:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
         <key>Label</key>
         <string>localhost.pbcopy</string>
         <key>ProgramArguments</key>
         <array>
             <string>/usr/bin/pbcopy</string>
         </array>
         <key>inetdCompatibility</key>
         <dict>
              <key>Wait</key>
              <false/>
         </dict>
         <key>Sockets</key>
         <dict>
              <key>Listeners</key>
                   <dict>
                        <key>SockServiceName</key>
                        <string>2224</string>
                        <key>SockNodeName</key>
                        <string>127.0.0.1</string>
                   </dict>
         </dict>
    </dict>
    </plist>

    …then, run: launchctl load ~/Library/LaunchAgents/pbcopy.plist

    This sets up a listener on localhost (127.0.0.1) port 2224, and sends any data received on this socket to /usr/bin/pbcopy. You can try it with telnet:

    $ telnet 127.0.0.1 2224
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    hello
    ^]
    telnet> ^D
    Connection closed.

    …then try pasting. You should have hello (followed by a newline) on your pasteboard.

    The next step is tying this into SSH. Add RemoteForward 2224 127.0.0.1:2224 to ~/.ssh/config. This will tell your SSH connections to automatically forward the remote machine's local port 2224 to your local machine, on the same port, over your encrypted SSH tunnel. It's essentially the same thing as adding -R2224:localhost:2224 to your SSH connection command.

    Now you have a listener on your local machine, and a secure tunnel from remote servers to this listener. We need one more piece to tie everything together. Put the following in a file (preferably in your path) on the remote machine(s) where you'd like a pipe-friendly pasteboard:

    cat | nc -q1 localhost 2224

    …I like to put this in ~/bin/pbcopy or /usr/local/bin/pbcopy on servers where I have root. You'll also need to chmod +x this file to make it executable. You'll need the nc executable, which is often available in a package called netcat. This invocation of nc takes standard input and pushes it to localhost on port 2224.

    Now you should have a useful pbcopy on your remote server(s). Be aware, though, that there is no additional security on this port connection. If someone on the remote machine can connect to localhost:2224, they can inject something into your pasteboard. This is usually safe, but you should definitely keep it in mind. Also, if you have multiple users using this technique on the same server, you'll probably want to change the port numbers for each user.

    I use this technique all the time. Now you can too. Hope it's helpful.

    (Note: I'm tagging this PHP and Web because it's likely to overlap with those groups.)

  4. Brooklyn Beta

    Last week, many of the Web's most influential developers and designers converged on a seemingly unremarkable art space (née factory for novelty invisible dog leashes) in Brooklyn for the first of what I hope will become a long-standing conference tradition: Brooklyn Beta.

    Brooklyn Beta

    Despite having personally helped organize several other conferences in the past, Brooklyn Beta has easily earned a spot at the top of my list of favourite events in my career.

    I've been involved with planning this event nearly since its inception, but mostly in an advisory role. My friends and colleagues Cameron and Chris did the heavy lifting and deserve all of the credit, though they'd be the first to object to this statement by identifying the many people who came together to volunteer and without whom the conference simply would not have happened.

    The goal of BB was to get a group of developers, designers, and (a few) savvy business-type people — the makers of the Web — in one room to meet, converse, show & tell, and hopefully to inspire them to collaborate and make something. Even though only a few days have passed, I know this effort was successful, and I can't wait to see the applications, sites, art and teams that arise and attend next year's conference.

    In addition to the impeccable list of speakers, what really made BB stand out was the group of attendees who had the pleasure of spending the day(s) together. Despite my daze (see below), I finally put a face to many of the people whose blogs and Twitter streams have occupied large amounts of my career.

    Much of the time leading up to Brooklyn Beta is a blur — we've been frantically trying to finish our app in time to demo (more below) at BB, in addition to handling last-minute details, and we quite obviously bit off more than we could chew. A tip: organize a conference OR finish a large application; don't do both in the same week.

    To keep this from turning into rambling and to let me get back to putting some polish on the aforementioned app, here are a few things I feel worth highlighting, in point form:

    • I am blown away by the overwhelming positivity associated with Brooklyn Beta. I've been following the associated Twitter stream, and with the exception of one misinformed whiner (who didn't even attend BB), I've seen nothing but glowing reviews. Further reading: Fred Wilson (one of our speakers), Josh Smith (Plaid), and Charlie O'Donnell; I also put my photos of Brooklyn Beta on Flickr.
    • The first talk of the day, by Shelley Bernstein, far exceeded my expectations. It's not that I had low expectations, it's that the talk was absolutely full of wisdom and good practices. If you have the opportunity to see Shelley give this talk, I suggest you take it.
    • Marco Arment's talk on giving up his day job at Tumblr to focus his efforts on Instapaper was very inspiring. If I wasn't already hip-deep in a startup, I'm pretty sure I wouldn't be able to resist the urge to build something of my own after hearing Marco speak.
    • Fred Wilson, who — from what I can gather — has been key in funding at least $80M of our peers' projects this year, spoke on Golden Principles for Successful Web Apps. The talk as a whole was very good, but he immediately captured my attention when he opened with a statement that seems obvious to me, but I feel is under-represented in the industry: Speed Matters. This point wasn't buried in the middle of a discussion; it was at the forefront of his talk. Remember this point; Fred obviously knows his stuff.
    • Gimme Bar! As I hinted above, we're on the cusp of launching a project that I've been working on full time since leaving my day job at the end of 2009. We demoed Gimme Bar at Brooklyn Beta and received universally positive and excited comments. This is extremely encouraging. You will hear more about this before next week.
    • Similarly, my friends at Analog demoed their project, Mapalong, which was also positively received. I'm excited for them to be launching as well.

    If you missed Brooklyn Beta this year, hopefully you won't let it pass you by again in 2011.

    There's so much more I could say… but I've got a project to launch. (-:

  5. Arbitrary Incrementer in PHP

    On several recent occasions I had a need for an incrementer that uses an arbitrary character set and I thought I'd share my code with you.

    I've used this code in the GPL Virus that I wrote to poke fun at the Wordpress/Thesis/GPL debacle, as well as in some clean up I'm doing for the extremely useful JS Bin project.

    The most important application, however, was in creating a URL shortening system for the as-yet-unannounced startup project that I'm working on.

    I wanted the URL shortener to make the shortest possible URLs. To keep the number of characters in a URL short, I had to increase the set of characters that could comprise a key.

    To illustrate this, consider a hexadecimal number versus its decimal equivalent:

    $num = 32323232321;
    echo $num . "\n";
    echo dechex($num) . "\n";

    This outputs:

    32323232321
    7869d6241

    As you can see, the second number is two characters shorter than the first number. The reason for this is that every digit of a decimal number is represented by one of 0123456789 (10 unique characters), while ever digit of the hexadecimal number is represented by one of 0123456789abcdef (16 unique characters). This means that we can pack more information into each digit, making the overall length of the key shorter.

    PHP has a base_convert() function that allows any sequential base up to 36 (the number of letters in the alphabet (26) plus the 10 numeric digits). We can further compress the above example by increasing the base from 16 (hexadecimal) to 36:

    $num = 32323232321;
    echo $num . "\n";
    echo base_convert($num, 10, 16) . "\n";
    echo base_convert($num, 10, 36) . "\n";

    Using the full spectrum saves us 4 characters:

    32323232321
    7869d6241
    eukf1oh

    Unfortunately, base_convert() does not take the base beyond 36. I wanted to increase the information density (and thus decrease the length of the tokens) even further. URLs are case-sensitive, so why not use both uppercase and lowercase letters? We might as well throw in a few extra characters (- and _).

    Additionally, I wanted to be able to increment the sequence, based on the current maximum value. PHP offers no facility as simple as base_convert for this (and the $a = "zzz"; echo ++$a; trick doesn't quite do what I need).

    After a bit of code wrangling, I came up with the following algorithm that allows an arbitrary character set, and increments over it, recursively.

    function inc($n, $pos=0)
    {
        static $set = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_';
        static $setmax = 61;
     
        if (strlen($n) == 0) {
            // no string
            return $set[0];
        }
     
        $nindex = strlen($n) - 1 - $pos;
        if ($nindex < 0) {
            // add a new digit to the front of the number
            return $set[0] . $n;
        }
     
        $char = $n[$nindex];
        $setindex = strpos($set, $char);
     
        if ($setindex == $setmax) {
            $n[$nindex] = $set[0];
            return inc($n, $pos+1);
        } else {
            $n[$nindex] = $set[$setindex + 1];
            return $n;
        }
    }

    To change the set, simply alter the $set variable, and adjust the $setmax accordingly. I hope you find this as useful as I have.

    After writing this piece, but before publishing it, I stumbled upon some similar code that they use at Flickr to do arbitrary base conversion, so take a peek over there to see how they handle this.