<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  <title type="text">good coders code, great reuse</title>
  <id>http://www.catonmat.net/feed</id>
  <updated>2012-05-07T18:09:26Z</updated>
  <link href="http://www.catonmat.net" />
  
  <author>
    <name>Peteris Krumins</name>
    <uri>http://www.catonmat.net/about</uri>
    <email>peter@catonmat.net</email>
  </author>
  <subtitle type="text">Peteris Krumins' blog about programming, hacking, software reuse, software ideas, computer security, google and technology.</subtitle>
  <icon>http://www.catonmat.net/favicon.ico</icon>
  <generator uri="http://www.catonmat.net" version="v1.0">catonmat blog</generator>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/catonmat" /><feedburner:info uri="catonmat" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>catonmat</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Introduction to Perl one-liners</title>
    <id>318</id>
    <updated>2012-05-07T18:09:26Z</updated>
    <published>2012-05-07T18:10:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/Iz56h5ZrLJw/introduction-to-perl-one-liners" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/b3LdDPGJMIFUGJ8c5mE9fK8vgmU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/b3LdDPGJMIFUGJ8c5mE9fK8vgmU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/b3LdDPGJMIFUGJ8c5mE9fK8vgmU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/b3LdDPGJMIFUGJ8c5mE9fK8vgmU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="c" style="float: right; margin-left: 5px; padding-bottom: 0"&gt;&lt;p&gt;&lt;a href="http://www.catonmat.net/blog/perl-book/" class="nohover" title="Perl One-Liners Explained"&gt;&lt;img src="http://www.catonmat.net/images/perl-book/cover.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;&lt;a href="http://www.catonmat.net/blog/perl-book/"&gt;perl book&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This is &lt;strong&gt;the introduction to perl one-liners&lt;/strong&gt;. Originally I wrote this introduction for my &lt;a href="http://www.catonmat.net/blog/perl-book/"&gt;third e-book&lt;/a&gt;, however later I decided to make it a part of the &lt;a href="http://www.catonmat.net/download/perlbook-preview.pdf"&gt;free e-book preview&lt;/a&gt; and republish it here as this article.&lt;/p&gt;
&lt;h2&gt;Introduction to Perl one-liners&lt;/h2&gt;
&lt;p&gt;Perl one-liners are small and awesome Perl programs that fit in a single line of code and they do one thing really well. These things include changing line spacing, numbering lines, doing calculations, converting and substituting text, deleting and printing certain lines, parsing logs, editing files in-place, doing statistics, carrying out system administration tasks, updating a bunch of files at once, and many more. Perl one-liners will make you the shell warrior. Anything that took you minutes to solve, will now take you seconds!&lt;/p&gt;
&lt;p&gt;Let's look at several examples to get more familiar with one-liners. Here is one:&lt;/p&gt;
&lt;pre &gt;
perl -pi -e 's/you/me/g' file
&lt;/pre&gt;
&lt;p&gt;This one-liner replaces all occurrences of the text &lt;code&gt;you&lt;/code&gt; with &lt;code&gt;me&lt;/code&gt; in the file &lt;code&gt;file&lt;/code&gt;. Very useful if you ask me. Imagine you are on a remote server and have this file and you need to do the replacement. You can either open it in text editor and execute find-replace or just do it through command line and, bam, be done with it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-e&lt;/code&gt; argument is the best argument. It allows you to specify the Perl code to be executed right on the command line. In this one-liner the code says, do the substitution (&lt;code&gt;s/find/replace/flags&lt;/code&gt; command) and replace &lt;code&gt;you&lt;/code&gt; with &lt;code&gt;me&lt;/code&gt; globally (&lt;code&gt;g&lt;/code&gt; flag). The &lt;code&gt;-p&lt;/code&gt; argument makes sure the code gets executed on every line, and that the line gets printed out after that. The &lt;code&gt;-i&lt;/code&gt; argument makes sure that &lt;code&gt;file&lt;/code&gt; gets edited in-place, meaning Perl opens the file, executes the substitution for each line, prints the output to a temporary file, and then replaces the original file.&lt;/p&gt;
&lt;p&gt;How about doing the same replacement in multiple files? Just specify them on the command line!&lt;/p&gt;
&lt;pre &gt;
perl -pi -e 's/you/me/g' file1 file2 file3
&lt;/pre&gt;
&lt;p&gt;Now let's do the same replacement only on lines that match &lt;code&gt;we&lt;/code&gt;. It's as simple as this:&lt;/p&gt;
&lt;pre &gt;
perl -pi -e 's/you/me/g if /we/' file
&lt;/pre&gt;
&lt;p&gt;Here we use the conditional &lt;code&gt;if /we/&lt;/code&gt;. This makes sure that &lt;code&gt;s/you/me/g&lt;/code&gt; gets executed only on lines that match the regular expression &lt;code&gt;/we/&lt;/code&gt;. The regular expression here can be anything. Let's say you want to execute the substitution only on lines that have digits in them. You can then use the &lt;code&gt;/\d/&lt;/code&gt; regular expression that matches numbers:&lt;/p&gt;
&lt;pre &gt;
perl -pi -e 's/you/me/g if /\d/' file
&lt;/pre&gt;
&lt;p&gt;Now how about finding all repeated lines in a file?&lt;/p&gt;
&lt;pre &gt;
perl -ne 'print if $a{$_}++' file
&lt;/pre&gt;
&lt;p&gt;This one-liner records the lines seen so far in the &lt;code&gt;%a&lt;/code&gt; hash and keeps the counter of how many times it has seen the same line. The &lt;code&gt;$a{$_}++&lt;/code&gt; creates elements in the &lt;code&gt;%a&lt;/code&gt; hash automagically. When it sees a repeated line, the value of that hash element is defined and greater than zero, so &lt;code&gt;if $a{$_}&lt;/code&gt; is true, and it prints the line. This one-liner also uses the &lt;code&gt;-n&lt;/code&gt; command line argument that loops over the input but unlike &lt;code&gt;-p&lt;/code&gt; doesn't print the lines automatically, so you have to use &lt;code&gt;print&lt;/code&gt; explicitly.&lt;/p&gt;
&lt;p&gt;How about numbering lines? Super simple! Perl has the &lt;code&gt;$.&lt;/code&gt; special variable that automatically maintains the current line number. You can just print it out together with the line:&lt;/p&gt;
&lt;pre &gt;
perl -ne 'print "$. $_"'
&lt;/pre&gt;
&lt;p&gt;You can also achieve the same by using &lt;code&gt;-p&lt;/code&gt; argument and modifying the &lt;code&gt;$_&lt;/code&gt; variable, which contains the entire line:&lt;/p&gt;
&lt;pre &gt;
perl -pe '$_ = "$. $_"'
&lt;/pre&gt;
&lt;p&gt;Here each line gets replaced by the string &lt;code&gt;"$. $_"&lt;/code&gt;, which is the current line number followed by the line itself.&lt;/p&gt;
&lt;p&gt;How about we combine the previous two one-liners and create one that numbers repeated lines? Here we go:&lt;/p&gt;
&lt;pre &gt;
perl -ne 'print "$. $_" if $a{$_}++'
&lt;/pre&gt;
&lt;p&gt;Now let's do something different. Let's sum up all the numbers on each line. We'll use the &lt;code&gt;sum&lt;/code&gt; function from the &lt;code&gt;List::Util&lt;/code&gt; CPAN module. You can install it as easily as running &lt;code&gt;perl -MCPAN -e'install List::Util'&lt;/code&gt;.&lt;/p&gt;
&lt;pre &gt;
perl -MList::Util=sum -alne 'print sum @F'
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;-MList::Util&lt;/code&gt; command line argument imports the &lt;code&gt;List::Util&lt;/code&gt; module, and the &lt;code&gt;=sum&lt;/code&gt; part of it imports the &lt;code&gt;sum&lt;/code&gt; function from it. Next &lt;code&gt;-a&lt;/code&gt; enables automatic splitting of fields into the &lt;code&gt;@F&lt;/code&gt; array. The &lt;code&gt;-l&lt;/code&gt; argument makes sure that &lt;code&gt;print&lt;/code&gt; outputs a newline at the end of each line. Finally the &lt;code&gt;sum @F&lt;/code&gt; sums up all the elements in the &lt;code&gt;@F&lt;/code&gt; list and &lt;code&gt;print&lt;/code&gt; prints it out, followed by a newline (that was added by the &lt;code&gt;-l&lt;/code&gt; argument).&lt;/p&gt;
&lt;p&gt;How about finding the date 1299 days ago? That's also solvable by a simple one-liner:&lt;/p&gt;
&lt;pre &gt;
perl -MPOSIX -le '
  @now = localtime;
  $now[3] -= 1299;
  print scalar localtime mktime @now
'
&lt;/pre&gt;
&lt;p&gt;This one-liner didn't quite fit in one line, but that's just because my blog has narrow space for content. What happens here is we modify the 4th element of the structure returned by &lt;code&gt;localtime&lt;/code&gt;, which happens to be days. So we just subtract 1299 days from the current day. Then we reassembles it into a new time through &lt;code&gt;localtime mktime @now&lt;/code&gt; and print it in scalar context that prints human readable time.&lt;/p&gt;
&lt;p&gt;How about generating an 8 letter password? Again, solvable elegantly with a one-liner:&lt;/p&gt;
&lt;pre &gt;
perl -le 'print map { (a..z)[rand 26] } 1..8'
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;a..z&lt;/code&gt; generates a list of letters from a to z (total 26). Then we randomly choose one of the characters through generating a random number in range 0-25, and then we repeat this whole process 8 times!&lt;/p&gt;
&lt;p&gt;Here is another one. Suppose you want to quickly find the decimal number that corresponds to an IP address. You can use the &lt;code&gt;unpack&lt;/code&gt; function and find it really quickly:&lt;/p&gt;
&lt;pre &gt;
perl -le 'print unpack("N", 127.0.0.1)'
&lt;/pre&gt;
&lt;p&gt;This one-liner uses a vstring, which is a version literal. The IP address &lt;code&gt;127.0.0.1&lt;/code&gt; is treated as a vstring, which is basically the numbers &lt;code&gt;127&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt; concatenated together. Next the &lt;code&gt;unpack&lt;/code&gt; function unpacks them to a single decimal number.&lt;/p&gt;
&lt;p&gt;Btw, I once created a cheat sheet with all the &lt;code&gt;pack/unpack&lt;/code&gt; format strings. Get it here: &lt;a href="http://www.catonmat.net/blog/perl-pack-unpack-printf-cheat-sheet/"&gt;perl pack, unpack cheat sheet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now how about calculations? Let's find the sum of the numbers in the first column:&lt;/p&gt;
&lt;pre &gt;
perl -lane '$sum += $F[0]; END { print $sum }'
&lt;/pre&gt;
&lt;p&gt;Here the lines automatically get split up into fields through the &lt;code&gt;-a&lt;/code&gt; argument. The fields can be now accessed through the &lt;code&gt;@F&lt;/code&gt; array. The first element of the array, &lt;code&gt;$F[0]&lt;/code&gt;, is the first column. So all we have to do is sum all the columns up through &lt;code&gt;$sum += $F[0]&lt;/code&gt;. When the Perl program ends its job, it executes any code in the special &lt;code&gt;END&lt;/code&gt; block. In this case we print out the total sum there. Really easy!&lt;/p&gt;
&lt;p&gt;Now let's find out how many packets have gone through all the &lt;code&gt;iptables&lt;/code&gt; rules. It's this simple:&lt;/p&gt;
&lt;pre &gt;
iptables -L -nvx | perl -lane '
  $_ = $F[0]; $pkts += $_ if /^\d/; END { print $pkts }
