Here's a quick tutorial on how to make unprivileged programs listen on privileged ports. The trick here is to make the unprivileged program to listen on an unprivileged port and redirect the privileged port to the unprivileged through iptables.

Here's a concrete example. Let's say you want to run a web server (on port 80) but don't want to run it as root as it has security implications. What you do instead is run your web server on port 8080 (or any other unprivileged port) and redirect port 80 to 8080 with iptables.

You'll need at least 2 iptables rules to set it up. The first rule will redirect all incoming traffic on all public interfaces from port 80 to port 8080:

iptables -A PREROUTING -t nat -p tcp --dport 80 -j REDIRECT --to-port 8080

The second rule will redirect all localhost traffic from port 80 to port 8080:

iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080

You might also need a third rule that will redirect all localhost traffic directed to the public IP (or hostname) of the service:

iptables -t nat -I OUTPUT -p tcp -d hostname.com --dport 80 -j REDIRECT --to-ports 8080

If you're unfamiliar with iptables, see the the frozen tux iptables tutorial. It's the best iptables tutorial out there.

I was recently interviewed by CodeProject who run a weekly interview series in which they talk with developers about their backgrounds, interests and pet peeves. I created a backup copy of the interview here on my blog. Here's the original.

Who are you? Tell us your name, where you live and work, your "job title" or business. Be as specific as comfort and employer policies allow.

My name is Peteris Krumins. I live in Riga, Latvia and I'm the co-founder of Browserling and Testling. I also run the popular programming blog catonmat.net.

What projects have you worked on? Tell us a bit about your daily work and the kinds of projects you've completed. If commercial products, names and URLs are great.

I've worked on over a hundred different projects. I tend to push all my code to GitHub. You can check my GitHub profile. I love writing code in a dozen different languages. I've an unorganized list of the project that I've done on my projects page. Currently my two largest projects are Browserling and Testling. Browserling lets you cross-browser test websites interactively in Internet Explorer and other browsers. Testling lets you run automatic JavaScript tests in various browsers.

Lately I've also started writing books. So far I've written three titles about the essential Unix tools Awk, Sed and Perl. My latest book about Perl is currently being republished by No Starch Press and will be available in October this year. My next title, currently work in progress, is about Bash. I publish all the book chapters for free on my blog. Once I've written all the chapters I put together the book and publish the announcement on my blog. People can then either buy the whole book or read it for free.

I like sticking to a plan and a daily schedule. At all times I've a list of things to do on my desk on an sheet of paper. Here's an example of a recent todo list.

As I finish things, I cross them off. I also keep a printed calendar in front of me with the most important things to do. Here's an example from June 2011.

I also sketch a lot when thinking about things. Here's an example of what my thought process looks like for one of the projects that I did in 2007.

I've been using this method since 2002 and it works for me really well.

What is your development environment? Tell us about your hardware, development tools and most-used or favorite languages and frameworks.

Here's an image from a few years ago that shows my development environment.

And here's another image from a while ago.

I use desktop PCs only. I still run Windows XP on my workstation. It's a 3.2Ghz Pentium 4 with 2 gigs of memory from 2004. It gets the job done. I use two shared screens and a Microsoft Natural keyboard. I don't enjoy laptops because of the small keyboard and the impossible-to-use mouse (touchpad) that they have. I also run two Slackware Linux servers. One as a file server and the other as a development server. The file server runs Samba and is mapped on Windows XP. I also have a bunch of servers for testing and experimenting.

My favorite development tool is Visual Studio 2008. I do most of the C and C++ development in it. Nothing beats IntelliSense and MSDN documentation. I use vim to write in JavaScript, HTML, Python, Perl and other languages. My favorite language is Perl because it's so concise and I can prototype things in it very quickly. I don't enjoy frameworks as it's often much quicker to write a basic version of the same thing than to learn how to use the framework.

What new tools, languages or frameworks are you playing with (or just interested in exploring more)?

I'm currently not playing with any new tools because I love to get things done with the existing tools. The new tools are often confusing, change too fast and/or are too experimental. I only adopt the new tools once they've become old and have survived.

What is your coding pet peeve? Favorite naming convention? Hungarian, camelCase? Indentation style? K&R, Allman, etc.?

It depends on the language that I use and the environment and context I'm working in. For example, if I'm writing a C program from scratch I stick with the_following_naming_convention and 4 spaces for a tab. However if I'm contributing to some project, I'm using the naming convention, and indentation style of the existing project so that my contributions get accepted. If I'm writing a Windows program in MCF, I stick to Hungarian notation. If I'm writing Java, I mostly use camelCase, etc.

How did you get started programming? Tell us about your first computer and programming language.

I learned a bunch of different languages at once very quickly. I learned Pascal, mIRC scripts, HTML, JavaScript, C and Visual Basic all at once. I got my first computer on September 1st, 2000. It was was a Celeron 400 with 256mb of memory and it ran Windows 98. Before that I was writing code on paper at home and trying it out at a local university. A friend of mine called Zombie also helped me a lot with learning programming and Linux.

