debuggable

 
Contact Us
 
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10

Burning Apple

Posted on 13/10/09 by Felix Geisendörfer

Apple fanboy? Caught in the distortion field? No problem, there is a cure:

Play video

As you can see, I have not always been a Mac user. In fact I passionately hated anything Mac after my first contact with an iMac (OS 10.3). I did this video in 2005 while I was a foreign exchange student in Atlanta. My friend in the video is still using PCs - don't flash you fancy macbook next to him in a coffee shop!

Why I have held back posting this for so long? I just integrated transload.it into debuggable.com and needed a video to test. More gems like this are on their way : ).

-- Felix Geisendörfer aka the_undefined

 

7 + 8 === 7 in JavaScript

Posted on 6/10/09 by Felix Geisendörfer

I kid you not, this is an issue I actually ran into a long time ago and have been terribly careful of avoiding ever since.

It must have been a fantastic day in the "Bad Parts" JavaScript department. While one team was busy screwing up the + operator to be responsible for both string concatenation and addition, another team set out to build a nasty trap inside the parseInt() function.

This together results in probably my favourite JavaScript bug of all times. It goes like this: You have two strings that contain zero padded numbers (like hours or minutes) and you want to perform some math on them:

var a = '07';
var b = '08'

alert(a + b);

Of course you would not write such code, but maybe you have a friend who has done it. This friend probably quickly realized that '0708' was not the result he was hoping for, so he got clever and updated his code to:

var a = '07';
var b = '08'

alert(parseInt(a) + parseInt(b));

However, it turns out that the result of this operation is actually 7. SEVEN you ask? Yes: it's not a bug, it's a feature.

JavaScript assumes that any 0-prefixed string ought to be referring to an octal number. This will not become apparent until your string represents an invalid octal such as '08'. So in order to outsmart this "feature" you have to explicitly provide the base for your integer:

var a = '07';
var b = '08'

alert(parseInt(a, 10) + parseInt(b, 10));

I hope this will one day safe somebody the hour of my life that went into this : ).

-- Felix Geisendörfer aka the_undefined

PS: Got a great JavaScript bug like this as well? I'd be happy to hear about it in the comments.

 

Turning JavaScript's arguments object into an array

Posted on 1/10/09 by Felix Geisendörfer

JavaScript is awesome when you stick to the good parts. But sometimes you have to touch it's bad parts. Consider this:

function hello() {
    arguments.unshift('hello');
    alert(arguments.join(' '));
}

hello('pretty', 'world');

"TypeError: arguments. unshift is not a function"! How dare you JavaScript?

JavaScript might trick you into thinking the arguments variable is an array because you can access it like one (arguments[0], arguments[1], ...), but it's lying. The truth is that the arguments variable really is an object.

Lucky for us, the good parts of JavaScript come to rescue, namely prototypical inheritance:

function hello() {
    var args = Array.prototype.slice.call(arguments);
    args.unshift('hello');
    alert(args.join(' '));
}

hello('pretty', 'world');

This creates a variable called args that holds a true array version of the arguments variable. This works by hjacking the Array.splice function to make it work on the arguments variable.

Yes, this is the kind of code you might want to document for the poor kids who will have to debug grandpa's "AJAX museum" one day.

Got a better solution? Let me know!

-- Felix Geisendörfer aka the_undefined

 

Going to JSConf.eu

Posted on 1/10/09 by Felix Geisendörfer

Tim and I just got our tickets for the upcoming JSConf.eu in Berlin. It's almost sold out now, but in case you already have a ticket let us know so we can hang out.

I'm very thrilled about the speaker lineup (Amy Hoy, Thomas Fuchs, John Resig, Dion Almaer & Ben Galbraith, Douglas Crockford, Ryan Dahl, Kevin Dangoor, Kyle Simpson, Steve Souders). It's especially exciting to see that Ryan Dahl has been selected as a speaker to talk about node.js, my new favourite OS project!

I will try my best to cover his as well as some of the other talks for the blog!

-- Felix Geisendörfer aka the_undefined

 

Streaming file uploads with node.js

Posted on 28/9/09 by Felix Geisendörfer

Update: I just updated the code so it works with node v0.1.18.

Not excited by hello world in node.js? No problem.

Let's say you are a startup focusing on upload technology and you want the maximum level of control for your file uploads. In our case that means having the ability to directly interact with the multipart data stream as it comes in (so we can abort the upload if something isn't right, - beats the hell out of letting the user wait an hour to tell him after the upload has finished).

Here is a complete example on how to accomplish this in node.js (you'll need the bleeding edge git version):

var http = require('http');
var multipart = require('multipart');
var sys = require('sys');

var server = http.createServer(function(req, res) {
  switch (req.uri.path) {
    case '/':
      display_form(req, res);
      break;
    case '/upload':
      upload_file(req, res);
      break;
    default:
      show_404(req, res);
      break;
  }
});
server.listen(8000);

function display_form(req, res) {
  res.sendHeader(200, {'Content-Type': 'text/html'});
  res.sendBody(
    '<form action="/upload" method="post" enctype="multipart/form-data">'+
    '<input type="file" name="upload-file">'+
    '<input type="submit" value="Upload">'+
    '</form>'
  );
  res.finish();
}

function upload_file(req, res) {
  req.setBodyEncoding('binary');

  var stream = new multipart.Stream(req);
  stream.addListener('part', function(part) {
    part.addListener('body', function(chunk) {
      var progress = (stream.bytesReceived / stream.bytesTotal * 100).toFixed(2);
      var mb = (stream.bytesTotal / 1024 / 1024).toFixed(1);

      sys.print("Uploading "+mb+"mb ("+progress+"%)\015");

      // chunk could be appended to a file if the uploaded file needs to be saved
    });
  });
  stream.addListener('complete', function() {
    res.sendHeader(200, {'Content-Type': 'text/plain'});
    res.sendBody('Thanks for playing!');
    res.finish();
    sys.puts("\n=> Done");
  });
}

function show_404(req, res) {
  res.sendHeader(404, {'Content-Type': 'text/plain'});
  res.sendBody('You r doing it rong!');
  res.finish();
}

The code is rather straight forward. First of all we include the multipart.js parser which is a library that has just been added to node.js.

Next we create a server listening on port 8000 that dispatches incoming requests to one of our 3 functions: display_form, upload_file or show_404. Again, very straight forward.

display_form serves a very short (and invalid) piece of HTML that will render a file upload form with a submit button. You can get to it by running the example (via: node uploader.js) and pointing your browser to http://localhost:8000/.

upload_file kicks in as soon as you select a file and hit the submit button. It tells the request object to expect binary data and then passes the work on to the multipart Stream parser. The result is a new stream object that emits two kinds of events: 'part' and 'complete'. 'part' is called whenever a new element is found within the multipart stream, you can find all the information about it by looking at the first argument's headers property. In order to get the actual contents of this part we attach a 'body' listener to it, which gets called for each chunk of bytes getting uploaded. In our example we just use this event to render a progress indicator in our command line, but we could also append this chunk to a file which would eventually become the entire file as uploaded from the browser. Finally the 'complete' event sends a response to the browser indicating the file has been uploaded.

show_404 is handling all unknown urls by returning an error response.

As you can see, the entire process is pretty simple, yet gives you a ton of control. You can also easily use this technique to show an AJAX progress bar for the upload to your users. The multipart parser also works with non-HTTP requests, just pass it the {boundary: '...'} option into the constructor and use steam.write() to pass it some data to parse. Check out the source of the parser if you're curious how it works internally.

-- Felix Geisendörfer aka the_undefined

 
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10