'
&lt;/pre&gt;
&lt;p&gt;The iptables program outputs the packets as the first field. All we do is check if the first field is numeric (because it also outputs labels header), and if so, sum the packets up on the first column, just like in the previous one-liner.&lt;/p&gt;
&lt;p&gt;How about getting a list of the names of all users on the system?&lt;/p&gt;
&lt;pre &gt;
perl -a -F: -lne 'print $F[4]' /etc/passwd
&lt;/pre&gt;
&lt;p&gt;Combining &lt;code&gt;-a&lt;/code&gt; with &lt;code&gt;-F&lt;/code&gt; argument allows you to specify the character that lines should be split on. In this case it's the colon, which is the record separator of &lt;code&gt;/etc/passwd&lt;/code&gt;. Next we just print the 5th field &lt;code&gt;$F[4]&lt;/code&gt;, which is the real name of the user. Really quick and easy.&lt;/p&gt;
&lt;p&gt;As you can see, knowing Perl one-liners lets you accomplish many tasks quickly. If you wish to learn more and become really fast in the shell, I suggest you get a copy of my "&lt;a href="http://www.catonmat.net/blog/perl-book/"&gt;Perl One-Liners Explained&lt;/a&gt;" e-book. The e-book contains 130 unique one-liners and many of them are presented in several different ways, so the total number of one-liners in this book is over 200.&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;a href="http://www.catonmat.net/blog/perl-book/" class="nohover" title="Perl One-Liners Explained"&gt;&lt;img src="http://www.catonmat.net/images/perl-book/cover.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;&lt;a href="http://www.catonmat.net/blog/perl-book/"&gt;perl book&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;If you enjoy my writing, you can &lt;a href="http://www.catonmat.net/feed/"&gt;subscribe&lt;/a&gt; to my blog, follow me on &lt;a href="http://twitter.com/pkrumins"&gt;Twitter&lt;/a&gt; or &lt;strong&gt;&lt;a href="https://plus.google.com/102155999275405024037"&gt;&lt;span style="color: blue"&gt;G&lt;/span&gt;&lt;span style="color: red"&gt;o&lt;/span&gt;&lt;span style="color: #EE9A00"&gt;o&lt;/span&gt;&lt;span style="color: blue"&gt;g&lt;/span&gt;&lt;span style="color: green"&gt;l&lt;/span&gt;&lt;span style="color: red"&gt;e&lt;/span&gt;&lt;span style="color: gray"&gt;+&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Iz56h5ZrLJw:hs_8UcNvx4I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Iz56h5ZrLJw:hs_8UcNvx4I:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=Iz56h5ZrLJw:hs_8UcNvx4I:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Iz56h5ZrLJw:hs_8UcNvx4I:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=Iz56h5ZrLJw:hs_8UcNvx4I:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Iz56h5ZrLJw:hs_8UcNvx4I:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Iz56h5ZrLJw:hs_8UcNvx4I:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/Iz56h5ZrLJw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/introduction-to-perl-one-liners</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">A quine in node.js</title>
    <id>320</id>
    <updated>2012-05-01T14:44:39Z</updated>
    <published>2012-05-01T14:30:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/acAtIWDe7Jg/quine-in-node" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/-eAAe-fqZ7mIT5lvM6k3QbTBUJY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-eAAe-fqZ7mIT5lvM6k3QbTBUJY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/-eAAe-fqZ7mIT5lvM6k3QbTBUJY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-eAAe-fqZ7mIT5lvM6k3QbTBUJY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I remembered about &lt;a href="http://en.wikipedia.org/wiki/Quine_(computing)"&gt;quines&lt;/a&gt; today and as I hadn't ever written one before, I decided to write a quine in javascript for node.js. A quine is a computer program which takes no input and produces a copy of its own source code as its only output.&lt;/p&gt;
&lt;p&gt;Turns out it was easier than expected. The key idea in writing a quine is having data that contains the whole program, which is then modified to match the program and printed.&lt;/p&gt;
&lt;p&gt;Here is how my quine for node.js looks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;module.exports = function () { console.log(\&amp;quot;var data = \\\&amp;quot;%s\\\&amp;quot;\\n%s\&amp;quot;, data.replace(/\\\\/g, \&amp;quot;\\\\\\\\\&amp;quot;).replace(/\&amp;quot;/g, \&amp;quot;\\\\\\\&amp;quot;\&amp;quot;), data.replace(/{/, \&amp;quot;{\\n   \&amp;quot;).replace(/}$/, \&amp;quot;\\n}\&amp;quot;)); }&amp;quot;&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;var data = \&amp;quot;%s\&amp;quot;\n%s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\\/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;\\\\&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;quot;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;\\\&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/{/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;{\n   &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/}$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;\n}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If you require this module and call the exported function, you get the same module back:&lt;/p&gt;
&lt;pre &gt;
&gt; require('./index.js')()
&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;module.exports = function () { console.log(\&amp;quot;var data = \\\&amp;quot;%s\\\&amp;quot;\\n%s\&amp;quot;, data.replace(/\\\\/g, \&amp;quot;\\\\\\\\\&amp;quot;).replace(/\&amp;quot;/g, \&amp;quot;\\\\\\\&amp;quot;\&amp;quot;), data.replace(/{/, \&amp;quot;{\\n   \&amp;quot;).replace(/}$/, \&amp;quot;\\n}\&amp;quot;)); }&amp;quot;&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;var data = \&amp;quot;%s\&amp;quot;\n%s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\\/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;\\\\&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;quot;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;\\\&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/{/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;{\n   &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/}$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;\n}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Node-quine on my github: &lt;a href="https://github.com/pkrumins/node-quine"&gt;https://github.com/pkrumins/node-quine&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Update&lt;/h2&gt;
&lt;p&gt;Turns out a quine in node.js that prints itself can be written much simpler this way (by &lt;a href="http://twitter.com/#!/maciejmalecki"&gt;maciejmalecki&lt;/a&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;quine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;quine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="http://www.substack.net"&gt;SubStack&lt;/a&gt; came up with this solution:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;(&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;)()&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})()&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And here is &lt;a href="https://github.com/mjor"&gt;Erik Lundin&lt;/a&gt;'s quine:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;module.exports = &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/isaacs"&gt;Isaacs&lt;/a&gt; offers this version of qunie that adds cli support. However this doesn't count as quine is not allowed to read the source file of itself. But I'm including it here anyway as it's fun:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;fs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;utf8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Hooray for quines!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=acAtIWDe7Jg:SCk8d2uRDh0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=acAtIWDe7Jg:SCk8d2uRDh0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=acAtIWDe7Jg:SCk8d2uRDh0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=acAtIWDe7Jg:SCk8d2uRDh0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=acAtIWDe7Jg:SCk8d2uRDh0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=acAtIWDe7Jg:SCk8d2uRDh0:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=acAtIWDe7Jg:SCk8d2uRDh0:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/acAtIWDe7Jg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/quine-in-node</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">A poem about division from Hacker's Delight</title>
    <id>316</id>
    <updated>2012-04-21T23:05:39Z</updated>
    <published>2012-04-21T21:50:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/lb5yAZbXGgA/poem-from-hackers-delight" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/xj6wCrj34sUI_CKEe3O1FroFPX8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xj6wCrj34sUI_CKEe3O1FroFPX8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/xj6wCrj34sUI_CKEe3O1FroFPX8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xj6wCrj34sUI_CKEe3O1FroFPX8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I was re-reading &lt;a href="http://www.amazon.com/Hackers-Delight-Henry-S-Warren/dp/0201914654?tag=catonmat-20"&gt;Hacker's Delight&lt;/a&gt; and on page 202 I found a poem about division that I had forgotten about.&lt;/p&gt;
&lt;center&gt;&lt;p&gt;I think that I shall never envision&lt;br&gt;
An op unlovely as division.&lt;/p&gt;
&lt;p&gt;An op whose answer must be guessed&lt;br&gt;
And then, through multiply, assessed;&lt;/p&gt;
&lt;p&gt;An op for which we dearly pay,&lt;br&gt;
In cycles wasted every day.&lt;/p&gt;
&lt;p&gt;Division code is often hairy;&lt;br&gt;
Long division's downright scary.&lt;/p&gt;
&lt;p&gt;The proofs can overtax your brain,&lt;br&gt;
The ceiling and floor may drive you insane.&lt;/p&gt;
&lt;p&gt;Good code to divide takes a Knuthian hero,&lt;br&gt;
But even God can't divide by zero!&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Henry S. Warren, author of &lt;a href="http://www.amazon.com/Hackers-Delight-Henry-S-Warren/dp/0201914654?tag=catonmat-20"&gt;Hacker's Delight&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=lb5yAZbXGgA:O-5adimPQkg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=lb5yAZbXGgA:O-5adimPQkg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=lb5yAZbXGgA:O-5adimPQkg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=lb5yAZbXGgA:O-5adimPQkg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=lb5yAZbXGgA:O-5adimPQkg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=lb5yAZbXGgA:O-5adimPQkg:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=lb5yAZbXGgA:O-5adimPQkg:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/lb5yAZbXGgA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/poem-from-hackers-delight</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">The curious case of the DES algorithm</title>
    <id>315</id>
    <updated>2012-04-21T01:54:26Z</updated>
    <published>2012-04-19T16:50:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/VuGEyoXSBko/curious-case-of-des-algorithm" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/YO_X2UBzLgYtSywgW2E_b93bviQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YO_X2UBzLgYtSywgW2E_b93bviQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/YO_X2UBzLgYtSywgW2E_b93bviQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YO_X2UBzLgYtSywgW2E_b93bviQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I was implementing password authentication for VNC in node.js the other day and faced a problem where it would just never successfully authenticate. I checked my implementation several times and it seemed fine. Then I tried to implement it in Python just to see if I was missing something obvious. It also didn't work. Then I tried doing the authentication through openssl and it was also giving a result I didn't expect. Finally I found some old C code and wrote &lt;a href="https://github.com/pkrumins/node-des"&gt;node-des&lt;/a&gt;, which worked. I still haven't figured out why it didn't work in node, python and openssl. Perhaps my readers can help me understand what was going on!&lt;/p&gt;
&lt;p&gt;Here is a quick overview of how VNC password authentication works. On the VNC server you set the authentication password. When a VNC client connects, the VNC server generates random 16 byte garbage called challenge and sends it to the client. The client DES encrypts the challenge with the password as the key. The result is called the response and is also 16 bytes in size. The client then sends it to the VNC server. The VNC server then also DES encrypts challenge with the password and compares it with the response. If challenge matches response, the session gets authenticated.&lt;/p&gt;
&lt;p&gt;Let's say the password set on the VNC server is &lt;code&gt;browsers&lt;/code&gt;, and the challenge that the VNC server sends to the client is the following 16 bytes:&lt;/p&gt;
&lt;pre &gt;
0c fd 6b 8c 5c 04 b3 e5 01 40 b9 de 33 9e 0d db
&lt;/pre&gt;
&lt;p&gt;Then DES encrypting these 16 bytes with the password &lt;code&gt;browsers&lt;/code&gt; should produce the following response:&lt;/p&gt;
&lt;pre &gt;
44 ee fc 48 83 bb 95 f1 c0 82 c3 e2 98 c3 6a 4a
&lt;/pre&gt;
&lt;p&gt;I sniffed this data from a real VNC client - VNC server communication and I use this as a test case for &lt;a href="https://github.com/pkrumins/node-des"&gt;node-des&lt;/a&gt; as it's the correct result. However now let's look at what happens if I encrypt the challenge with node's crypto module, with Python and with openssl.&lt;/p&gt;
&lt;p&gt;First node's crypto module. I wrote the following program to DES encrypt the 16 challenge challenge bytes with the password &lt;code&gt;browsers&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;crypto&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
   &lt;span class="mh"&gt;0x0c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x6b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x8c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x5c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x04&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xb3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xe5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xb9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xde&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x9e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xdb&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createCipher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;des&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;browsers&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When I run it, it produces 27 byte long output and it's not what I'd expect:&lt;/p&gt;