How has the developer community - online and offline - influenced your coding? What do you like or dislike about the dev community? Are you actively using forums, Twitter, LinkedIn, GitHub or other online resources?

I don't enjoy communities in general. As soon as you're part of a community people assign all the philosophy that goes with the community to you. I like being individual.

What one piece of advice would you give to an up-and-coming programmer?

Get things done and move on.

Who would you like to see us interview?

My friend Amir Salihefendic (https://twitter.com/amix3k). We worked together at a startup called Plurk. He's an amazing developer who gets things done.

I created an ASCII cheat sheet from the table that I used in my blog post about my favorite regular expression. I know there are a billion ASCII cheat sheets out there but I wanted my own. This cheat sheet includes dec, hex, oct and bin values for ASCII characters.


download ascii cheat sheet

Also see my other cheat sheets.

Six Years of BloggingHey everyone! Another year has passed and it's been 6 years since I've been blogging here on catonmat! In this post I wish to summarize this year's statistics.

See the one year of blogging, two years of blogging, three years of blogging, four years of blogging, and five years of blogging for the previous year statistics.

Let's start this year's stats with traffic:



Traffic statistics from Google Analytics for Jul 1, 2012 - Jun 30, 2013.

This year: 903,468 uniques. 1,191,596 visits. 1,695,544 page views.
Last year: 988,295 uniques. 1,374,228 visits. 1,940,530 page views.
Delta: -84,827 unqiues. -182,632 visits. -244,986 page views.

I haven't been blogging as much as in the previous year and that explains the negative delta.

Feedburner stats: At 16,343 rss subscribers this year. Last year 14,362. Delta +1,981. subscribe.
Github stats: At 1400 followers this year. Last year 1070. Delta +330. follow me.
Twitter stats: At 3774 followers this year. Last year 3093. Delta +681. follow me.

Subscriptions and followers grow over time, which explains the positive delta.

Total articles written: 25. Top 10 articles:

My top 5 favorite articles:

During this year I made 4 announcements:

That's all folks! Now let's have some 6 year birthday cake,

And let's meet for the cake next year again! See you!

This guide covers the ins-and-outs of tape, a simple TAP-producing test library for node and browsers. The tape API is a small superset of the node core assert module.

This guide was written for Testling. Testling lets you write continuous integration cross-browser tests that run on every git push! Once the tests run you get a badge you can put in your readme with the current browser test status. Here's how it looks:


Click the badge to learn how to write Testling tests!

For an exaustive list of all the methods that tape supports, consult the tape readme.

Simple equality with a plan

Most of the time, you'll just need to plan out a few simple asserts with t.equal(), which uses === internally:

var test = require('tape');

test('basic arithmetic', function (t) {
    t.plan(2);

    t.equal(2 + 3, 5);
    t.equal(7 * 8 + 9, 65);
});

If you want you can leave off the test name and just do:

var test = require('tape');

test(function (t) {
    t.plan(2);

    t.equal(2 + 3, 5);
    t.equal(7 * 8 + 9, 65);
});

Simple equality with an end

If you have an indefinite number of assertions, sometimes it's easier to call t.end() instead:

var test = require('tape');

test('basic arithmetic', function (t) {
    t.equal(2 + 3, 5);
    t.equal(7 * 8 + 9, 65);

    t.end();
});

Deep equality

To compare array and object references deeply, you can use t.deepEqual():

var test = require('tape');

test('deep equality', function (t) {
    t.plan(2);

    t.deepEqual([ 3, 4, 5 ], [ 3, 4, 2+3 ]);
    t.deepEqual(
        { a: 7, b: [ 8, 9 ] },
        { a : 3+4, b: [ 4*2 ].concat(3*3) }
    );
});

Comparing booleans

Just use .ok() to assert truthiness:

var test = require('tape');

test('comparing booleans', function (t) {
    t.plan(1);

    t.ok(3 > 4 || 5 > 2);
});

Negations

For each kind of assertion, prepend (and camel-case) a "not" to turn it into a negative assertion:

var test = require('tape');

test('negatives', function (t) {
    t.plan(3);
    t.notEqual(1+2, 5);
    t.notDeepEqual([1,2], [12]);
    t.notOk(false);
});

Pass/fail

If you need a test to just fail, you can call t.fail():

var test = require('tape');

test('empty map', function (t) {
    [].map(function (x) {
        t.fail('this callback should never fire');
    });

    t.end();
});

Conversely, there is a t.pass() which always succeeds:

var test = require('tape');

test('map with elements', function (t) {
    t.plan(2);

    [2,3].map(function (x) {
        t.pass();
    });
});

More info

You can always add an assertion description as the last argument:

var test = require('tape');

test('more info', function (t) {
    t.plan(2);

    t.equal(1+2, 3, 'basic arithmetic still works');
    t.ok(3+4>5, 'inequalities are as we might expect');
});

Asynchronous

Since we either plan out the number of assertions explicitly with t.plan(n) or end the test explicitly with t.end(), we don't need to do anything differently when our tests make asynchronous calls:

var test = require('tape');

test('asynchronous results', function (t) {
    t.plan(2);

    t.equal(2+3, 5);

    setTimeout(function () {
        t.equal(5+5, 10);
    }, 500);
});

Multiple serial tests

var test = require('tape');

test('first', function (t) {
    t.plan(1);
    setTimeout(function () { t.ok(true) }, 200);
});

test('second', function (t) {
    t.plan(1);
    setTimeout(function () { t.ok(true) }, 100);
});

The 'first' test will run, then the 'second'.

Nesting tests

You probably shouldn't do this very often, but you can have nested tests too:

var test = require('tape');

test('nested', function (t) {
    t.test(function (st) {
        st.plan(1);
        st.equal(1+2, 3);
    });

    t.test(function (st) {
        st.plan(1);
        setTimeout(function () {
            st.pass();
        }, 100);
    });
});

Running a tape test in node

Just run your test file directly with node:

$ node test/def.js 
TAP version 13
# defined-or
ok 1 empty arguments
ok 2 1 undefined
ok 3 2 undefined
ok 4 4 undefineds
ok 5 false[0]
ok 6 false[1]
ok 7 zero[0]
ok 8 zero[1]
ok 9 first arg
ok 10 second arg
ok 11 third arg

1..11
# tests 11
# pass  11

# ok

Running a directory full of tape tests in node

If you npm install -g tape, you get a test runner for running directories full of tests all at once:

$ tape test/*.js
TAP version 13
# defined-or
ok 1 empty arguments
ok 2 1 undefined
ok 3 2 undefined
ok 4 4 undefineds
ok 5 false[0]
ok 6 false[1]
ok 7 zero[0]
ok 8 zero[1]
ok 9 first arg
ok 10 second arg
ok 11 third arg
# (anonymous)
ok 12 should be equal

1..12
# tests 12
# pass  12

# ok

You could also use the test runner from the tap module for more terse output. First npm install -g tap, then do:

$ tap test/*.js
ok test/def.js ........................................ 12/12
ok test/falsy.js ........................................ 2/2
total ................................................. 14/14

ok

In the test runner scripts for both tap and tape you will get lots of output including line numbers when an assertion fails.

Running a tape test in a browser

First npm install -g browserify, then you can do:

$ browserify test.js > bundle.js
$ echo '<script src="bundle.js"></script>' > test.html

Then open test.html in a browser and look at the test output in the debugger. tape writes all its output to console.log() by default.

If you want to run your tests in a real headless browser locally, npm install -g testling then do:

$ browserify test.js | testling
TAP version 13
# defined-or
ok 1 empty arguments
ok 2 1 undefined
ok 3 2 undefined
ok 4 4 undefineds
ok 5 false[0]
ok 6 false[1]
ok 7 zero[0]
ok 8 zero[1]
ok 9 first arg
ok 10 second arg
ok 11 third arg

1..11
# tests 11
# pass  11

# ok

and your test will run in chrome or firefox headlessly, depending which you have installed on your system. The console.log() output is proxied from the browser to your stdout and the testling command generates an exit code by parsing the TAP output.

Running a directory full of tape tests in a browser

To run multiple tests, just use a file glob:

$ browserify test/*.js | testling
TAP version 13
# defined-or
ok 1 empty arguments
ok 2 1 undefined
ok 3 2 undefined
ok 4 4 undefineds
ok 5 false[0]
ok 6 false[1]
ok 7 zero[0]
ok 8 zero[1]
ok 9 first arg
ok 10 second arg
ok 11 third arg
# (anonymous)
ok 12 should be equal

1..12
# tests 12
# pass  12

# ok

Running tape tests on Testling

To get your tape tests running on testling simply add the "testling" field to package.json

"testling" : {
    "files" : "test/*.js",
    "browsers" : {
        "ie" : [ 6, 7, 8, 9, 10 ],
        "ff" : [ 3.5, 10, 15.0, 16.0, 17.0 ],
        "chrome" : [ 10, 20, 21, 22, 23 ],
        "safari" : [ 5.1 ],
        "opera" : [ 10, 11, 12 ]
    }
}

and setup a github hook to point to git.testling.com. Now every time you push to github the tape tests will run in all the specified browsers.

To learn more about how to write testling tests, see this article.

Conclusion

If you need more complicated abstractions in your tests, just npm install them and require() them in your tests. Just be careful that the libraries you're importing also work in browsers.

Tape shows that you don't actually need very much API to test your libraries in a powerful and flexible way that works in node and in browsers.