I was just watching a friend of mine work with git, and he'd always type all the git commands in full, like git status and git push. I realized that he must not be the only one to do so, so I decided to write this quick blog post and encourage everyone to create Huffman coded aliases for the most commonly used commands. Instead of typing git status, alias it to gs. Instead of git add, alias it to ga, etc.

Here are a bunch of aliases that I created for 99% of git commands I ever use:

alias ga='git add'
alias gp='git push'
alias gl='git log'
alias gs='git status'
alias gd='git diff'
alias gdc='git diff --cached'
alias gm='git commit -m'
alias gma='git commit -am'
alias gb='git branch'
alias gc='git checkout'
alias gra='git remote add'
alias grr='git remote rm'
alias gpu='git pull'
alias gcl='git clone'

Here is my typical workflow with these command:

$ vim file.c
$ gd                     # git diff
$ ga file.c              # git add file.c
$ gm "added feature x"   # git commit -m "added feature x"
$ ...
$ gp                     # git push

Short and sweet!

This article is part of the article series "Perl One-Liners Explained."
<- previous article next article ->

Perl One LinersThis is the sixth part of a nine-part article on Perl one-liners. In this part I will create various one-liners for selective printing and deleting of certain lines. See part one for introduction of the series.

Perl one-liners is my attempt to create "perl1line.txt" that is similar to "awk1line.txt" and "sed1line.txt" that have been so popular among Awk and Sed programmers and Linux sysadmins.

The article on Perl one-liners will consist of nine parts:

The selective printing and selective deleting of certain lines is actually the same process. If you wish to delete certain lines, you just print the lines you're interested in. Or the other way around! For example, to delete all lines with even line numbers, print the odd lines, and to delete odd lines print the even lines.

After I am done with the 8 parts of the article, I will release the whole article series as a pdf e-book! Please subscribe to my blog to be the first to get it!

Awesome news: I have written an e-book based on this article series. Check it out:

Here are today's one-liners:

82. Print the first line of a file (emulate head -1).

perl -ne 'print; exit'

This is the simplest one-liner so far. Here Perl reads in the first line into $_ variable thanks to -n option, then it calls print statement that prints the contents of the $_ variable. And then it just exists. That's it. The first line got printed and that's all we wanted.

83. Print the first 10 lines of a file (emulate head -10).

perl -ne 'print if $. <= 10'

This one-liner uses the $. special variable. This variable stands for "current line number." Each time Perl reads in the next line, it increments $. by one. Therefore it's very simple to understand what this one-liner does, it prints the line if the line number is equal to or less than 10.

This one liner can also be written the other way around without use of if statement,

perl -ne '$. <= 10 && print'

Here the print statement gets called only if $. <= 10 boolean expression is true, and it's true only if current line number is less than or equal to 10.

84. Print the last line of a file (emulate tail -1).

perl -ne '$last = $_; END { print $last }'

Printing the last line of the file is a bit tricker, because you always have to maintain the previous line in memory. In this one-liner we always save the current line in $_ to $last variable. When Perl program ends, it always executes code in the END block. Now just before exiting it read in the last line, so when it quits, we print $last that prints the last line.

Another way to do the same is,

perl -ne 'print if eof'

This one-liner uses the eof function that returns 1 if the next read will return end of file. Since the next read after the last line in the file will really return eof, this one-liner does what it's supposed to do.

85. Print the last 10 lines of a file (emulate tail -10).

perl -ne 'push @a, $_; @a = @a[@a-10..$#a]; END { print @a }'