&lt;pre &gt;
&amp;lt;Buffer c3 a9 72 c2 8b c3 a2 10 56 c2 8f c3 94 12 c2 a3 c3 a3 33 c2 ba c3 9e c2 a7 c2 96&gt;
&lt;/pre&gt;
&lt;p&gt;So node.js doesn't produce the expected 16 byte result. In fact I tried all the possible variations of the des algorithm that openssl (which node.js bases its crypto module on) supports. Perhaps I chose the wrong des implementation as there are many?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;crypto&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
   &lt;span class="mh"&gt;0x0c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x6b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x8c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x5c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x04&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xb3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xe5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xb9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xde&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x9e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xdb&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;algos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;des des-cbc des-cfb des-ecb des-ede &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;des-ede-cbc des-ede-cfb des-ede-ofb &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;des-ede3 des-ede3-cbc des-ede3-cfb &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;des-ede3-ofb des-ofb des3 desx&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\s+/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;algos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;algo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;algo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createCipher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;algo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;browsers&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Crypto doesn&amp;#39;t support:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;algo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It produced the following output and not a single result was what I'd expect:&lt;/p&gt;
&lt;pre &gt;
des
&amp;lt;Buffer c3 a9 72 c2 8b c3 a2 10 56 c2 8f c3 94 12 c2 a3 c3 a3 33 c2 ba c3 9e c2 a7 c2 96&gt;
des-cbc
&amp;lt;Buffer c3 a9 72 c2 8b c3 a2 10 56 c2 8f c3 94 12 c2 a3 c3 a3 33 c2 ba c3 9e c2 a7 c2 96&gt;
des-cfb
&amp;lt;Buffer 24 43 c2 99 11 c2 8c c3 ac c3 b2 42 c3 b1 77 c3 a2 c2 96 05 c3 b3 c3 94 02&gt;
des-ecb
&amp;lt;Buffer c2 aa 09 c3 98 c3 92 c2 8c 69 68 c2 97 c2 88 09 c2 ae c3 89 4f 3f c3 9f c3 83&gt;
des-ede
&amp;lt;Buffer c2 84 c2 86 3f c3 ba 2b c2 ba 4b c2 bd 50 05 c3 a8 c3 9d 37 66 15 51&gt;
des-ede-cbc
&amp;lt;Buffer 7d 60 c2 8d 4e 27 c3 b2 0f 6f 0e 48 54 60 38 2e c2 b3 7e&gt;
des-ede-cfb
&amp;lt;Buffer 43 4d c2 ac 19 c3 92 c2 81 c2 a2 3f c2 9a c2 be c2 8a c2 b3 72 44 37 34&gt;
des-ede-ofb
&amp;lt;Buffer 43 4d c2 ac 19 c3 92 c2 81 c2 a2 3f 49 c3 a4 04 24 2c 77 05 40&gt;
des-ede3
&amp;lt;Buffer c2 a4 c2 84 c2 b2 2e 45 c2 90 c2 af c2 9c 21 5b c2 bd c3 aa c2 84 c3 9b 4c 76&gt;
des-ede3-cbc
&amp;lt;Buffer c3 81 5c c2 b9 28 c2 be c3 b6 74 c3 89 c3 89 c2 8c 62 c2 ab 3a c2 95 6c 3f&gt;
des-ede3-cfb
&amp;lt;Buffer 3f c3 8d 22 c3 8e 5d 01 29 c2 8b c2 85 c2 b5 11 75 6f c2 b5 5b c3 9c&gt;
des-ede3-ofb
&amp;lt;Buffer 3f c3 8d 22 c3 8e 5d 01 29 c2 8b c2 8c 64 51 c2 8e c2 a7 2f c2 a8 c2 97&gt;
des-ofb
&amp;lt;Buffer 24 43 c2 99 11 c2 8c c3 ac c3 b2 42 09 68 1b c3 bd 2d 79 c2 ba c3 a1&gt;
des3
&amp;lt;Buffer c3 81 5c c2 b9 28 c2 be c3 b6 74 c3 89 c3 89 c2 8c 62 c2 ab 3a c2 95 6c 3f&gt;
desx
&amp;lt;Buffer 4c 45 c2 bb c2 bd 78 c2 bd c3 b5 c2 b9 c3 96 c3 b7 c3 b0 6d c3 b9 c3 8d c3 a9 2d&gt;
&lt;/pre&gt;
&lt;p&gt;I had no idea what was going on at this point, so I decided to try Python and see if I can get the result I expect through Python's DES algorithm. Worst case I could spawn Python each time I need to authenticate at VNC. I used the &lt;a href="http://twhiteman.netfirms.com/des.html"&gt;pyDes&lt;/a&gt; module for my experiment and installed it to virtualenv as following:&lt;/p&gt;
&lt;pre &gt;
$ virtualenv pydes
$ cd pydes
$ . ./bin/activate
$ easy_install pydes
&lt;/pre&gt;
&lt;p&gt;Then I wrote the following test program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pyDes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;des&lt;/span&gt;

&lt;span class="n"&gt;challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\x0c\xfd\x6b\x8c&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; \
            &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\x5c\x04\xb3\xe5&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; \
            &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\x01\x40\xb9\xde&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; \
            &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\x33\x9e\x0d\xdb&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;des&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;browsers&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0x&lt;/span&gt;&lt;span class="si"&gt;%x&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The output was 16 bytes but not what I'd expect:&lt;/p&gt;
&lt;pre &gt;
['0xd0', '0x6f', '0x0', '0x1a', '0x73', '0xb8', '0x24', '0xc6', '0xf1', '0x72', '0x81', '0x6e', '0x6d', '0x59', '0xc8', '0xa7']
&lt;/pre&gt;
&lt;p&gt;Then I thought, perhaps the endianness was incorrect, so I reversed the words in the challenge:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pyDes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;des&lt;/span&gt;

&lt;span class="n"&gt;challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\xfd\x0c\x8c\x6b&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; \
            &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\x04\x5c\xe5\xb3&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; \
            &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\x40\x01\xde\xb9&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; \
            &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\x9e\x33\xdb\x0d&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;des&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;browsers&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0x&lt;/span&gt;&lt;span class="si"&gt;%x&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;But no, this was also giving some other result that wouldn't work with VNC:&lt;/p&gt;
&lt;pre &gt;
['0x2e', '0xe8', '0xec', '0x7c', '0xde', '0xf7', '0x36', '0x56', '0xf0', '0x60', '0xbe', '0x6f', '0xb', '0xf8', '0x9b', '0x76']
&lt;/pre&gt;
&lt;p&gt;Being totally clueless, I decided to use the plain command line &lt;code&gt;openssl&lt;/code&gt; tool just to see if node.js or Python were messing up the binary data or something like that. As I had sniffed the challenge from the VNC session, I put it in a file &lt;code&gt;challenge&lt;/code&gt; and ran the &lt;code&gt;openssl&lt;/code&gt; tool as following:&lt;/p&gt;
&lt;pre &gt;
$ openssl des -pass pass:browsers -in challenge -e -nosalt | hexdump
0000000 72e9 e28b 5610 d48f a312 33e3 deba 96a7
0000010 d253 826d 9b86 3620                    
&lt;/pre&gt;
&lt;p&gt;The output was again different, 24 bytes in size and it didn't match the response.&lt;/p&gt;
&lt;p&gt;At this point I had had enough with all these different results and I started searching the web for the simplest possible DES implementation as I wasn't up to implementing DES myself. I found some C code that was public domain and wrote &lt;a href="https://github.com/pkrumins/node-des"&gt;node-des&lt;/a&gt; that produces the results that I expect and that VNC server accepts.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;des&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;../build/Release/des.node&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
   &lt;span class="mh"&gt;0x0c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x6b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x8c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x5c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x04&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xb3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xe5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xb9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xde&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x9e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xdb&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;des&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;browsers&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre &gt;
$ node des.js
&amp;lt;SlowBuffer 44 ee fc 48 83 bb 95 f1 c0 82 c3 e2 98 c3 6a 4a&gt;
&lt;/pre&gt;
&lt;p&gt;Victory! It worked and my VNC code was functional! The question is, why did every single attempt to DES encrypt with node, python and openssl fail? Any ideas? Let's get to the bottom of this in the comments!&lt;/p&gt;
&lt;h2&gt;Update&lt;/h2&gt;
&lt;p&gt;One of my readers noticed that many of the words in node's output were of the form &lt;code&gt;cx xx&lt;/code&gt;, so he asked me if I was sure that node wasn't converting the output to utf8? I was pretty sure it wasn't, buffers are buffers of raw bytes after all, but this looked too suspicious. I looked up in the documentation and found out that the default encoding for the buffers was utf8... &lt;/p&gt;
&lt;p&gt;So I modified the original program and replaced &lt;code&gt;console.log(Buffer(response))&lt;/code&gt; with &lt;code&gt;console.log(Buffer(response, 'binary'))&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;crypto&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
   &lt;span class="mh"&gt;0x0c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x6b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x8c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x5c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x04&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xb3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xe5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xb9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xde&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="mh"&gt;0x33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x9e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0xdb&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createCipher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;des&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;browsers&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;binary&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now I do get 16 bytes in the output but it still doesn't match the sniffed response:&lt;/p&gt;
&lt;pre &gt;
&amp;lt;Buffer e9 72 8b e2 10 56 8f d4 12 a3 e3 33 ba de a7 96&gt;
&lt;/pre&gt;
&lt;p&gt;I also modified the program that runs through all the DES algorithms by adding the &lt;code&gt;'binary'&lt;/code&gt; encoding to the Buffer's constructor. The output now is 16 bytes for all algorithms:&lt;/p&gt;
&lt;pre &gt;
des
&amp;lt;Buffer e9 72 8b e2 10 56 8f d4 12 a3 e3 33 ba de a7 96&gt;
des-cbc
&amp;lt;Buffer e9 72 8b e2 10 56 8f d4 12 a3 e3 33 ba de a7 96&gt;
des-cfb
&amp;lt;Buffer 24 43 99 11 8c ec f2 42 f1 77 e2 96 05 f3 d4 02&gt;
des-ecb
&amp;lt;Buffer aa 09 d8 d2 8c 69 68 97 88 09 ae c9 4f 3f df c3&gt;
des-ede
&amp;lt;Buffer 84 86 3f fa 2b ba 4b bd 50 05 e8 dd 37 66 15 51&gt;
des-ede-cbc
&amp;lt;Buffer 7d 60 8d 4e 27 f2 0f 6f 0e 48 54 60 38 2e b3 7e&gt;
des-ede-cfb
&amp;lt;Buffer 43 4d ac 19 d2 81 a2 3f 9a be 8a b3 72 44 37 34&gt;
des-ede-ofb
&amp;lt;Buffer 43 4d ac 19 d2 81 a2 3f 49 e4 04 24 2c 77 05 40&gt;
des-ede3
&amp;lt;Buffer a4 84 b2 2e 45 90 af 9c 21 5b bd ea 84 db 4c 76&gt;
des-ede3-cbc
&amp;lt;Buffer c1 5c b9 28 be f6 74 c9 c9 8c 62 ab 3a 95 6c 3f&gt;
des-ede3-cfb
&amp;lt;Buffer 3f cd 22 ce 5d 01 29 8b 85 b5 11 75 6f b5 5b dc&gt;
des-ede3-ofb
&amp;lt;Buffer 3f cd 22 ce 5d 01 29 8b 8c 64 51 8e a7 2f a8 97&gt;
des-ofb
&amp;lt;Buffer 24 43 99 11 8c ec f2 42 09 68 1b fd 2d 79 ba e1&gt;
des3
&amp;lt;Buffer c1 5c b9 28 be f6 74 c9 c9 8c 62 ab 3a 95 6c 3f&gt;
desx
&amp;lt;Buffer 4c 45 bb bd 78 bd f5 b9 d6 f7 f0 6d f9 cd e9 2d&gt;
&lt;/pre&gt;
&lt;p&gt;But still no match.&lt;/p&gt;
&lt;h2&gt;Solution&lt;/h2&gt;
&lt;p&gt;Ryan (in the comments below) found out why this was happening. Turns out that the VNC authentication reverses the order of bits in every byte of the password.&lt;/p&gt;
&lt;p&gt;I was basing my implementation on the &lt;a href="http://www.catonmat.net/ftp/rfbproto.pdf"&gt;RFB protocol's specification&lt;/a&gt; and it doesn't say a word about it.&lt;/p&gt;
&lt;p&gt;I'm quoting that document:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;The server sends a random 16-byte challenge. The client encrypts the challenge with DES, using a password supplied by the user as the key, and sends the resulting 16-byte response.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is no way I could have guessed this. How often do you think of reversing bits in every byte of the password? Never.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VuGEyoXSBko:jP85ZKPqRfc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VuGEyoXSBko:jP85ZKPqRfc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=VuGEyoXSBko:jP85ZKPqRfc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VuGEyoXSBko:jP85ZKPqRfc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=VuGEyoXSBko:jP85ZKPqRfc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VuGEyoXSBko:jP85ZKPqRfc:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VuGEyoXSBko:jP85ZKPqRfc:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/VuGEyoXSBko" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/curious-case-of-des-algorithm</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">A proof that Unix utility "sed" is Turing complete</title>
    <id>186</id>
    <updated>2012-04-18T19:06:26Z</updated>
    <published>2012-04-17T22:55:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/dqFgLrT0hPc/proof-that-sed-is-turing-complete" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/zSwH23xwgarLWEHIP5Hmk1xW53I/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zSwH23xwgarLWEHIP5Hmk1xW53I/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/zSwH23xwgarLWEHIP5Hmk1xW53I/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zSwH23xwgarLWEHIP5Hmk1xW53I/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Many people are surprised when they hear that sed is Turing complete. How come a text filtering program is Turing complete they ask? Turns out sed is like a small assembly language that has a comparison operation, a branching operation and a temporary buffer. If you translate a problem into a textual representation then these operations are enough to make sed Turing complete!&lt;/p&gt;
&lt;p&gt;I didn't want to invent a new proof so I'll just present a proof by &lt;a href="http://www.blaess.fr/christophe/"&gt;Christophe Blaess&lt;/a&gt;. The proof may sound silly but it works. Back in the day Christophe wrote an implementation of a Turing machine in sed [&lt;a href="http://www.catonmat.net/ftp/sed/turing.sed"&gt;download turing.sed&lt;/a&gt;]. Now since any programming language that can implement a Turing machine is Turing complete leads us to conclude that sed is also Turing complete. ■ Haha. That's it!&lt;/p&gt;
&lt;p&gt;Christophe Blaess offers his own introduction to Turing machines and a description of how his sed implementation works in his article &lt;a href="http://www.catonmat.net/ftp/sed/turing.txt"&gt;Implementation of a Turing Machine as Sed Script&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is an example program for his Turing machine that increments a binary number. The program has the initial tape configuration on the first line of the program, and the program itself below it. In this example the initial tape configuration is the binary number &lt;code&gt;10010111&lt;/code&gt; (151) and the program increments it by one.&lt;/p&gt;
&lt;pre &gt;
| 10010111

# State 0
0  R0
011R1
000R1

# State 1
1  L2
100R1
111R1

# State 2
2 1R3
201R3
210L2

# State 3
3  RF
300R3
311R3 
&lt;/pre&gt;
&lt;p&gt;To run this program save it to a file &lt;a href="http://www.catonmat.net/ftp/sed/increment.tm"&gt;increment.tm&lt;/a&gt; and run it through &lt;a href="http://www.catonmat.net/ftp/sed/turing.sed"&gt;turing.sed&lt;/a&gt; as following:&lt;/p&gt;
&lt;pre &gt;
$ sed -f turing.sed &amp;lt; example.tm
&lt;/pre&gt;
&lt;p&gt;You'll get the following output:&lt;/p&gt;
&lt;pre &gt;
(0) | |10010111
(0) |1|0010111
(1) 1|0|010111
(1) 10|0|10111
(1) 100|1|0111
(1) 1001|0|111
(1) 10010|1|11
(1) 100101|1|1
(1) 1001011|1|
(1) 10010111| |
(2) 1001011|1|
(2) 100101|1|0
(2) 10010|1|00
(2) 1001|0|000
(3) 10011|0|00
(3) 100110|0|0
(3) 1001100|0|
(3) 10011000| |
(F) 10011000 | |
Final state F reached... end of processing
&lt;/pre&gt;
&lt;p&gt;The output shows the state and tape changes as the program is executed. When it's done the final state &lt;code&gt;F&lt;/code&gt; is reached and the computation process terminates producing &lt;code&gt;10011000&lt;/code&gt; (152) as a result as expected.&lt;/p&gt;
&lt;p&gt;Since you can write any program in sed, people have done so and written tetris, sokoban and many other programs. Take a look at these:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.catonmat.net/ftp/sed/sedtris.sed"&gt;Tetris&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.catonmat.net/ftp/sed/sokoban.sed"&gt;Sokoban (game)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.catonmat.net/ftp/sed/dc.sed"&gt;Calculator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Impressive!&lt;/p&gt;
&lt;h2&gt;The Busy Beaver&lt;/h2&gt;
&lt;p&gt;If you liked this article, you'll also like my article about &lt;a href="http://www.catonmat.net/blog/busy-beaver/"&gt;the busy beaver&lt;/a&gt;. The busy beaver is a Turing machine that puts 1's on an initially blank tape. The busy beaver problem is to find an n-state Turing machine that puts as many 1's on the tape as possible. It hasn't been solved for a 5-state Turing machine yet and theorists doubt that it shall ever be computed for 6 states!&lt;/p&gt;
&lt;h2&gt;My sed book&lt;/h2&gt;
&lt;p&gt;I wrote this fun book on sed a while ago called "&lt;a href="http://www.catonmat.net/blog/sed-book/"&gt;Sed One-Liners Explained&lt;/a&gt;." If you don't know sed yet and wish to learn it, my book teaches it through 100 practical and well-explained examples. Take a look!&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;a href="http://www.catonmat.net/blog/sed-book/" class="nohover" title="Sed One-Liners Explained"&gt;&lt;img src="http://www.catonmat.net/images/sed-book/cover.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;&lt;a href="http://www.catonmat.net/blog/sed-book/"&gt;sed book&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=dqFgLrT0hPc:8Y4B9trl1ss:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=dqFgLrT0hPc:8Y4B9trl1ss:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=dqFgLrT0hPc:8Y4B9trl1ss:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=dqFgLrT0hPc:8Y4B9trl1ss:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=dqFgLrT0hPc:8Y4B9trl1ss:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=dqFgLrT0hPc:8Y4B9trl1ss:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=dqFgLrT0hPc:8Y4B9trl1ss:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/dqFgLrT0hPc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/proof-that-sed-is-turing-complete</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Here is why vim uses the hjkl keys as arrow keys</title>
    <id>311</id>
    <updated>2012-03-21T00:02:27Z</updated>
    <published>2012-03-09T15:25:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/kxlfye1-w5c/why-vim-uses-hjkl-as-arrow-keys" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/3Wzno8OKBq_749LTFmXbj7y-gDg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3Wzno8OKBq_749LTFmXbj7y-gDg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/3Wzno8OKBq_749LTFmXbj7y-gDg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3Wzno8OKBq_749LTFmXbj7y-gDg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I was reading about vim the other day and found out why it used &lt;code&gt;hjkl&lt;/code&gt; keys as arrow keys. When &lt;a href="http://en.wikipedia.org/wiki/Bill_Joy"&gt;Bill Joy&lt;/a&gt; created the vi text editor he used the &lt;a href="http://en.wikipedia.org/wiki/ADM-3A"&gt;ADM-3A terminal&lt;/a&gt;, which had the arrows on &lt;code&gt;hjkl&lt;/code&gt; keys. Naturally he reused the same keys and the rest is history!&lt;/p&gt;