Now this is tricky. Here we push each line to the @a array, and then we replace with a slice of itself. We do @a = @a[@a-10..$#a], which means, replace @a with last 10 elements of a. @a-10 is evaluated in scalar context here and it returns number of elements in the array minus 10. #$a is the last index in the @a array. And @a[@a-10..$#a] takes the last 10 elements of the array, so @a always contains just 10 last elements.

Here is an example. Suppose @a contains ("line1", "line2", "line3", "line4"). And let's say we want to print last 4 lines of the file. Now when we read the 5th line, the array becomes ("line1", "line2", "line3", "line4", "line5"). At this moment @a-4 is 1, because @a in scalar context is 5. The $#a however is 4 because that's the last index in the array. Now taking the slice, @a[@a-4..$#a] is @a[1..4], which drops the front element from the array and the @a array becomes ("line2", "line3", "line4", "line5").

86. Print only lines that match a regular expression.

perl -ne '/regex/ && print'

Here /regex/ is short for $_ =~ /regex/. Since the -n operator puts every line in $_ variable the /regex/ returns true on all lines that matched the regex. If that happened, print prints the line.

87. Print only lines that do not match a regular expression.

perl -ne '!/regex/ && print'

This is the same as the previous one-liner, except the regular expression match has been negated. So all the lines that don't match the regex get printed.

88. Print the line before a line that matches a regular expression.

perl -ne '/regex/ && $last && print $last; $last = $_'

In this one-liner every line gets saved to $last variable. Now when the next line matches /regex/ and there has been a previous line $last, then it print $last prints the last line, and then it assigns the current line to the last line variable via $last = $_.

89. Print the line after a line that matches a regular expression.

perl -ne 'if ($p) { print; $p = 0 } $p++ if /regex/'

Here we set the variable $p if the line matches a regex. It indicates that the next line should be printed. Now when the next line is read in and $p is set, then that line gets printed and $p gets set to 0 again to reset the state.

90. Print lines that match regex AAA and regex BBB in any order.

perl -ne '/AAA/ && /BBB/ && print'

This one-liner is basically the same as one-liner #86 above. Here we test if a line matches two regular expressions instead of line. If a line matches both regexes, then it gets printed.

91. Print lines that don't match match regexes AAA and BBB.

perl -ne '!/AAA/ && !/BBB/ && print'

This one-liner is almost the same as one-liner #87. Here we test if a line doesn't match two regular expressions in any order. If it doesn't match /AAA/ and it doesn't match /BBB/, then we print it.

92. Print lines that match regex AAA followed by regex BBB followed by CCC.

perl -ne '/AAA.*BBB.*CCC/ && print'

Here we simply chain regexes AAA, BBB and CCC with .*, which stands for match anything or nothing at all. If AAA is followed by BBB and that is followed by CCC then we print the line. It also matches AAABBBCCC with nothing in between the regexes.

93. Print lines that are 80 chars or longer.

perl -ne 'print if length >= 80'

This one-liner prints all lines that are 80 chars or longer. In Perl you can sometimes omit the brackets () for function calls. In this one we omitted brackets for length function call. In fact, length, length() and length($_) are the same.

94. Print lines that are less than 80 chars in length.

perl -ne 'print if length < 80'

This is the opposite of previous one-liner. It checks if the length of a line is less than 80 characters.

95. Print only line 13.

perl -ne '$. == 13 && print && exit'

As I explained in one-liner #83, the $. special variable stands for "current line number". So if $. has value 13, then we print the line and exit.

96. Print all lines except line 27.

perl -ne '$. != 27 && print'

Just like in previous one-liner, we check if the current line is line 27, if it's not then we print it, otherwise we skip it.

Another way to write the same is to reverse print and $. != 27 and use if statement,

perl -ne 'print if $. != 27'

97. Print only lines 13, 19 and 67.

perl -ne 'print if $. == 13 || $. == 19 || $. == 67'

If you have Perl 5.10 or later then you can use the ~~ smart match operator,

perl -ne 'print if int($.) ~~ (13, 19, 67)' 

The smart matching operator ~~ appeared only in Perl 5.10. You can do all kinds of smart matching with it, for example, check if two arrays are the same, if an array contains an element, and many other use cases (see perldoc perlsyn). In this particular one-liner we use int($.) ~~ (13, 19, 67) that determines if numeric value $. is in the list (13, 19, 69). It's basically short for, grep { $_ == int($._) } (13, 19, 67). If the check succeeds the line gets printed.

98. Print all lines between two regexes (including lines that match regex).

perl -ne 'print if /regex1/../regex2/'

This one-liner uses the flip-flop operator, which becomes true when a line matches regex1 and becomes false after another line matches regex2. Therefore this one-liner prints all lines between (and including) lines that match regex1 and regex2.

99. Print all lines from line 17 to line 30.

perl -ne 'print if $. >= 17 && $. <= 30'

This one-liner is very simple to understand. The $. variable stands for the current line number, so it checks if the current line number is greater than or equal to 17 and less than or equal to 30.

I just thought of another way to write it,

perl -ne 'print if int($.) ~~ (17..30)'

This is one-liner uses the Perl 5.10 (and later) smart matching operator ~~. It basically says, is the current line number in the list (17, 18, 19, ..., 30). If it is, the smart match succeeds and the line gets printed.

You can write the same idea in older Perls as following,

perl -ne 'print if grep { $_ == $. } 17..30'

What happens here is grep checks if the current line number is in the list (17, 18, ..., 30). If it is, it returns a list of just one element, and a list of one element is true, and the line gets printed. Otherwise grep returns the empty list, which is false, and nothing gets printed.

100. Print the longest line.

perl -ne '$l = $_ if length($_) > length($l); END { print $l }'

This one-liner keeps the longest line seen so far in the $l variable. In case the current line $_ exceeds the length of currently longest line, it gets replaced. Just before exiting, the END block is executed and it prints the longest line $l.

101. Print the shortest line.

perl -ne '$s = $_ if $. == 1; $s = $_ if length($_) < length($s); END { print $s }'

This one-liner is the opposite of the previous one. But as we're finding the minimum and $s is not defined for the first line, we have to set it to first line explicitly. Otherwise it's the same just with the length check reversed length($_) < length($s).

102. Print all lines that contain a number.

perl -ne 'print if /\d/'

This one-liner uses a regular expression \d that stands for "match a number" and checks if a line contains one. If it does, the check succeeds, and the line gets printed.

103. Find all lines that contain only a number.

perl -ne 'print if /^\d+$/'

This one-liner is very similar to the previous one, but instead of matching a number anywhere on the line, it anchors the match to the beginning of the line, and to the end of the line. The regular expression ^\d+$ means "match one or more numbers that start at the beginning of line and end at the end of the line".

104. Print all lines that contain only characters.

perl -ne 'print if /^[[:alpha:]]+$/

This one-liner checks if the line contains only characters and if it does, it prints it. Here the [[:alpha:]] stands for "match all characters". You could also write the same as [a-zA-Z] (if you live in ASCII world).

105. Print every second line.

perl -ne 'print if $. % 2'

This one-liner prints first, third, 5th, 7th, etc, line. It does so because $. % 2 is true when the current line number is odd, and it's false when the current line number is even.

106. Print every second line, starting the second line.

perl -ne 'print if $. % 2 == 0'

This one-liner is very similar to the previous one but except printing 1st, 3rd, 5th, etc, lines, it prints 2nd, 4th, 6th, etc, lines. It prints them because $. % 2 == 0 is true when the current line number is 2, 4, 6, ....

107. Print all lines that repeat.

perl -ne 'print if ++$a{$_} == 2'

This one-liner keeps track of the lines it has seen so far and it also keeps the count of how many times it has seen the line before. If it sees the line the 2nd time, it prints it out because ++$a{$_} == 2 is true. If it sees the line more than 2 times, it just does nothing because the count for this line has gone beyond 2 and the result of the print check is false.

108. Print all unique lines.

perl -ne 'print unless $a{$_}++'

Here the lines get printed only if the hash value $a{$_} for the line is 0. Every time Perl reads in a line, it increments the value for the line and that makes sure that only never before seen lines get printed.

Perl one-liners explained e-book

I've now written the "Perl One-Liners Explained" e-book based on this article series. I went through all the one-liners, improved explanations, fixed mistakes and typos, added a bunch of new one-liners, added an introduction to Perl one-liners and a new chapter on Perl's special variables. Please take a look:

Have Fun!

Thanks for reading the article! The next part is going to be about various interesting, intriguing, silly and crazy regular expressions, because Perl is all about regular expressions.

Several weeks ago my friend Madars was in an airport in the Netherlands and he wanted to login into his server via ssh. It turned out that their public internet had only ports 80 and 443 open so he couldn't do that. He asked me if I could proxy either port 80 or 443 to his server. Surely, I had a solution. I modified the tcp proxy server that I had written for my Turn any Linux computer into SOCKS5 proxy in one command article and did:

sudo ./tcp-proxy2.pl 443 madars-server.com:22

This proxied the port 443 on my server to madars-server.com ssh port. Now Madars could do

ssh -p 443 catonmat.net

and he got connected to his server. Mission accomplished.

Here is the code of tcp-proxy2.pl,

use warnings;
use strict;

use IO::Socket::INET;
use IO::Select;

my @allowed_ips = ('all', '10.10.10.5');
my $ioset = IO::Select->new;
my %socket_map;

my $debug = 1;

sub new_conn {
    my ($host, $port) = @_;
    return IO::Socket::INET->new(
        PeerAddr => $host,
        PeerPort => $port
    ) || die "Unable to connect to $host:$port: $!";
}

sub new_server {
    my ($host, $port) = @_;
    my $server = IO::Socket::INET->new(
        LocalAddr => $host,
        LocalPort => $port,
        ReuseAddr => 1,
        Listen    => 100
    ) || die "Unable to listen on $host:$port: $!";
}

sub new_connection {
    my $server = shift;
    my $remote_host = shift;
    my $remote_port = shift;

    my $client = $server->accept;
    my $client_ip = client_ip($client);

    unless (client_allowed($client)) {
        print "Connection from $client_ip denied.\n" if $debug;
        $client->close;
        return;
    }
    print "Connection from $client_ip accepted.\n" if $debug;

    my $remote = new_conn($remote_host, $remote_port);
    $ioset->add($client);
    $ioset->add($remote);

    $socket_map{$client} = $remote;
    $socket_map{$remote} = $client;
}

sub close_connection {
    my $client = shift;
    my $client_ip = client_ip($client);
    my $remote = $socket_map{$client};
    
    $ioset->remove($client);
    $ioset->remove($remote);

    delete $socket_map{$client};
    delete $socket_map{$remote};

    $client->close;
    $remote->close;

    print "Connection from $client_ip closed.\n" if $debug;
}

sub client_ip {
    my $client = shift;
    return inet_ntoa($client->sockaddr);
}

sub client_allowed {
    my $client = shift;
    my $client_ip = client_ip($client);
    return grep { $_ eq $client_ip || $_ eq 'all' } @allowed_ips;
}

die "Usage: $0 <local port> <remote_host:remote_port>" unless @ARGV == 2;

my $local_port = shift;
my ($remote_host, $remote_port) = split ':', shift();


print "Starting a server on 0.0.0.0:$local_port\n";
my $server = new_server('0.0.0.0', $local_port);
$ioset->add($server);

while (1) {
    for my $socket ($ioset->can_read) {
        if ($socket == $server) {
            new_connection($server, $remote_host, $remote_port);
        }
        else {
            next unless exists $socket_map{$socket};
            my $remote = $socket_map{$socket};
            my $buffer;
            my $read = $socket->sysread($buffer, 4096);
            if ($read) {
                $remote->syswrite($buffer);
            }
            else {
                close_connection($socket);
            }
        }
    }
}

Download tcp-proxy2.pl

Download link: tcp proxy 2 (tcp-proxy2.pl)
Download URL: http://www.catonmat.net/download/tcp-proxy2.pl
Downloaded: 7408 times

I also pushed the tcp-proxy2.pl to a new GitHub repository: tcp-proxy2.pl on GitHub.

Enjoy!

I was interviewed by David Weekly recently on 2011-03-19. I copied the interview here in case David's website changes. It was an audio podcast with me and James Halliday.

Original link to the interview.

David Weekly interviews James Halliday and Peter Krumins, the CEO and CTO (respectively) of the newly-established Browserling, a browser testing firm in which David made his first angel investment. (The interview was done a mere hour after closing the round!) James describes his drive down from Alaska to the Bay Area to pursue funding for his startup and Peter describes his childhood with computers and his meeting James on IRC.

Download The David Weekly podcast with Peter Krumins and James Halliday

Here's a pic we took on the investment day:


James Halliday, David Weekly, Peter Krumins

Here's the transcription of the interview:

David: Hey, everybody. It's the David Weekly. This is Sunday, March 6, 2011. I'm joined here by the founders of Browserling, a brand new company. Hey guys.
Peter: Hey.
James: Yo.
David: Yeah, so you're James and Peter.
Peter: Right.
David: So how did you guys meet?
Peter: So we are on this IRC network called Freenode. We are both really interested in programming. I'm on channels like C++ and Perl and Node.js, and James was on some of those channels as well. We met like two years ago on Perl channel. I was publishing blog posts on my blog, catonmat.net, about Perl.
David: So your blog is Cat On Mat?
Peter: Right.
David: Dot net?
Peter: Yes.
David: Okay, so this was like about the same time as maybe some of the funny cat pictures were circulating or?
Peter: I don't really know how I came up with the name.
James: How long have those pictures been circulating? I think an awful long time. Anyhow.
Peter: Yeah, right. So I was doing blog posts about Perl and James noticed them, and he also did some art for them.
James: Yeah, just random projects and things. I've had all these projects for such a long time. I guess ... Well, Peter first got me sort of into blogging to begin with.
David: Uh huh. So you were a reader of his Cat On Mat blog?
James: Yeah, I had read a few of his things.
Peter: Yeah, so I was blogging since 2007.
James: Yeah.
Peter: And we met with James on IRC like in 2009.
David: Got it.
Peter: Or 2008 maybe.
David: What kind of things were you writing in your Cat On Mat blog?
Peter: Oh, so I write about all kinds of computing, like Perl programming, C programming, and sometimes system administration, like Linux shell tricks, and Perl one-liners.
James: And linear algebra stuff too.
Peter: Oh yeah. Linear algebra and MIT algorithms course.
David: Why did you start blogging?
Peter: Just to get popular on the Internet.
David: And then you're popular now.
Peter: Yes I am.
David: So success!
Peter: Yeah, success!
James: Horray!
David: How did you make your blog popular?
Peter: Oh, so I would be submitting my stories anywhere that I can, like Reddit, to Hacker News, to all kinds of Linux forums and like posting the posts on Facebook and on Twitter and Plurk and all the other social networks. I would write a post and spend the next 30 minutes submitting it everywhere. Yeah.
David: Nice. Got it. And then how did you get introduced to computers?
Peter: I was about six.
David: Okay.
Peter: And I went my mom's job. She's a journalist, and they had computers for journalism to make the newspapers, glue them together to send for printing. Sometimes people who worked on the computers allowed me to do some stuff like play games and play around.
David: How old were you?
Peter: Six.
David: Okay.
Peter: Yeah.
David: Yeah, and then so you started playing around on these computers on journalist's downtime.
Peter: Right, it was like ... Yes. It was like Windows 3.0 at first and then Windows 3.1.
David: At what point did you start programming?
Peter: It was about 12 or 13. At first I actually didn't have a computer at home, so I was programming on paper.
David: Oh, wow.
Peter: So I would program on paper and then go to these faculties and then rewrite them in text editor and compile them and run them.
David: Wow. That's a lot of patience to do that.
Peter: Yeah. Well, it didn't go for too long. Maybe I wrote like 15 programs. Then I would just ... Later I got my own computer, so I could do programming on my own at home.
David: Cool. Cool. What about you James? When did you get started programming?
James: So about the same age, about six years old. I guess there's two big parts of what got me so interested in computing. I guess first of all, my mom was pretty big into computing early on. She had, during high school, this TRX-80 from Radio Shack. I didn't actually see that used at all ever, but we also had a 386 at home. This is like 1993 that we got that. I thought, "Wow this is really fun," 'cause there were all these silly DOS games, like Battle Chess for one.
David: Oh, yeah! That was so awesome. Pieces would slay each other.
James: Exactly, yeah.
David: It made chess exhilarating, yeah.
James: Yeah, and you tried to get the queen, for instance, to kill the bishop or something 'cause it's something you don't really see very often. It's like, "What was that again? Oh, that's awesome."
David: Right. Right.
James: So there was that. I was growing up in Portland, Oregon at the time and there's this awesome museum called, OMSI, the Oregon Museum of Science and Industry. So it was like 1994, and my family had one of those membership passes. We'd go like once a month or something, and there'd be new exhibits and everything, like dinosaurs and awesome mechanical stuff. But then like all the way upstairs on the third floor, there was all of these computers, all of these different types of computers too, which I even haven't seen in modern times really much. But all these different kinds of computers, like NeXT computers with like Unixes and Solaris and old Macs and Windows PCs which was then like when it's 3.1. And later they had Windows 95. Big improvement.
But all of these computers were connected to the Internet, and so they all had different types of web browsers, like Mosaic and Netscape, and I thought it was just really amazing that you could just ... If you could find it, just go to all of this crazy content and you didn't have to thumb through ... Well, I guess before then I was really big into kind of encyclopedias 'cause I really loved just browsing seemingly random facts and just sorts sort of ingesting data.
But then, once I'd used the Internet for the first time, I'm like, "Screw all this book crap. I want to" ...
David: The books are dead.
James: Exactly. You can't GREP a book I guess.
David: Right. Right.
James: So that got me really interested in computing. Later my mom got the Internet at home. This was like 1996 with AOL.
David: And where were you living then?
James: That was still in Portland. Went to Eastern Washington around 5th grade or so. I guess we also had some computer books like this HTML 3 book that I read cover to cover basically.
David: Nice.
James: I got some time to just read that and to actually try to write some web pages and things. And there was this chapter somewhere towards the end in the middle called ... I think it was called LiveScript in that book, but it's JavaScript basically. And just this really tiny snippet, and I thought, "Wow that's really cool. You can just"
David: PS. You can write code in your browser.
James: You can write some script and it pops up an alert box or something silly like that, and I thought that was really cool. And then you know, after that when I got my own computer I learned some other languages. I was probably like I think 11 when I started messing with HTML and JavaScript, and then 12 when I started messing like different other languages. I learned some Qbasic, but I really didn't get very far with that 'cause it was really ... It felt pretty impenetrable.
Peter: I actually learned the whole Visual Basic. Visual Basic 5 and Visual Basic 6.
James: Yeah, I messed with Visual Basic 4 a bit when I was younger too, but then I learned-
David: The first time I was ever paid interesting money for a program was a Visual Basic program. I made $100 which later I worked out was like $2 an hour, but it was a lot of money in high school.
James: Yeah.
David: When did you guys graduate high school?
Peter: In 2004.
James: Yeah, it was 2006. Oh goodness, by the time I graduated high school I had written so much code and I knew so many languages. It was pretty ridiculous.
David: What was your first experience with the command line?
James: Well, like when I was six with DOS programs.
David: Right, right, right.
James: That was how you used a computer.
David: That's right.
James: It's like-
David: So it seems pretty natural.
James: It didn't phase me at all. That's how you get data into and out of a computer.
Peter: Yeah, same for me.
James: You just have to type it in.
David: Yeah. So do you see a generational difference between people who were first introduced to computers through a command line interface and those who for whom accessing the command line's a special program they need to invoke?
James: I really don't think so. I think it has more to do with basically how old you are because ... So like over winter break ... A few times, I've started to teach all of my ... So I've got two little brothers and a little sister in Alaska.
David: Cool.
James: I've taught them some Python programming and some JavaScript, and I don't know, they seemed to get it right away 'cause you sort of can just introduce this, "Hey, this is just like a calculator except way more awesome than that." And you can sort of incrementally build up these programs using just simple concepts. I don't know, kids seem to get it. Or maybe it's just my own siblings.
David: You might be related to some very smart people.
James: Yeah, I don't know.
David: What would you guys recommend for somebody who's interested in getting involved in computer programming, is familiar with computers but has never really tried programming themselves?
Peter: I would probably recommend just to building a web page in HTML and throw in some JavaScript like James mentioned before. His first experience was just using alert to get the alert box in the browser. It's so easy to move elements around in the web page. Just write the appropriate JavaScript.
James: In fact, it's much easier nowadays because you've got these nice libraries like JQuery that abstract over all of the horrors that live in the DOM.
Peter: Yes.
James: It used to be so much ... Oh, and there's like layer tags in Netscape 4 and ugh.
David: Ugh.
Peter: Yeah, and now even with Node.js you can do the server side programming in JavaScript.
James: Yeah.
David: So it's sort of feeling like JavaScript's getting to be the first-class programming language of choice.
Peter: Yeah, well ...
James: I think it still continues to be a really important language, and I think that's only getting more so. But other languages are really fun too, like for beginners Python is pretty easy to just dive into and then Perl is also really easy to get into. You just read the Perl doc, Perl intro page, and you're ready to go.
David: Nice. So let's get back to the story of how you guys met. You guys started hanging out on the #Perl channel on freenode.
James: Yeah.
David: And then at what point did you start working on something together and then start making something that was serious together?
Peter: Yeah, so James had the first prototype last year in January. So it's January of 2010. So he wrote the first prototype of StackVM in Haskell, and he showed it to me. We actually had discussed doing a startup together before. He said, "Let's turn this StackVM into startup."
James: Oh, yeah. Oh goodness. I had all of these crazy harebrained ideas for how I would build a startup. I wanted to build this hackable computer type thing. And geez, what were some of my other projects? I wanted to build like sensor data. I guess I didn't have too many direct software ideas actually except for the StackVM thing. So yeah, over winter break I just built out the simplest possible thing that could work.
It was really just ... It was written in Pascal, but it was really silly. It was just AJAX calls and then you'd get an image back. It was just a really basic VNC decoder.
David: Nice.
Peter: Right. So he showed me the project and I liked it, so I jumped in. But yeah, the Pascal was a problem 'cause it was doing the image encoding really slowly. I converted that to Node.js. So I wrote the Node PNG module for doing fast PNG encodings. Yeah, and then James got into Node.js as well. It's around March, April.
David: Got it.
James: Yeah, so I was still in school at the time.
David: Where were you going to school?
James: I was at the University of Alaska Fairbanks.
David: Got it.
James: Actually, also in January I started working on this underwater RV contest project. So I did this in 2008. It was loads of fun. That was down in San Diego. This ... But in 2010 it was gonna be in Hawaii in June, July.
David: Awesome.
James: Oh goodness, yes. We had a lot of problems, I guess, when I did this contest in 2008 'cause we had an EE guy, but he made it his senior project or something, but then ... So it was a little bit ambitious because of that. Then he didn't work, and then it's like, "Oh no. Okay. So we don't have any electronics." I was just sort of tagging along to do some programming work, do a little bit of mechanical stuff.
We had a good-sized team, like I don't know, five people or something. Well four then. But so I had to kind of pick up the hat of doing circuit boards and electronics.
David: Exciting.
James: I had about two weeks to get up to speed to build a working prototype for like a driver system for this whole setup.
David: High speed electrical engineering education. Go!
James: Yeah, pretty much. Well, so it's just digital logic, so that helped. And then it also helped that the instructor, a really awesome guy, Ryan Luller, CS professor, has this crazy harebrained scheme to make circuit boards just using household stuff, like you had out here with this balloon experiment. Just hydrochloric acid and you can just etch these copper-plated fiberglass boards in like an afternoon, couple hours.
David: Cool.
James: You can just have a prototype really fast.
David: Cool. So take me back to how you were working with Peter to get StackVM out the door and make it into something real.
James: Okay, so yeah. I guess ... On freenode there's like the main channels. They're pretty on-topic. Then there's all of these fun side channels where it's a lot of just kind of seemingly random banter, but it's also a really good place to sort of just throw out ideas like, "Hey here's a link to this GitHub project I'm working on. It's kind of neat huh?"
So I think the collaboration with Peter started sort of that way where it's like, "Hey check out this neat GitHub project. I'm gonna turn this into a startup or something I guess." And then yeah, Peter just, like around March or something or April was it? Just started really adding all of this awesome stuff with Node.js.
Peter: Right, right. So it was ... Yeah, so at first I wrote this Node PNG stuff and then Node JPEG and Node GIF, so you could do animated GIF recordings of the virtual machines. And then I wrote Node Video for recording like C or OGG videos, video streams, from the virtual machines. Yeah, and then I improved the design.
And then James jumped in and wrote dnode.
James: Yeah, so I had a lag after midterms when I had a bit of free time. Well, I didn't really have a bit of free time. I was super busy that whole time, but I decided to make some time. I noticed that our routing stuff was getting kind of complicated so I wrote this crazy RPC system using some of the ideas that I'd gotten during a student job using this thing that Ruby has called DRb. I basically took some of those ideas that I thought were awesome and ignored all of the things that were really annoying and I hated. And like implementing my own thread pool because the requests were synchronous. That's bad news. I just made everything asynchronous.
And yeah, so we used that system, dnode, in all of our back-end communication, but then also I wrote an adapter to make that work on top of socket.io which is this abstraction layer for web sockets for fallbacks. So basically we can use the same interfaces between our back-end systems and with the client, and it just makes programming just so much more fun and just so much easier to get your head around.
David: Cool. So it sounds like you guys had started to develop this really productive collaboration where you're kind of piggy-backing on each other's work. You had this sense of momentum, that something was really being built.
James: Yeah.
David: This around summer last year or so?
Peter: Yeah, summer and like a bit of autumn as well.
James: Yeah, so-
David: And then what happened?
Peter: So then we decided to apply at Y-Combinator with the StackVM idea. So we sent the application ... Yeah, and-
James: Well, so I guess we had also decided that, "Hey let's just go to the Bay Area just because, whether or not we get accepted. We're doing this thing."
Peter: Yeah.
David: And when was that, that you decided to move to the Bay Area?
Peter: James moved in early October.
David: Okay.
Peter: And I moved in late October.
David: Got it.
Peter: Yeah.
David: So you just drove down from Alaska?
James: Yeah, so-
David: And were like, "I'm gonna live here now."
James: Yeah, so I had this clunky old car. I guess when I first left Fairbanks ... It had this little bit of oil leak, and it got even worse if you just spilled a little bit of oil on the radiator 'cause it was just really hot. As I was driving out of Fairbanks, there's this really steep hill. It's the only hill pretty much the whole way even though there's a mountain range between. But going up this really steep hill. All of a sudden, I look back in my rear view mirror and there's like this cloud following me. Turns out I-
David: At the beginning of your trip from Alaska, you're pulling out of Fairbanks and there's a cloud of this plume behind you.
James: Yeah, coming out of my exhaust pipe.
David: That's no good.
James: So I looked at that. I slowed down. I stopped. I put my blinkers on, and I just kind of looked at it. And then I'm like, "You know what? Screw it. The car's still going forward. Let's just see." And it did. I guess it was just some oil that had spilled, so I filled ... I topped off the oil before I left. I'd spilled a little I guess.
David: Got it.
James: It made a huge-
David: Got it.
James: Yeah.
David: So driving down from Fairbanks. That's gotta be quite a journey. How long did it take you?
James: Well, so I left Fairbanks and stopped off at my parents' house in Kenai. That takes you a day, maybe like 12 hours or something. I mean it's a pretty long time. I stayed at my parents' house for about a month. Did Node Knockout actually down there which is this fun programming contest. Peter, myself, and one of my friends in Alaska in Fairbanks, Josh. So it was like-
David: So all three of you were competing in this contest remotely?
James: Yeah.
Peter: Yeah, so this is like Battle Chess [crosstalk 00:19:57].
James: Yeah, it was this web-based real-time chess game, and the cool thing is you could watch everybody else's chess games from the main page. You could click on one to see it in 3D-style.
David: Nice.
James: So it was pretty much exactly like Battle Chess with the layout. You could like switch it between top view and then this sort of pseudo trapezoid-projected view.
David: Yeah, yeah, yeah, yeah.
James: Yeah, it was really fun.
David: Cool.
James: But then after that, I drove down. I think I left September 30th, and I just slept in my car the whole way. The other thing about my car besides it having plumes behind it sometimes-
David: Exciting.
James: ... was that it didn't have ... It really needed shocks, but I really didn't have the money to get them replaced.
David: It gave you a real feeling for what was going on with the road.
James: Yeah. Goodness, yes. It wasn't actually that bad for Alaska roads, but as soon as you cross over, like right at the border between Alaska and the Yukon Territory, the roads are just insane. It's just really, really bumpy and there's like potholes everywhere and it's just gravelly. Actually, the gravel parts are the good parts because the paved parts not as good.
I drove down all the way. It took me about four days driving from Kenai, where my parents are, down to ... I've some Godparents in Everette, Washington. So stayed there for a night. Then went down to my grandparents' house in Kelso, Washington. Stayed there for like ... I might have been there for maybe like four or five days, but so ... My grandpa actually helped me get my car into a bit more operable condition.
Because so I thought it would be really awesome to just jet over to Vancouver in Canada. I was headed down the Alaska Highway, and it was like in Dawson Creek and whatever, and like, "Yeah, that seems reasonable."
David: Sure.
James: It's not reasonable at all.
David: Really?
James: The road between like Whistler and ... I forget the name of the town. It was like Luluette or something. Is just the windiest most ridiculous road I've ever been on. It's got wooden bridges and they're one lane, and so you have to wait for other cars to pass, not that there were many cars because no sane motorist would take this road. And like speed limits in some places were like 20 kilometers an hour because the turns were just that severe. Going up, going down a hill was just ridiculous.
By the time that I got to Whistler, I noticed, "Hey" ... Well, I noticed this more as I was in the mountains, but, "Hey, my transmission really doesn't work as good as it used to." It became ... All of a sudden, it was an automatic, really hard to shift this thing.
David: Uh oh.
James: It made driving hard and unsafe.
David: But you made it safely.
James: But I did make it down. I took Highway 101 after Washington, and it was really nice.
Peter: I was following all these adventures in IRC. James would jump on some-
James: I would hop on at a coffee shop or whatever, when I get network and be like, "Hey, I'm in Astoria," or, "I'm in," wherever, you know?
David: Nice. So you made it down to the Bay Area ultimately like at the beginning of October?
James: Yeah, October, yeah, 3rd or some such. Actually one thing I should add ... My car, it was really hot. So the whole trip was really cold. There was actually some snow up in Canada for a bit, but as soon as I turned ... As soon as the highway turned inland, it got really hot, and my car didn't like that.
David: Uh oh.
James: By the time I got to Santa Rosa I had to just ... Well, there was really heavy traffic for the first time also in the whole trip, except for Vancouver I guess. But my whole car started smoking out of the blue, so I had to beeline it for an exit.
David: Oh my God.
James: Just had to wait for the thing to cool off because ...
David: Are you still driving this car or?
James: Yeah. No, no, no, no. It got towed away actually 'cause I couldn't move it.
David: Got it. So you made it down here. You got a place in Berkeley where you're living now.
James: Yeah, North Oakland.
David: Yeah, North Oakland.
James: Just 'cause ... Well, Peteris had a friend.
Peter: Yeah, so I had a friend called David, and I told him that James is moving down from Alaska. Do you know any place to stay? I didn't know he was in Oakland. I just knew he was somewhere in the Bay Area, so I told him, "Can you help me out and find a place for James?" And so he contacted the landlady and she had a room in the same apartment house where he lives. Yeah, and it turned out to be Oakland.
James: Yeah, so that's where I just set down.
David: Got it.
James: 'Cause I really wasn't in a position to be moving around too much with that car.
David: Right.
James: Yeah, just landing.
David: Yeah. Cool, so then you've got a place now. You're in the Bay Area, and you start coding full-time and Peter comes and joins you a few weeks later.
James: Yep.
David: So the two of you are hacking out in this ... What is it? One bedroom? Two bedroom?
James: Yeah, just a one bedroom even. It's-
Peter: Yeah.
David: You guys gotta be ... Was that the first time you had actually met in person?
James: Yeah.
Peter: Right. Yes.
David: Oh my goodness.
Peter: Well, he sounded like a good guy in our IRC conversations.
James: And some Skype. So we put together some of these videos for StackVM too [crosstalk 00:26:14].
Peter: Oh, yeah. Right. We also did some videos. Yeah, like the demo video for ... Yeah, like [crosstalk 00:26:18].
James: Goodness. So putting together videos remotely is so hard.
Peter: It took us like 16 hours to put the video together.
David: Oh my goodness.
Peter: Yeah.
David: So you guys have been living together since the end of October in North Oakland working full-time on StackVM and then also browserling?
Peter: Yes.
James: Yeah, so I just found a couch, really nice couch, and Peteris has been sleeping on it.
Peter: Yeah, I'm sleeping on the couch.
David: Is it a comfortable couch?
Peter: No, it's not.
James: We got an air mattress too, but yeah.
Peter: I don't like the air mattress.
David: Has he been sleeping on an uncomfortable couch for like five months?
Peter: Yes.
David: Have you thought about getting a bed or?
Peter: Well now that we've got funding, it's definitely a possibility.
David: So you guys started ... You had done some interesting work on StackVM, and at what point did the idea of browserling enter into the picture?
Peter: Started it October, mid-October actually.
James: Yeah.
Peter: So we submitted the application for Y-Combinator and they mentioned that we are doing browserling, but we didn't really have a prototype or anything working for the browserling.
James: Yeah, so I guess-
David: And you didn't get into Y-Combinator.
Peter: No.
James: No. Well, we were sort of in the middle of a pivot. I mean that's like the worst time to have [crosstalk 00:27:41].
David: Did they give you any feedback?
Peter: No.
James: No.
David: Okay, so they're just like, "No."
Peter: They don't give feedback.
James: Yeah.
David: Got it. So they were just like, "No, sorry." And you guys were like, "Okay, well we're gonna do this thing anyhow."
Peter: Yeah.
James: Yeah. Well, so I guess the idea for it ... I'd had a kind of vague idea about ... Something like this might be useful at some point. I didn't really know what it was gonna look like though. But I thought more that it was just something that you could do with StackVM. It wasn't really a product in itself in my mind, but then ... So I went to this meetup in Berkeley, this Hackers/Founders meetup. Pretty cool. Just a bunch of random like business and hacker types just all in the same place and just talking about stuff. And I was just showing some people.
And so we'd been posting to Hacker News and Reddit. So some people that I met there had actually heard of us before which I thought was amazing.
David: So cool.
James: Yeah.
David: "Oh, people know me!"
James: Yeah.
David: That's got to be a great moment.
James: Uh huh. Yeah, a lot of the people that ... We got a lot of feedback when we did these Hacker News posts. Also, just meeting people in person, it sounded like there was this really hard problem that made perfect sense that everybody has if they're a web developer. It's that, "Hey, you really don't want to have to care about running all of these browsers yourself. You just want to be able to sweep that under the rug."
David: "I bought a Mac and I need to test with IE6. Help."
James: Exactly.
Peter: Right, yeah.
James: That should be somebody else's problem. I mean it's-
David: And you're the "somebody else" whose problem it is.
James: "Hey, well there's somebody else." Yeah.
David: Very, very cool. Sweet. So then it became clear at that point that there was a real business to be had in doing in-browser testing.
Peter: Yes.
James: Yeah, so I took like $10 or whatever. I didn't have much money left, but I just spent like 20 minutes coming up with names, and landed on browserling. And it's like, "Whatever. I just need a domain for this," because then we're sort of-
David: Then you're launched.
James: Yeah.
David: Yeah.
James: Yeah, so we actually launched that really fast.
Peter: Yeah, so-
James: It was surprising how fast we launched that thing.
Peter: And-
James: Yeah, I think I started ... I like get git init'd on the October 18th or something for browserling.
Peter: Yeah, and then we launched on November 24th.
David: Nice.
James: And did a Hacker's News post. We had this queue thing also which got to be insanely long, like 100 people or something.
David: So you had 100 people who were waiting to start using the product, who were just sitting in front of their browsers twiddling their thumbs.
James: Yeah. We actually had five servers, queued up five desktops with the browsers loaded that you could use for that, but because of a bug in our routing software, I think we were only using one. But that was ... Yeah. Yeah.
David: Cool, so-
James: It's been fixed, but ...
David: Got it. Got it. So then use of your product is continuing to increase. Today, you actually closed your first round of funding.
James: Yeah, thanks for that.
Peter: Right, yeah.
David: Super cool. So what was that like for you guys to try and negotiate the waters of getting other people's money for the first time?
Peter: Yeah, so we have been going to these Hackers/Founders meetups, and we met Jonathan Nelson who is organizing the event. He started introducing us around to other people with a note that we are looking for funding. Yeah, so we met Adam Rifkin also at Hackers/Founders. And then Adam introduced us to you.
David: Yeah.
Peter: Right. Yeah, that's how we met you.
James: Yeah, of course there were all of these other weeds that-
David: Yeah. Yeah.
Peter: Yeah.
James: Oh goodness. So I guess it was a really big shift going from just hacking and doing nothing else pretty much to going out and meeting people and felt like it really sucks your energy-
David: It does.
James: ... to have to wake up ... Well, I guess this is more ... To have to wake up at a semi-regular schedule like normal people. I don't really do that, so it was especially harrowing.
David: What kind of hours do you normally keep?
James: Yeah, I don't even know. They drift and I don't try to fight it 'cause when I try to fight it, I just feel sleepy all day, and yeah.
David: Do you find your days are like 30 hours long then, or like-
James: They're not that long. They're over 24. Maybe 26ish.
David: Okay.
James: Yeah. But they drift a lot. It's not like there's any pattern to it.
David: So you just basically ... You go to sleep when you feel tired. You wake up when you're ready to wake up. You work when you work.
James: Yeah.
David: And you just kind of just roll with it.
James: Yeah, well I think with programming, especially the crazy kinds of programming that we've been doing, you really have to be in the right mindset for that. You really have to have a good motivational drive and it's-
David: Could you explain to a non-programmer why the kind of programming that you're doing is so crazy.
James: Well, so I guess with browserling, we've ... This is sort of a continuation of some of the design choices that we've been doing previously, but like to an even greater degree. But basically how we structure our coding at browserling is we have our core codebase and we ... Every chance that we can get to abstract out some big chunk to make the core nicer, we take that. For instance, I've got like 90 projects on my GitHub right now. And-
Peter: Yeah, I have like 83.
James: Yeah, and I've got like-
David: You've divided up the project into lots of these little sub-projects.
James: Yeah.
Peter: All of them are already usable.
James: Yeah, so other people can use these things. It's like dnode, our RPC system, is on NPM, the Node package manager, and all of these little projects that other people can use. I think it's really great because, you know, not only are you contributing to the community, which is great, but of course we're running a business. What do we care about altruism? I guess the really bottom line kind of way to think about this is all of the complexity that you can take out of your project and host just completely outside of it is code that you don't have to think about anymore. You can just focus on the parts that are very unique and specific to your application.
Peter: Yeah. Yeah.
James: It makes the motivational picture so much different. So one-
Peter: Yeah, so each time you create a new project, like a new submodule, it's like a new project and you are very enthusiastic about it and just start coding it from start to finish 'cause it's not that large.
James: Yeah, the scope is really limited and manageable, and you get these sorts of iterative feedback right away when you're just taking a small piece of it out. That's what people say a lot when they say, "Oh, modular programming. That's great. How's that any different?" But I mean, when you actually take that piece out of your codebase altogether, like not even in a lib folder or something, it's different because ... Especially if you throw it up on GitHub, and especially if you throw it up on a package manager like NPM.
Peter: Yes, then you have good documentation for it and good tests.
James: Yeah, and there's like this latent implicit social pressure to make it good, to make it reusable, and to not increase the scope beyond what it should do. And I think that's really powerful too.
David: Interesting. How do you decide what to publish out there on GitHub and what to keep as proprietary?
Peter: So we did StackVM. StackVM was originally all opensource, but it's really hard for the users to install 'cause there are all kinds of tricks you have to do.
James: Yeah.
David: 100 packages for the [crosstalk 00:35:45].
Peter: Right, yeah. [crosstalk 00:35:47] packages and then all kinds of siblings between the libraries.
James: Yeah, and just the setup for this. I don't even know that that problem is going to go away because it's just such an intrinsically hard problem to configure some virtual environment and to get everything that you need to get running well on the servers that you happen to have. It's just really, really hard, and that's something that I think led us to conclude that, "Hey, we should be doing this for our users," with something like browserling.
David: Got it.
Peter: Yeah, but then browserling is closed source, so the core stuff like all the queuing system and the [crosstalk 00:36:27].
James: Yeah, all of our crazy back-end message passing and token passing system. That's all-
Peter: That's all closed sourced. But then we're using all these opensource modules that we wrote.
James: Yeah, and so we just spin them off when we think that they should be open because they're just this reusable piece. I mean, it's good for us, for our bottom line, as I mentioned, with our motivation. It's good for visibility in the community too. I mean this is a product for developers.
Peter: Yes.
James: So it'd be awesome if they've heard of us one way or another.
David: What do you want to do with it? Where do you guys want to go with it? Imagine it's five years from now, not even like 6 months. Where's browserling? Where are you guys?
Peter: Huh.
James: Yeah.
Peter: So we'll definitely keep building it, browserling, for a few years and then just see what happens. Maybe we have a acquisition offer that we can't just resist, or maybe we'll spin off some more projects based on top of StackVM because we have the StackVM technology. We have had a lot of ideas how we can use StackVM.
James: Yeah, well so I don't know about predicting too far out because I mean this problem seems like a really neglected important problem.
David: That's right.
James: As a result of that, there's so much stuff that people haven't done yet because nobody's even been thinking about it.
David: Got it. No, I mean that totally makes sense. I'm curious about your personal aspirations.
James: Oh, personal aspirations. Well I guess I'd like to get a bit more into robotics. I thought the stuff I did in Hawaii and down in San Diego was just amazingly fun, especially when I had to wear so many hats, etching the boards and designing them in Inkscape of all things 'cause we were using a laser printer to iron on the designs.
David: Nice.
James: And doing that, doing mechanical stuff, doing ... So I really-
David: Just continuing to push yourself in lots of different [crosstalk 00:38:29].
James: Yeah, I really like pushing myself into stuff that I really don't know what I'm doing and I just kind of figure it out.
Peter: Well, I'm actually not sure. I haven't figured out. So with browserling and then ... I'm not really sure. Whatever falls, whatever I feel like doing.
David: Cool.
James: Yeah.
David: Cool. Well, I'm really excited to see you guys working on an important problem that nobody else is doing a good job tackling. Just to see a pair of people from such different backgrounds and so passionate about technology and art and helping other people.
Peter: Yeah.
David: I'm really excited to have backed you guys.
Peter: Thanks.
David: Thanks so much for letting me participate.
Peter: Yeah.
David: Cool. All right. Well, thanks guys.
Peter: Yeah, thanks.
James: Bye.

There are two ways you can change file permissions in Unix - one is using chmod's symbolic (text) modes (like chmod ug+x file), the other is using the octal modes (like chmod 0660 file). It turns out that symbolic modes are more powerful because you can mask out the permission bits you want to change! Octal permission modes are absolute and can't be used to change individual bits. Octal modes are also sometimes called absolute because of that.

Here is an example that illustrates that.

Suppose you have this file,

$ ls -las file
0 -rw-rw----  1 pkrumins  cats  0 Feb 25 12:49 file

and you want to set the execute x bit for everyone. If you use symbolic modes, you can just do,

$ chmod a+x file
$ ls -las file
0 -rwxrwx--x  1 pkrumins  cats  0 Feb 25 12:49 file

But, if you're used only to absolute modes, then you first need to calculate the existing permission mask, which would be 0660, and then calculate the new one by adding the 1 to each group, so the end result would be 0771,

$ chmod 0771 file
$ ls -las file
0 -rwxrwx--x  1 pkrumins  cats  0 Feb 25 12:49 file

It's still easy with octal modes, but why do it the harder way when you can just chmod a+x file, right?

I'd also like to note that symbolic modes are a feature of chmod utility. If you look at chmod system call, it only takes the octal mode. The chmod utility first does a stat to determine the existing mode, then calculates the new one. It does the calculation for you. So don't do it again yourself!