&lt;p&gt;Here is how the &lt;code&gt;hjkl&lt;/code&gt; keys looked:&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/why-vim-uses-hjkl/adm-3a-hjkl-keyboard.jpg"&gt;&lt;br&gt;
&lt;small&gt;ADM-3A keyboard's hjkl keys with arrows.&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;And here is the whole terminal that vi was created on:&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/why-vim-uses-hjkl/lsi-adm-3a.jpg"&gt;&lt;br&gt;
&lt;small&gt;Lear Siegler's ADM-3A computer terminal.&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Since vim is derived from vi, it uses the same &lt;code&gt;hjkl&lt;/code&gt; keys.&lt;/p&gt;
&lt;p&gt;And while we're at it, notice where the &lt;code&gt;ESC&lt;/code&gt; key is positioned:&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/why-vim-uses-hjkl/lsi-adm3a-full-keyboard.jpg"&gt;&lt;br&gt;
&lt;small&gt;Lear Siegler's ADM-3A computer terminal's full keyboard.&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;That's why the &lt;code&gt;ESC&lt;/code&gt; is used to change between vi modes! Because it's so close and easy to reach.&lt;/p&gt;
&lt;p&gt;Also ever wondered why home directory is &lt;code&gt;~&lt;/code&gt; in UNIX? Look at the &lt;code&gt;HOME&lt;/code&gt; key in upper right corner!&lt;/p&gt;
&lt;h2&gt;HJKL T-Shirt!&lt;/h2&gt;
&lt;p&gt;I just got a deal with &lt;a href="http://teespring.com/hjkl2"&gt;Teespring&lt;/a&gt; for a &lt;code&gt;hjkl&lt;/code&gt; t-shirt! Teespring is like kickstarter for t-shirts. If at least 30 people commit to buy the shirt the deal goes through and everyone gets the shirt. Otherwise nothing happens.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://teespring.com/hjkl2"&gt;Get your limited edition hjkl t-shirt now!&lt;/a&gt; (Ships worldwide in 4-8 days.)&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;a href="http://teespring.com/hjkl2" class="nohover"&gt;&lt;img src="http://www.catonmat.net/images/why-vim-uses-hjkl/hjkl-tshirt.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Extra Discussions!&lt;/h2&gt;
&lt;p&gt;My post has generated a lot of awesome responses, see &lt;a href="http://news.ycombinator.com/item?id=3684515"&gt;hacker news&lt;/a&gt;, &lt;a href="http://www.osnews.com/comments/25701"&gt;osnews&lt;/a&gt;, and reddit discussions (two of them on &lt;a href="http://www.reddit.com/r/programming/comments/qpaxl/here_is_why_vim_uses_the_hjkl_keys_as_arrow_keys/"&gt;/r/programming&lt;/a&gt; and &lt;a href="http://www.reddit.com/r/vim/comments/qp0f1/why_vim_uses_hjkl_as_arrow_keys/"&gt;/r/vim&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Follow me!&lt;/h2&gt;
&lt;p&gt;If you enjoyed my post, &lt;a href="http://www.catonmat.net/feed/"&gt;subscribe to my blog&lt;/a&gt;, follow me on &lt;a href="http://twitter.com/pkrumins"&gt;twitter&lt;/a&gt;, &lt;a href="http://www.google.com/profiles/peteris.krumins"&gt;google+&lt;/a&gt; or &lt;a href="http://github.com/pkrumins"&gt;github&lt;/a&gt;. Thank you!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=kxlfye1-w5c:hef9mbQERYM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=kxlfye1-w5c:hef9mbQERYM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=kxlfye1-w5c:hef9mbQERYM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=kxlfye1-w5c:hef9mbQERYM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=kxlfye1-w5c:hef9mbQERYM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=kxlfye1-w5c:hef9mbQERYM:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=kxlfye1-w5c:hef9mbQERYM:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/kxlfye1-w5c" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/why-vim-uses-hjkl-as-arrow-keys</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Announcing dedicated servers for Browserling</title>
    <id>310</id>
    <updated>2012-03-01T21:58:53Z</updated>
    <published>2012-03-01T20:00:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/x0a3kqxDT4o/announcing-dedicated-servers-for-browserling" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/KG9EcYvGl3t8EkLJiVuhX6tWP5g/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KG9EcYvGl3t8EkLJiVuhX6tWP5g/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/KG9EcYvGl3t8EkLJiVuhX6tWP5g/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KG9EcYvGl3t8EkLJiVuhX6tWP5g/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;We're super excited to announce dedicated plans for &lt;a href="http://browserling.com/"&gt;Browserling&lt;/a&gt;. With a dedicated Browserling plan you get your own Windows server with all the browsers pre-installed, plus you can install any software that you want, any browser plugins you want, and do absolutely anything you wish with it as you also get full administrator rights to your server.&lt;/p&gt;
&lt;p&gt;I made a demo video of dedicated plans. Take a look:&lt;/p&gt;
&lt;div class="c"&gt;&lt;iframe width="600" height="500" src="http://www.youtube.com/embed/Hww_7zj9qr4" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;small&gt;&lt;a href="http://www.youtube.com/watch?v=Hww_7zj9qr4"&gt;http://www.youtube.com/watch?v=Hww_7zj9qr4&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Tweet us &lt;a href="http://twitter.com/browserling"&gt;@browserling&lt;/a&gt; if you want to try a free demo. Or you can just buy a dedicated instance right away from the pricing menu!&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;a class="nohover" href="http://browserling.com"&gt;&lt;img src="http://www.catonmat.net/images/browserling.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;&lt;a href="http://browserling.com"&gt;Try browserling!&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Browserling is an interactive cross-browser testing tool. You can use it to test your website in IE, Firefox, Chrome, Opera, and Safari.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x0a3kqxDT4o:lmBTkNGByeY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x0a3kqxDT4o:lmBTkNGByeY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=x0a3kqxDT4o:lmBTkNGByeY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x0a3kqxDT4o:lmBTkNGByeY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=x0a3kqxDT4o:lmBTkNGByeY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x0a3kqxDT4o:lmBTkNGByeY:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=x0a3kqxDT4o:lmBTkNGByeY:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/x0a3kqxDT4o" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/announcing-dedicated-servers-for-browserling</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Announcing my third e-book "Perl One-Liners Explained"</title>
    <id>303</id>
    <updated>2012-02-02T05:34:44Z</updated>
    <published>2012-02-01T13:40:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/27oRonhWXEU/perl-book" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/yaCf8gxnVwB5cmfMMEZyDajRyhQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yaCf8gxnVwB5cmfMMEZyDajRyhQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/yaCf8gxnVwB5cmfMMEZyDajRyhQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/yaCf8gxnVwB5cmfMMEZyDajRyhQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="float:right; margin-left: 5px"&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/perl-book/cover.png" width="260" height="310"&gt;&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;p&gt;&lt;a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=2HMCK3EJRM6MC"&gt;Buy it now for just $9.95&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;&lt;p&gt;&lt;a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=2HMCK3EJRM6MC" class="nohover"&gt;&lt;img src="https://www.paypalobjects.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;&lt;img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1"&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Hello ladies and gentlemen! &lt;strong&gt;I'm happy to announce my 3rd e-book called "Perl One-Liners Explained."&lt;/strong&gt; This book is based on the "&lt;a href="http://www.catonmat.net/blog/perl-one-liners-explained-part-one/"&gt;Famous Perl One-Liners Explained&lt;/a&gt;" article series that I wrote over the last 3 years and that has been read over 500,000 times!&lt;/p&gt;
&lt;p&gt;I went through all the one-liners in the article series, 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.&lt;/p&gt;
&lt;h2&gt;Table of Contents&lt;/h2&gt;
&lt;p&gt;The e-book has 111 pages and it explains 130 unique one-liners. Many of one-liners are presented in several different ways so the total number of one-liners in the book is over 200.&lt;/p&gt;
&lt;p&gt;The e-book is divided into the following chapters:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Preface.&lt;/li&gt;
&lt;li&gt;1. Introduction to Perl One-Liners.&lt;/li&gt;
&lt;li&gt;2. Spacing.&lt;/li&gt;
&lt;li&gt;3. Numbering.&lt;/li&gt;
&lt;li&gt;4. Calculations&lt;/li&gt;
&lt;li&gt;5. String Creation and Array Creation.&lt;/li&gt;
&lt;li&gt;6. Text Conversion and Substitution.&lt;/li&gt;
&lt;li&gt;7. Selective Printing and Deleting of Lines.&lt;/li&gt;
&lt;li&gt;8. Handy Regular Expressions.&lt;/li&gt;
&lt;li&gt;9. perl1line.txt&lt;/li&gt;
&lt;li&gt;Appendix A. Perl's Special Variables.&lt;/li&gt;
&lt;li&gt;Index.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What are Perl One-Liners?&lt;/h2&gt;
&lt;p&gt;Perl one-liners are small and awesome Perl programs that fit in a single line of code and they do one thing really well. These things include changing line spacing, numbering lines, doing calculations, converting and substituting text, deleting and printing certain lines, parsing logs, editing files in-place, doing statistics, carrying out system administration tasks, updating a bunch of files at once, and many more.&lt;/p&gt;
&lt;p&gt;Let's take a look at several practical examples that you can easily do with one-liners. All these examples and many more are explained in the e-book.&lt;/p&gt;
&lt;p&gt;I have also made the first chapter of the book, &lt;em&gt;Introduction to Perl One-Liners&lt;/em&gt;, freely available. Please download &lt;a href="http://www.catonmat.net/download/perlbook-preview.pdf"&gt;the e-book preview&lt;/a&gt; to read it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1: Replace a string in multiple files at once&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
perl -p -i.bak -e 's/Config/config/g' conf1 conf2 conf3
&lt;/pre&gt;
&lt;p&gt;Suppose you have 3 configuration files, and you discover that you made a mistake and need to replace all occurrences of &lt;code&gt;Config&lt;/code&gt; with &lt;code&gt;config&lt;/code&gt;. This one-liner does just that. It executes the &lt;code&gt;s/Config/config/g&lt;/code&gt; that replaces all occurrences of &lt;code&gt;Config&lt;/code&gt; with &lt;code&gt;config&lt;/code&gt; on all lines. And since you're smart about it, you always do &lt;code&gt;-i.bak&lt;/code&gt; to make backup files in case something goes wrong.&lt;/p&gt;
&lt;p&gt;I explain the &lt;code&gt;-i&lt;/code&gt;, &lt;code&gt;-p&lt;/code&gt;, and &lt;code&gt;-e&lt;/code&gt; arguments in the e-book in great detail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2: Generate a random 8 character password&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
perl -le 'print map { ("a".."z")[rand 26] } 1..8'
&lt;/pre&gt;
&lt;p&gt;This one-liner generates and prints a random 8 character password. It uses the list range operator &lt;code&gt;..&lt;/code&gt; operator to produce all strings from &lt;code&gt;"a"&lt;/code&gt; to &lt;code&gt;"z"&lt;/code&gt;, which is the alphabet. Then a random letter is chosen by &lt;code&gt;rand 26&lt;/code&gt; and this operation is repeated 8 times.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 3: URL-escape a string&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
perl -MURI::Escape -lne 'print uri_escape($string)'
&lt;/pre&gt;
&lt;p&gt;Here we use the &lt;code&gt;URI::Escape&lt;/code&gt; module from CPAN. It exports the &lt;code&gt;uri_escape&lt;/code&gt; function that does URL-escaping.&lt;/p&gt;
&lt;p&gt;You can install this module from CPAN by running &lt;code&gt;perl -MCPAN -e'install URI::Escape'&lt;/code&gt; on the command line.&lt;/p&gt;
&lt;p&gt;I have this one-liner as an alias actually for both URL-escaping and unescaping URL-escaping as it's such a common thing to do:&lt;/p&gt;
&lt;pre &gt;
urlescape () { perl -MURI::Escape -lne 'print uri_escape($_)' &amp;lt;&amp;lt;&amp;lt; "$1" }
urlunescape () { perl -MURI::Escape -lne 'print uri_unescape($_)' &amp;lt;&amp;lt;&amp;lt; "$1"; }
&lt;/pre&gt;
&lt;p&gt;Then I can do this in the shell:&lt;/p&gt;
&lt;pre &gt;
$ urlescape "http://www.catonmat.net"
http%3A%2F%2Fwww.catonmat.net

$ urlunescape http%3A%2F%2Fwww.catonmat.net
http://www.catonmat.net
&lt;/pre&gt;
&lt;p&gt;Very useful!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 4: Print all lines from line 17 to line 30&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
perl -ne 'print if 17..30'
&lt;/pre&gt;
&lt;p&gt;Here we use the binary flip-flop operator &lt;code&gt;..&lt;/code&gt; that becomes true when the input line number is 17, stays true while the line number is less than or equal to 30, and then becomes false. Combining the flip-flop operator with &lt;code&gt;print if&lt;/code&gt; makes it print only lines 17-30.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 5: Remove all consecutive blank lines, leaving just one&lt;/strong&gt;&lt;/p&gt;
&lt;pre &gt;
perl -00pe0
&lt;/pre&gt;
&lt;p&gt;I included this one-liner here in the examples just to show you how funny and obscure one-liners can get. This one-liner deletes all repeated blank lines from the input or from the given file. It does it by enabling the paragraph slurp mode through &lt;code&gt;-00&lt;/code&gt; command line argument, which reads the input paragraph-by-paragraph, rather than line-by-line, and prints the paragraphs. This way any number of blank lines between the paragraphs get ignored.&lt;/p&gt;
&lt;p&gt;I explain this one-liner in more details in the e-book.&lt;/p&gt;
&lt;p&gt;As I hope you can see, knowing how to write one-liners is very useful. It was one of my top priority tasks through the years to become very efficient in the shell. Literally every day when I'm programming, I have to do all kinds of data processing tasks, changing files, verifying output, doing quick calculations, parsing data, etc, and knowing Perl one-liners makes it really fast to get things done.&lt;/p&gt;
&lt;p&gt;Now that I have written this e-book, you can become very efficient, too. Enjoy!&lt;/p&gt;
&lt;h2&gt;Book Preview&lt;/h2&gt;
&lt;p&gt;I prepared a free book preview that contains the first 13 pages of the book. It includes the table of contents, preface, introduction to Perl one-liners and the first page of the second chapter.&lt;/p&gt;
&lt;div class="c" style="padding-top: 1em; padding-bottom: 1em;"&gt;&lt;p&gt;&lt;big&gt;&lt;a href="http://www.catonmat.net/download/perlbook-preview.pdf"&gt;Perl One-Liners Explained. Book Preview.&lt;/a&gt;&lt;/big&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Buy it now!&lt;/h2&gt;
&lt;p&gt;The price of the e-book is &lt;strong&gt;$9.95&lt;/strong&gt; and it can be &lt;a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=2HMCK3EJRM6MC"&gt;purchased via PayPal&lt;/a&gt;:&lt;/p&gt;
&lt;div class="c" style="padding-top: 1em; padding-bottom: 1em;"&gt;&lt;p&gt;&lt;a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=2HMCK3EJRM6MC" class="nohover"&gt;&lt;img src="https://www.paypalobjects.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"&gt;&lt;/a&gt;&lt;br&gt;
&lt;img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1"&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;After you have made the payment, my automated e-book processing system will send you the PDF e-book in a few minutes!&lt;/p&gt;
&lt;h2&gt;Tweet about my book!&lt;/h2&gt;
&lt;p&gt;Help me spread the word about my new book! I prepared a special link that you can use to tweet about it:&lt;/p&gt;
&lt;div class="c" style="padding-top: 1em"&gt;&lt;p&gt;&lt;a href="http://bit.ly/perlebook" class="nohover"&gt;&lt;img src="http://www.catonmat.net/images/tweet-my-book.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;What's next?&lt;/h2&gt;
&lt;p&gt;I really love writing about programming and I have planned writing many more books. The next few are going to be a book on mastering vim, a practical guide on how to be anonymous on the web, and the catonmat book.&lt;/p&gt;
&lt;h2&gt;Enjoy!&lt;/h2&gt;
&lt;p&gt;Enjoy the book and don't forget to leave comments about it! Ask me anything you wish and I'll help you out.&lt;/p&gt;
&lt;p&gt;Also if you're interested, take a look at my other two e-books. The 1st one is called "&lt;a href="http://www.catonmat.net/blog/awk-book/"&gt;Awk One-Liners Explained&lt;/a&gt;" and the 2nd one is called "&lt;a href="http://www.catonmat.net/blog/sed-book/"&gt;Sed One-Liners Explained&lt;/a&gt;" They're written in a similar style as this e-book and they teach practical Awk and Sed through many examples.&lt;/p&gt;
&lt;p&gt;Finally, if you enjoy my writing, you can &lt;a href="http://www.catonmat.net/feed/"&gt;subscribe to my blog&lt;/a&gt;, &lt;a href="http://twitter.com/pkrumins"&gt;follow me on Twitter&lt;/a&gt; or &lt;strong&gt;&lt;a href="http://google.com/profiles/peteris.krumins"&gt;&lt;span style="color: blue"&gt;G&lt;/span&gt;&lt;span style="color: red"&gt;o&lt;/span&gt;&lt;span style="color: #EE9A00"&gt;o&lt;/span&gt;&lt;span style="color: blue"&gt;g&lt;/span&gt;&lt;span style="color: green"&gt;l&lt;/span&gt;&lt;span style="color: red"&gt;e&lt;/span&gt;&lt;span style="color: gray"&gt;+&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=27oRonhWXEU:37g9ZCZSaa0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=27oRonhWXEU:37g9ZCZSaa0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=27oRonhWXEU:37g9ZCZSaa0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=27oRonhWXEU:37g9ZCZSaa0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=27oRonhWXEU:37g9ZCZSaa0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=27oRonhWXEU:37g9ZCZSaa0:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=27oRonhWXEU:37g9ZCZSaa0:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/27oRonhWXEU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/perl-book</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">How Browserling Works [art]</title>
    <id>308</id>
    <updated>2012-01-29T23:19:54Z</updated>
    <published>2012-01-29T23:20:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/YZLYyk1MXQc/how-browserling-works" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/3v0XinExttP68iNtD_SBSanVu_o/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3v0XinExttP68iNtD_SBSanVu_o/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/3v0XinExttP68iNtD_SBSanVu_o/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/3v0XinExttP68iNtD_SBSanVu_o/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="c"&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/how-browserling-works.png"&gt;&lt;br&gt;
&lt;small&gt;Art by &lt;a href="http://substack.net"&gt;James Halliday&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;1. We run the browsers on our servers.&lt;br&gt;
2. You use the browsers from the graphical web console.&lt;br&gt;
3. If the servers are full, you wait in the queue.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.browserling.com"&gt;Try Browserling!&lt;/a&gt;&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=YZLYyk1MXQc:-V-vfW6jKWE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=YZLYyk1MXQc:-V-vfW6jKWE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=YZLYyk1MXQc:-V-vfW6jKWE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=YZLYyk1MXQc:-V-vfW6jKWE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=YZLYyk1MXQc:-V-vfW6jKWE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=YZLYyk1MXQc:-V-vfW6jKWE:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=YZLYyk1MXQc:-V-vfW6jKWE:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/YZLYyk1MXQc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/how-browserling-works</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Node.js modules you should know about: procstreams</title>
    <id>305</id>
    <updated>2012-01-24T17:49:17Z</updated>
    <published>2012-01-24T16:20:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/VpZVHQUt9tw/nodejs-modules-procstreams" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/vYG9f7yjoOf0VtC2zHxqKA9JKrA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vYG9f7yjoOf0VtC2zHxqKA9JKrA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/vYG9f7yjoOf0VtC2zHxqKA9JKrA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vYG9f7yjoOf0VtC2zHxqKA9JKrA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/nodejs-modules/nodejs-logo.png" alt="node logo" class="post-icon" align="left"&gt;Hello everyone! This is the 15th post in the &lt;a href="http://www.catonmat.net/blog/nodejs-modules-dnode/"&gt;node.js modules you should know about&lt;/a&gt; article series.&lt;/p&gt;
&lt;p&gt;The first post was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-dnode/"&gt;dnode&lt;/a&gt; - the freestyle rpc library for node, the second was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-optimist/"&gt;optimist&lt;/a&gt; - the lightweight options parser for node, the third was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-lazy/"&gt;lazy&lt;/a&gt; - lazy lists for node, the fourth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-request/"&gt;request&lt;/a&gt; - the swiss army knife of HTTP streaming, the fifth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-hashish/"&gt;hashish&lt;/a&gt; - hash combinators library, the sixth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-read/"&gt;read&lt;/a&gt; - easy reading from stdin, the seventh was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-ntwitter/"&gt;ntwitter&lt;/a&gt; - twitter api for node, the eighth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-socketio/"&gt;socket.io&lt;/a&gt; that makes websockets and realtime possible in all browsers, the ninth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-redis/"&gt;redis&lt;/a&gt; - the best redis client API library for node, the tenth was on &lt;a href="http://www.catonmat.net/blog/nodejs-modules-express/"&gt;express&lt;/a&gt; - an insanely small and fast web framework for node, the eleventh was &lt;a href="http://www.catonmat.net/blog/nodejs-modules-semver/"&gt;semver&lt;/a&gt; - a node module that takes care of versioning, the twelfth was &lt;a href="http://www.catonmat.net/blog/nodejs-modules-cradle/"&gt;cradle&lt;/a&gt; - a high-level, caching, CouchDB client for node, the thirteenth was &lt;a href="http://www.catonmat.net/blog/nodejs-modules-jsonstream/"&gt;jsonstream&lt;/a&gt; - streaming JSON parsing library, the fourteenth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-everyauth/"&gt;everyauth&lt;/a&gt; - a module for authenticating your webapp with facebook, twitter, etc.&lt;/p&gt;
&lt;p&gt;Today I'm gonna introduce you to &lt;a href="https://github.com/polotek/procstreams"&gt;procstreams&lt;/a&gt; by &lt;a href="http://marcorogers.com/blog/"&gt;Marco Rogers&lt;/a&gt; aka &lt;a href="https://twitter.com/#!/polotek"&gt;polotek&lt;/a&gt;. Procstreams is a little experiment with shell scripting in node. Here is an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;procstreams&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;$p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cat lines.txt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;wc -l&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// prints number of lines in the file lines.txt&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This example executes the shell command &lt;code&gt;cat lines.txt&lt;/code&gt;, then pipes the output to &lt;code&gt;wc -l&lt;/code&gt;, and then collects the output through a callback that prints the number of lines in &lt;code&gt;lines.txt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Here is another example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;procstreams&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;$p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mkdir foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cp file.txt foo/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rm file.txt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;exit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;done&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This example executes &lt;code&gt;mkdir foo&lt;/code&gt;, and if that succeeds, it executes &lt;code&gt;cp file.txt foo/&lt;/code&gt;, and if that succeeds, it executes &lt;code&gt;rm file.txt&lt;/code&gt;. In shells scripting you'd write this as:&lt;/p&gt;
&lt;pre &gt;
mkdir foo &amp;&amp; cp file.txt foo/ &amp;&amp; rm file.txt
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.and(...)&lt;/code&gt; is the same as &lt;code&gt;&amp;&amp;&lt;/code&gt; in the shell scripting.&lt;/p&gt;
&lt;p&gt;Procstreams also support &lt;code&gt;.or(...)&lt;/code&gt;, which is &lt;code&gt;||&lt;/code&gt; in the shell and &lt;code&gt;.then(...)&lt;/code&gt;, which is &lt;code&gt;;&lt;/code&gt; in the shell.&lt;/p&gt;
&lt;p&gt;Here is an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;procstreams&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;$p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mkdir foo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cp file.txt file2.txt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;echo &amp;quot;failed&amp;quot; &amp;gt; ~/notify&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This example &lt;code&gt;mkdirs foo&lt;/code&gt;, then copies file.txt to file2.txt, if that fails, it echos "failed" to &lt;code&gt;~/notify&lt;/code&gt;. Shell equivalent:&lt;/p&gt;
&lt;pre &gt;
mkdir foo; cp file.txt file2.txt || echo "failed" &gt; ~/notify
&lt;/pre&gt;
&lt;p&gt;See &lt;a href="https://github.com/polotek/procstreams"&gt;procstreams documentation&lt;/a&gt; on GitHub for full info on other thingies it supports.&lt;/p&gt;
&lt;p&gt;You can install &lt;code&gt;procstreams&lt;/code&gt; through npm as always:&lt;/p&gt;
&lt;pre &gt;
npm install procstreams
&lt;/pre&gt;
&lt;p&gt;Procstreams on GitHub: &lt;a href="https://github.com/polotek/procstreams"&gt;https://github.com/polotek/procstreams&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Sponsor this blog series!&lt;/h2&gt;
&lt;p&gt;Doing a node.js company and want your ad to appear in the series? The ad will go out to 14,000 rss subscribers, 7,000 email subscribers, and it will get viewed by thousands of my blog visitors! &lt;a href="http://www.catonmat.net/feedback/"&gt;Email me&lt;/a&gt; and we'll set it up! &lt;/p&gt;
&lt;h2&gt;Enjoy!&lt;/h2&gt;
&lt;p&gt;If you love these articles, &lt;a href="http://www.catonmat.net/feed/" title="Subscribe to catonmat.net RSS feed"&gt;subscribe to my blog&lt;/a&gt; for more, &lt;a href="http://twitter.com/pkrumins" title="Peteris Krumins on Twitter"&gt;follow me on Twitter&lt;/a&gt; to find about my adventures, and &lt;a href="http://github.com/pkrumins" title="Peteris Krumins on GitHub"&gt;watch me produce code on GitHub&lt;/a&gt;!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VpZVHQUt9tw:B8DYaijzyfc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VpZVHQUt9tw:B8DYaijzyfc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=VpZVHQUt9tw:B8DYaijzyfc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VpZVHQUt9tw:B8DYaijzyfc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=VpZVHQUt9tw:B8DYaijzyfc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VpZVHQUt9tw:B8DYaijzyfc:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=VpZVHQUt9tw:B8DYaijzyfc:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/VpZVHQUt9tw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/nodejs-modules-procstreams</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Browserling has a new design!</title>
    <id>302</id>
    <updated>2012-01-16T18:51:51Z</updated>
    <published>2012-01-16T18:50:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/t5nha2qE-aQ/new-browserling-design" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/22ghEXryR95X6YMVGQKFgTOIgR0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/22ghEXryR95X6YMVGQKFgTOIgR0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/22ghEXryR95X6YMVGQKFgTOIgR0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/22ghEXryR95X6YMVGQKFgTOIgR0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Awesome news everyone! We launched new design for &lt;a href="http://www.browserling.com"&gt;Browserling&lt;/a&gt;! We also switched to &lt;a href="http://www.catonmat.net/blog/stripe-payments-with-node/"&gt;Stripe&lt;/a&gt; for accepting payments and also added a bunch more browsers!&lt;/p&gt;
&lt;p&gt;The new design is much cleaner, and everything is driven through ajax calls, we don't even use HTML templates anymore!&lt;/p&gt;
&lt;p&gt;Here is a screenshot of Browserling with the new design:&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/browserling-new-design.jpg"&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="http://www.browserling.com"&gt;Browserling&lt;/a&gt; is interactive cross-browser testing tool that allows you to see what your webpage looks like in Internet Explorer, Firefox, Chrome, Opera, and Safari.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=t5nha2qE-aQ:h5Hesn8cpQg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=t5nha2qE-aQ:h5Hesn8cpQg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=t5nha2qE-aQ:h5Hesn8cpQg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=t5nha2qE-aQ:h5Hesn8cpQg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=t5nha2qE-aQ:h5Hesn8cpQg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=t5nha2qE-aQ:h5Hesn8cpQg:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=t5nha2qE-aQ:h5Hesn8cpQg:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/t5nha2qE-aQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/new-browserling-design</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Node.js modules you should know about: everyauth</title>
    <id>301</id>
    <updated>2012-01-03T18:34:38Z</updated>
    <published>2012-01-03T17:25:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/Lo25io4y6dg/nodejs-modules-everyauth" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/kBYejLhzynBVrHsfSsjpJApHrBY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kBYejLhzynBVrHsfSsjpJApHrBY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/kBYejLhzynBVrHsfSsjpJApHrBY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kBYejLhzynBVrHsfSsjpJApHrBY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/nodejs-modules/nodejs-logo.png" alt="node logo" class="post-icon" align="left"&gt;Hello everyone! This is the 14th post in the &lt;a href="http://www.catonmat.net/blog/nodejs-modules-dnode/"&gt;node.js modules you should know about&lt;/a&gt; article series.&lt;/p&gt;
&lt;p&gt;The first post was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-dnode/"&gt;dnode&lt;/a&gt; - the freestyle rpc library for node, the second was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-optimist/"&gt;optimist&lt;/a&gt; - the lightweight options parser for node, the third was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-lazy/"&gt;lazy&lt;/a&gt; - lazy lists for node, the fourth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-request/"&gt;request&lt;/a&gt; - the swiss army knife of HTTP streaming, the fifth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-hashish/"&gt;hashish&lt;/a&gt; - hash combinators library, the sixth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-read/"&gt;read&lt;/a&gt; - easy reading from stdin, the seventh was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-ntwitter/"&gt;ntwitter&lt;/a&gt; - twitter api for node, the eighth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-socketio/"&gt;socket.io&lt;/a&gt; that makes websockets and realtime possible in all browsers, the ninth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-redis/"&gt;redis&lt;/a&gt; - the best redis client API library for node, the tenth was on &lt;a href="http://www.catonmat.net/blog/nodejs-modules-express/"&gt;express&lt;/a&gt; - an insanely small and fast web framework for node, the eleventh was &lt;a href="http://www.catonmat.net/blog/nodejs-modules-semver/"&gt;semver&lt;/a&gt; - a node module that takes care of versioning, the twelfth was &lt;a href="http://www.catonmat.net/blog/nodejs-modules-cradle/"&gt;cradle&lt;/a&gt; - a high-level, caching, CouchDB client for node, the thirteenth was &lt;a href="http://www.catonmat.net/blog/nodejs-modules-jsonstream/"&gt;jsonstream&lt;/a&gt; - streaming JSON parsing library.&lt;/p&gt;
&lt;p&gt;Today I'm gonna introduce you to &lt;a href="https://github.com/bnoguchi/everyauth"&gt;everyauth&lt;/a&gt; by &lt;a href="https://github.com/bnoguchi"&gt;Brian Noguchi&lt;/a&gt;. Everyauth is a &lt;a href="http://senchalabs.github.com/connect/"&gt;connect&lt;/a&gt; middleware that allows you to setup authentication for your app via facebook, twitter, google, vimeo, tumblr, 4square, etc.&lt;/p&gt;
&lt;p&gt;Here is a list of all the sites you can use to login into your app:&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/nodejs-modules/everyauth.png"&gt;&lt;br&gt;
&lt;small&gt;Everyauth supports a plenty of sites.&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Everyauth supports OpenID, Google, Twitter, LinkedIn, Yahoo, Readability, Dropbox, Justin.tv, Vimeo, Tumblr, Facebook, Github, Instagram, Foursquare, Gowalla, 37signals, AngelList, Dwolla, Box.net.&lt;/p&gt;
&lt;p&gt;Using it is as simple as setting up a middleware for connect:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;everyauth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;everyauth&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;connect&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;everyauth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And setting up &lt;code&gt;config.json&lt;/code&gt; that contains secret keys from the sites you are going to be using for authentication:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;appId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;111565172259433&amp;#39;&lt;/span&gt;
      &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;appSecret&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;85f7e0a0cc804886180b887c1f04a3c1&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;twit&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;consumerKey&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;JLCGyLzuOK1BjnKPKGyQ&amp;#39;&lt;/span&gt;
      &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;consumerSecret&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;GNqKfPqtzOcsCtFbGTMqinoATHvBcy1nzCTimeA9M0&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;github&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;appId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;11932f2b6d05d2a5fa18&amp;#39;&lt;/span&gt;
      &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;appSecret&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2603d1bc663b74d6732500c1e9ad05b0f4013593&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then you setup routes for logging in for each particular site you want to support (in this example facebook) and you're done:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;./config.json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;usersByFbId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="nx"&gt;everyauth&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;facebook&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findOrCreateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accessTokenExtra&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fbUserMetadata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;usersByFbId&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fbUserMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersByFbId&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fbUserMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;addUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;facebook&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fbUserMetadata&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirectPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You can install &lt;code&gt;everyauth&lt;/code&gt; through npm as always:&lt;/p&gt;
&lt;pre &gt;
npm install everyauth
&lt;/pre&gt;
&lt;p&gt;EveryAuth on GitHub: &lt;a href="https://github.com/bnoguchi/everyauth"&gt;https://github.com/bnoguchi/everyauth&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Sponsor this blog series!&lt;/h2&gt;
&lt;p&gt;Doing a node.js company and want your ad to appear in the series? The ad will go out to 14,000 rss subscribers, 7,000 email subscribers, and it will get viewed by thousands of my blog visitors! &lt;a href="http://www.catonmat.net/feedback/"&gt;Email me&lt;/a&gt; and we'll set it up! &lt;/p&gt;
&lt;h2&gt;Enjoy!&lt;/h2&gt;
&lt;p&gt;If you love these articles, &lt;a href="http://www.catonmat.net/feed/" title="Subscribe to catonmat.net RSS feed"&gt;subscribe to my blog&lt;/a&gt; for more, &lt;a href="http://twitter.com/pkrumins" title="Peteris Krumins on Twitter"&gt;follow me on Twitter&lt;/a&gt; to find about my adventures, and &lt;a href="http://github.com/pkrumins" title="Peteris Krumins on GitHub"&gt;watch me produce code on GitHub&lt;/a&gt;!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Lo25io4y6dg:McqshYeKZL8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Lo25io4y6dg:McqshYeKZL8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=Lo25io4y6dg:McqshYeKZL8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Lo25io4y6dg:McqshYeKZL8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=Lo25io4y6dg:McqshYeKZL8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Lo25io4y6dg:McqshYeKZL8:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=Lo25io4y6dg:McqshYeKZL8:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/Lo25io4y6dg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/nodejs-modules-everyauth</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">How to setup Stripe payments with node.js</title>
    <id>300</id>
    <updated>2011-12-31T12:17:18Z</updated>
    <published>2011-12-29T14:55:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/1an8KBau4ZA/stripe-payments-with-node" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/6vAdMX56iPE0eGlMi1lXFsLSKg0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6vAdMX56iPE0eGlMi1lXFsLSKg0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/6vAdMX56iPE0eGlMi1lXFsLSKg0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6vAdMX56iPE0eGlMi1lXFsLSKg0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This is going to be a super quick tutorial on how to accept payments with &lt;a href="https://stripe.com/"&gt;Stripe&lt;/a&gt; payment processor and node.js. At &lt;a href="http://www.catonmat.net/blog/how-i-raised-money-for-browserling/"&gt;Browserling&lt;/a&gt; we're moving to Stripe right this very moment so I thought I'd write this quick post. Stripe is the most incredible payment processor -  it took me like 30 minutes to figure everything out. Everything is well documented and works like a charm!&lt;/p&gt;
&lt;p&gt;First, you will need the &lt;a href="https://github.com/abh/node-stripe"&gt;node-stripe&lt;/a&gt; module. Install it through npm, as always:&lt;/p&gt;
&lt;pre &gt;
npm install stripe
&lt;/pre&gt;
&lt;p&gt;Next, you'll need to login into Stripe, and setup a plan:&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/stripe/new-stripe-plan.png"&gt;&lt;br&gt;
&lt;small&gt;Setting up a new Stripe plan.&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Next, you'll need to find the test and live keys that are used in the payment code. They are located in Account Settings -&gt; API Keys.&lt;/p&gt;
&lt;div class="c"&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/stripe/stripe-api-keys.png"&gt;&lt;br&gt;
&lt;small&gt;Stripe keys are located in Account Settings -&gt; API keys.&lt;/small&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Next, you'll need to include Stripe's JavaScript library in your HTML code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://js.stripe.com/v1/&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Next, you'll need to setup an HTML form with card name, cvc, expiration date, amount (&lt;strong&gt;in cents!&lt;/strong&gt;). You don't need to ask the name or address, that stuff is old school:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stripe-form&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/plans/browserling_developer&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;payment-form&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-row&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cc-text&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Card Number&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;30&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;off&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;card-number&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-row&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cc-text&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;CVC&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;4&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;off&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;card-cvc&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;form-row&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cc-text&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Expiration (MM/YYYY)&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;card-expiry-month&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt; / &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;4&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;card-expiry-year&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;amount&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2000&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cc-amount&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;submit-button&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit Payment&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;error&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;success&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Thanks for signing up at Browserling!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Next, you'll need to generate a token when the form gets submitted, and submit it to your node.js application, instead of submitting credit card number and other info:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;publicStripeApiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;publicStripeApiKeyTesting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setPublishableKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicStripeApiKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;stripeResponseHandler&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;slideDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#stripe-form .submit-button&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;removeAttr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;disabled&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#payment-form&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;input type=&amp;#39;hidden&amp;#39; name=&amp;#39;stripeToken&amp;#39; value=&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;#39;/&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;action&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;slideDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#success&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;slideDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.submit-button&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;removeAttr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;disabled&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// http://stripe.com/docs/tutorials/forms&lt;/span&gt;
&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#payment-form&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#error&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// disable the submit button to prevent repeated clicks&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.submit-button&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;disabled&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;disabled&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#cc-amount&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// amount you want to charge in cents&lt;/span&gt;
  &lt;span class="nx"&gt;Stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.card-number&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;cvc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.card-cvc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;exp_month&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.card-expiry-month&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;exp_year&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.card-expiry-year&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stripeResponseHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// prevent the form from submitting with the default action&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Next, you need to setup a route handler in node.js web server for all your plan names. In this tutorial I'll handle just &lt;code&gt;browserling_developer&lt;/code&gt; plan:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;express&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;stripeApiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;stripeApiKeyTesting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;stripe&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;stripeApiKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bodyDecoder&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/plans/browserling_developer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stripeToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// customer&amp;#39;s email (get it from db or session)&lt;/span&gt;
    &lt;span class="nx"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;browserling_developer&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;unknown&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Error while processing your payment: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Success! Customer with Stripe ID &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; just signed up!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// save this customer to your database here!&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;That's it! This simple node.js code handles POST requests to &lt;code&gt;/plans/browserling_developer&lt;/code&gt;, and creates a new customer at Stripe. Notice that it uses &lt;code&gt;req.body.stripeToken&lt;/code&gt; and doesn't even touch credit card info.&lt;/p&gt;
&lt;p&gt;I have never worked with a payment processor which was easier to setup. It's a pure pleasure to use Stripe!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=1an8KBau4ZA:7kUnVZf2AhM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=1an8KBau4ZA:7kUnVZf2AhM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=1an8KBau4ZA:7kUnVZf2AhM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=1an8KBau4ZA:7kUnVZf2AhM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=1an8KBau4ZA:7kUnVZf2AhM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=1an8KBau4ZA:7kUnVZf2AhM:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=1an8KBau4ZA:7kUnVZf2AhM:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/1an8KBau4ZA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/stripe-payments-with-node</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">A Perl Regular Expression That Matches Prime Numbers</title>
    <id>298</id>
    <updated>2011-12-26T16:23:24Z</updated>
    <published>2011-12-25T20:00:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/FNJjWQWu3lo/perl-regex-that-matches-prime-numbers" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/aeu2V6F_xZKmpKQHftYmXE5gXaM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/aeu2V6F_xZKmpKQHftYmXE5gXaM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/aeu2V6F_xZKmpKQHftYmXE5gXaM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/aeu2V6F_xZKmpKQHftYmXE5gXaM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;pre &gt;
perl -lne '(1x$_) =~ /^1?$|^(11+?)\1+$/ || print "$_ is prime"'
&lt;/pre&gt;
&lt;p&gt;Can you figure out how it works? I give an explanation below, but try to figure it out yourself. Here is what happens when you run it:&lt;/p&gt;
&lt;pre &gt;
$ perl -lne '(1x$_) =~ /^1?$|^(11+?)\1+$/ || print "$_ is prime"'
1
2
2 is prime
3
3 is prime
4
5
5 is prime
6
7
7 is prime
8
9
10
11
11 is prime
&lt;/pre&gt;
&lt;p&gt;Here is how it works.&lt;/p&gt;
&lt;p&gt;First, the number is converted in its unary representation by &lt;code&gt;(1x$_)&lt;/code&gt;. For example, the number &lt;code&gt;5&lt;/code&gt; gets converted into &lt;code&gt;1x5&lt;/code&gt;, which is &lt;code&gt;11111&lt;/code&gt; (&lt;code&gt;1&lt;/code&gt; repeated &lt;code&gt;5&lt;/code&gt; times.)&lt;/p&gt;
&lt;p&gt;Next, the unary string gets tested against the regular expression. If it matches, the number is a composite, otherwise it's a prime.&lt;/p&gt;
&lt;p&gt;The regular expression works this way. It consists of two parts &lt;code&gt;^1?$&lt;/code&gt; and &lt;code&gt;^(11+?)\1+$&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first part matches number &lt;code&gt;1&lt;/code&gt; and the empty string. Clearly, the empty string and number &lt;code&gt;1&lt;/code&gt; are not prime numbers, therefore this regular expression matches, which indicates that they are not prime numbers.&lt;/p&gt;
&lt;p&gt;The second part determines if two or more &lt;code&gt;1&lt;/code&gt;s repeatedly make up the whole number. If two or more &lt;code&gt;1&lt;/code&gt;s repeatedly make up the whole number, the regex matches, which means that the number is composite. Otherwise it's a prime.&lt;/p&gt;
&lt;p&gt;Let's look at the second regex part on numbers &lt;code&gt;5&lt;/code&gt; and &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The number &lt;code&gt;5&lt;/code&gt; in unary representation is &lt;code&gt;11111&lt;/code&gt;. The &lt;code&gt;(11+?)&lt;/code&gt; matches the first two ones &lt;code&gt;11&lt;/code&gt;. The back-reference &lt;code&gt;\1&lt;/code&gt; becomes &lt;code&gt;11&lt;/code&gt; and the whole regex now becomes &lt;code&gt;^11(11)+$&lt;/code&gt;. It can't match five ones, therefore it fails. But since it used &lt;code&gt;+?&lt;/code&gt;, it backtracks and matches the first three ones &lt;code&gt;111&lt;/code&gt;. The back-reference becomes &lt;code&gt;111&lt;/code&gt; and the whole regex becomes &lt;code&gt;^111(111)+$&lt;/code&gt;. It doesn't match again. This repeats for &lt;code&gt;1111&lt;/code&gt; and &lt;code&gt;11111&lt;/code&gt;, which also don't match, therefore the whole regex doesn't match and the number is a prime.&lt;/p&gt;
&lt;p&gt;The number &lt;code&gt;4&lt;/code&gt; in unary representation is &lt;code&gt;1111&lt;/code&gt;. The &lt;code&gt;(11+?)&lt;/code&gt; matches the first two ones &lt;code&gt;11&lt;/code&gt;. The back-reference &lt;code&gt;\1&lt;/code&gt; becomes &lt;code&gt;11&lt;/code&gt; and the regex becomes &lt;code&gt;^11(11)+$&lt;/code&gt;. It matches the original string, therefore the number is not a prime.&lt;/p&gt;
&lt;p&gt;PS. I didn't invent this regular expression, it was invented in 1998 by &lt;a href="http://www.abigail.be/"&gt;Abigail&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Don't take this regular expression too seriously, it's actually neither a regular expression (as defined in automata theory), nor a way to check if a number is a prime. It's just an awesome thing that Perl can do. See this cool article called &lt;a href="http://zmievski.org/2010/08/the-prime-that-wasnt"&gt;The Prime That Wasn't&lt;/a&gt; by Andrei Zmievski for a discussion about how this regex fails for larger numbers because of backtracking.&lt;/p&gt;
&lt;p&gt;Also if you wish to learn more about Perl one-liners, check out my &lt;a href="http://www.catonmat.net/blog/perl-one-liners-explained-part-one/"&gt;Perl One-Liners Explained&lt;/a&gt; article series and download the &lt;a href="http://www.catonmat.net/download/perl1line.txt"&gt;perl1line.txt&lt;/a&gt; file.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=FNJjWQWu3lo:JfP9SbL7Hbg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=FNJjWQWu3lo:JfP9SbL7Hbg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=FNJjWQWu3lo:JfP9SbL7Hbg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=FNJjWQWu3lo:JfP9SbL7Hbg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=FNJjWQWu3lo:JfP9SbL7Hbg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=FNJjWQWu3lo:JfP9SbL7Hbg:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=FNJjWQWu3lo:JfP9SbL7Hbg:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/FNJjWQWu3lo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/perl-regex-that-matches-prime-numbers</feedburner:origLink></entry>
  <entry xml:base="http://www.catonmat.net/feed">
    <title type="text">Node.js modules you should know about: jsonstream</title>
    <id>285</id>
    <updated>2012-01-03T18:42:47Z</updated>
    <published>2011-12-22T14:00:00Z</published>
    <link href="http://feedproxy.google.com/~r/catonmat/~3/X7r_RjoOs6M/nodejs-modules-jsonstream" />
    <author>
      <name>Peteris Krumins</name>
      <uri>http://www.catonmat.net/about</uri>
      <email>peter@catonmat.net</email>
    </author>
    <content type="html">
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/JpxsD4oLFsAA3BbtqlbMV--vSos/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JpxsD4oLFsAA3BbtqlbMV--vSos/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/JpxsD4oLFsAA3BbtqlbMV--vSos/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JpxsD4oLFsAA3BbtqlbMV--vSos/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://www.catonmat.net/images/nodejs-modules/nodejs-logo.png" alt="node logo" class="post-icon" align="left"&gt;Hello everyone! This is the thirteenth post in the &lt;a href="http://www.catonmat.net/blog/nodejs-modules-dnode/"&gt;node.js modules you should know about&lt;/a&gt; article series.&lt;/p&gt;
&lt;p&gt;The first post was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-dnode/"&gt;dnode&lt;/a&gt; - the freestyle rpc library for node, the second was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-optimist/"&gt;optimist&lt;/a&gt; - the lightweight options parser for node, the third was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-lazy/"&gt;lazy&lt;/a&gt; - lazy lists for node, the fourth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-request/"&gt;request&lt;/a&gt; - the swiss army knife of HTTP streaming, the fifth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-hashish/"&gt;hashish&lt;/a&gt; - hash combinators library, the sixth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-read/"&gt;read&lt;/a&gt; - easy reading from stdin, the seventh was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-ntwitter/"&gt;ntwitter&lt;/a&gt; - twitter api for node, the eighth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-socketio/"&gt;socket.io&lt;/a&gt; that makes websockets and realtime possible in all browsers, the ninth was about &lt;a href="http://www.catonmat.net/blog/nodejs-modules-redis/"&gt;redis&lt;/a&gt; - the best redis client API library for node, the tenth was on &lt;a href="http://www.catonmat.net/blog/nodejs-modules-express/"&gt;express&lt;/a&gt; - an insanely small and fast web framework for node, the eleventh was &lt;a href="http://www.catonmat.net/blog/nodejs-modules-semver/"&gt;semver&lt;/a&gt; - a node module that takes care of versioning, the twelfth was &lt;a href="http://www.catonmat.net/blog/nodejs-modules-cradle/"&gt;cradle&lt;/a&gt; - a high-level, caching, CouchDB client for node.&lt;/p&gt;
&lt;p&gt;This time I'll introduce you to a very awesome module called &lt;a href="https://github.com/dominictarr/JSONStream"&gt;JSONStream&lt;/a&gt;. JSONStream is written by &lt;a href="https://github.com/dominictarr"&gt;Dominic Tarr&lt;/a&gt; and it parses streaming JSON.&lt;/p&gt;
&lt;p&gt;Here is an example. Suppose you have couchdb view like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;total_rows&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;129&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;offset&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rows&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;change1_0.6995461115147918&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;change1_0.6995461115147918&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rev&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1-e240bae28c7bb3667f02760f6398d508&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;doc&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s2"&gt;&amp;quot;change1_0.6995461115147918&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_rev&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1-e240bae28c7bb3667f02760f6398d508&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;change2_0.6995461115147918&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;change2_0.6995461115147918&amp;quot;&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rev&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1-13677d36b98c0c075145bb8975105153&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;doc&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;&amp;quot;_id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;change2_0.6995461115147918&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;_rev&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1-13677d36b98c0c075145bb8975105153&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And you wish to only filter out &lt;code&gt;doc&lt;/code&gt; values from the &lt;code&gt;rows&lt;/code&gt;. You can do it easily with JSONStream this way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSONStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rows&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/./&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;doc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This creates a &lt;a href="http://nodejs.org/docs/latest/api/all.html#streams"&gt;stream&lt;/a&gt; that parses out &lt;code&gt;rows.*.doc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since it's a stream you have to feed it data and then have it output the data somewhere. You can do it very nicely and idiomatically in node this way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre &gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Here is the output:&lt;/p&gt;
&lt;pre &gt;
{
  _id: 'change1_0.6995461115147918',
  _rev: '1-e240bae28c7bb3667f02760f6398d508',
  hello: 1
}
{
  _id: 'change2_0.6995461115147918',
  _rev: '1-13677d36b98c0c075145bb8975105153',
  hello: 2
}
&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;req&lt;/code&gt; is request to couchdb view and &lt;code&gt;parser&lt;/code&gt; is the JSONStream parser, and it all gets piped to process.stdout. The output, as you can see, is only the &lt;code&gt;rows.*.doc&lt;/code&gt;. That was a really easy way to parse a JSON stream without reading the whole JSON into memory.&lt;/p&gt;
&lt;p&gt;You can install &lt;code&gt;JSONStream&lt;/code&gt; through npm as always:&lt;/p&gt;
&lt;pre &gt;
npm install JSONStream
&lt;/pre&gt;
&lt;p&gt;JSONStream on GitHub: &lt;a href="https://github.com/dominictarr/JSONStream"&gt;https://github.com/dominictarr/JSONStream&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Sponsor this blog series!&lt;/h2&gt;
&lt;p&gt;Doing a node.js company and want your ad to appear in the series? The ad will go out to 14,000 rss subscribers, 7,000 email subscribers, and it will get viewed by thousands of my blog visitors! &lt;a href="http://www.catonmat.net/feedback/"&gt;Email me&lt;/a&gt; and we'll set it up! &lt;/p&gt;
&lt;h2&gt;Enjoy!&lt;/h2&gt;
&lt;p&gt;If you love these articles, &lt;a href="http://www.catonmat.net/feed/" title="Subscribe to catonmat.net RSS feed"&gt;subscribe to my blog&lt;/a&gt; for more, &lt;a href="http://twitter.com/pkrumins" title="Peteris Krumins on Twitter"&gt;follow me on Twitter&lt;/a&gt; to find about my adventures, and &lt;a href="http://github.com/pkrumins" title="Peteris Krumins on GitHub"&gt;watch me produce code on GitHub&lt;/a&gt;!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=X7r_RjoOs6M:6dgXlmfj3Lg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=X7r_RjoOs6M:6dgXlmfj3Lg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=X7r_RjoOs6M:6dgXlmfj3Lg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=X7r_RjoOs6M:6dgXlmfj3Lg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?i=X7r_RjoOs6M:6dgXlmfj3Lg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=X7r_RjoOs6M:6dgXlmfj3Lg:XiUCZPyL81w"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=XiUCZPyL81w" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/catonmat?a=X7r_RjoOs6M:6dgXlmfj3Lg:DhrJZwOgkxs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/catonmat?d=DhrJZwOgkxs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/catonmat/~4/X7r_RjoOs6M" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.catonmat.net/blog/nodejs-modules-jsonstream</feedburner:origLink></entry>
</feed>

