[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#924627: unblock: node-formidable/1.2.1-1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package node-formidable

Hello,

node-formidable hasn't been updated for years. Testing version isn't
compatible with our nodejs but this was not seen since there was no
real tests (see https://bugs.debian.org/924589).

I upgraded it and added full tests (build and autopkgtest).

node-formidable reverse dependencies:
 - node-superagent:
   +- node-multiparty (no reverse dependencies)

node-formidable bug does not affect these packages since the failing
functions are not used in it, that's why I decrease bug severity to
important. I tested the 2 reverse dependencies with both old and new
node-formidable with success (sbuild and autopkgtest).

debdiff is big since I embedded some node modules (only for tests, they
are not installed). Upstream changes are not so big. I updated also
debian/* files and added examples (and tests of course).

I think it's not risky to update node-formidable. However I leave you
appreciate if it is opportune.

Cheers,
Xavier

unblock node-formidable/1.2.1-1

-- System Information:
Debian Release: buster/sid
  APT prefers testing
  APT policy: (900, 'testing'), (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 4.19.0-2-amd64 (SMP w/8 CPU cores)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8),
LANGUAGE= (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..45032a1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/test/tmp/*
+*.upload
+*.un~
+/node_modules/*
diff --git a/.npmignore b/.npmignore
index 4fbabb3..ed16858 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,4 +1,7 @@
-/test/tmp/
+/test
+/tool
+/example
+/benchmark
 *.upload
 *.un~
 *.http
diff --git a/.travis.yml b/.travis.yml
index cb931cb..694a62f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
 language: node_js
 node_js:
-  - 0.8
-  - 0.9
-  - "0.10"
+  - 4
+  - 6
+  - 7
diff --git a/Readme.md b/Readme.md
index 1aecf08..ee1abfe 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,13 +1,15 @@
 # Formidable
 
-[![Build Status](https://secure.travis-ci.org/felixge/node-formidable.png?branch=master)](http://travis-ci.org/felixge/node-formidable)
+[![Build Status](https://travis-ci.org/felixge/node-formidable.svg?branch=master)](https://travis-ci.org/felixge/node-formidable)
 
 ## Purpose
 
-A node.js module for parsing form data, especially file uploads.
+A Node.js module for parsing form data, especially file uploads.
 
 ## Current status
 
+**Maintainers Wanted:** Please see https://github.com/felixge/node-formidable/issues/412
+
 This module was developed for [Transloadit](http://transloadit.com/), a service focused on uploading
 and encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from
 a large variety of clients and is considered production-ready.
@@ -22,17 +24,12 @@ a large variety of clients and is considered production-ready.
 
 ## Installation
 
-Via [npm](http://github.com/isaacs/npm):
-```
-npm install formidable@latest
-```
-Manually:
-```
-git clone git://github.com/felixge/node-formidable.git formidable
-vim my.js
-# var formidable = require('./formidable');
+```sh
+npm i -S formidable
 ```
 
+This is a low-level package, and if you're using a high-level framework it may already be included. However, [Express v4](http://expressjs.com) does not include any multipart handling, nor does [body-parser](https://github.com/expressjs/body-parser).
+
 Note: Formidable requires [gently](http://github.com/felixge/node-gently) to run the unit tests, but you won't need it for just using the library.
 
 ## Example
@@ -82,11 +79,10 @@ form.encoding = 'utf-8';
 Sets encoding for incoming form fields.
 
 ```javascript
-form.uploadDir = process.env.TMP || process.env.TMPDIR || process.env.TEMP || '/tmp' || process.cwd();
+form.uploadDir = "/my/dir";
 ```
-The directory for placing file uploads in. You can move them later on using
-`fs.rename()`. The default directory is picked at module load time depending on
-the first existing directory from those listed above.
+Sets the directory for placing file uploads in. You can move them later on using
+`fs.rename()`. The default is `os.tmpdir()`.
 
 ```javascript
 form.keepExtensions = false;
@@ -99,23 +95,35 @@ form.type
 Either 'multipart' or 'urlencoded' depending on the incoming request.
 
 ```javascript
-form.maxFieldsSize = 2 * 1024 * 1024;
+form.maxFieldsSize = 20 * 1024 * 1024;
+```
+Limits the amount of memory all fields together (except files) can allocate in bytes.
+If this value is exceeded, an `'error'` event is emitted. The default
+size is 20MB.
+
+```javascript
+form.maxFileSize = 200 * 1024 * 1024;
 ```
-Limits the amount of memory a field (not file) can allocate in bytes.
+Limits the size of uploaded file.
 If this value is exceeded, an `'error'` event is emitted. The default
-size is 2MB.
+size is 200MB.
 
 ```javascript
-form.maxFields = 0;
+form.maxFields = 1000;
 ```
 Limits the number of fields that the querystring parser will decode. Defaults
-to 0 (unlimited).
+to 1000 (0 for unlimited).
 
 ```javascript
 form.hash = false;
 ```
 If you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`.
 
+```javascript
+form.multiples = false;
+```
+If this option is enabled, when you call `form.parse`, the `files` argument will contain arrays of files for inputs which submit multiple files using the HTML5 `multiple` attribute.
+
 ```javascript
 form.bytesReceived
 ```
@@ -129,7 +137,7 @@ The expected number of bytes in this form.
 ```javascript
 form.parse(request, [cb]);
 ```
-Parses an incoming node.js `request` containing form data. If `cb` is provided, all fields an files are collected and passed to the callback:
+Parses an incoming node.js `request` containing form data. If `cb` is provided, all fields and files are collected and passed to the callback:
 
 
 ```javascript
@@ -198,15 +206,20 @@ If hash calculation was set, you can read the hex digest out of this var.
 
 
 #### 'progress'
+
+Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.
+
 ```javascript
 form.on('progress', function(bytesReceived, bytesExpected) {
 });
 ```
-Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.
 
 
 
 #### 'field'
+
+Emitted whenever a field / value pair has been received.
+
 ```javascript
 form.on('field', function(name, value) {
 });
@@ -214,7 +227,10 @@ form.on('field', function(name, value) {
 
 #### 'fileBegin'
 
-Emitted whenever a field / value pair has been received.
+Emitted whenever a new file is detected in the upload stream. Use this event if
+you want to stream the file to somewhere else while buffering the upload on
+the file system.
+
 ```javascript
 form.on('fileBegin', function(name, file) {
 });
@@ -222,11 +238,8 @@ form.on('fileBegin', function(name, file) {
 
 #### 'file'
 
-Emitted whenever a new file is detected in the upload stream. Use this even if
-you want to stream the file to somewhere else while buffering the upload on
-the file system.
-
 Emitted whenever a field / file pair has been received. `file` is an instance of `File`.
+
 ```javascript
 form.on('file', function(name, file) {
 });
@@ -235,6 +248,7 @@ form.on('file', function(name, file) {
 #### 'error'
 
 Emitted when there is an error processing the incoming form. A request that experiences an error is automatically paused, you will have to manually call `request.resume()` if you want the request to continue firing `'data'` events.
+
 ```javascript
 form.on('error', function(err) {
 });
@@ -243,7 +257,7 @@ form.on('error', function(err) {
 #### 'aborted'
 
 
-Emitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. In the future there will be a separate 'timeout' event (needs a change in the node core).
+Emitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. After this event is emitted, an `error` event will follow. In the future there will be a separate 'timeout' event (needs a change in the node core).
 ```javascript
 form.on('aborted', function() {
 });
@@ -260,11 +274,30 @@ Emitted when the entire request has been received, and all contained files have
 
 ## Changelog
 
+### v1.1.1 (2017-01-15)
+
+ * Fix DeprecationWarning about os.tmpDir() (Christian)
+ * Update `buffer.write` order of arguments for Node 7 (Kornel Lesiński)
+ * JSON Parser emits error events to the IncomingForm (alessio.montagnani)
+ * Improved Content-Disposition parsing (Sebastien)
+ * Access WriteStream of fs during runtime instead of include time (Jonas Amundsen)
+ * Use built-in toString to convert buffer to hex (Charmander)
+ * Add hash to json if present (Nick Stamas)
+ * Add license to package.json (Simen Bekkhus)
+
+### v1.0.14 (2013-05-03)
+
+* Add failing hash tests. (Ben Trask)
+* Enable hash calculation again (Eugene Girshov)
+* Test for immediate data events (Tim Smart)
+* Re-arrange IncomingForm#parse (Tim Smart)
+
 ### v1.0.13
 
 * Only update hash if update method exists (Sven Lito)
 * According to travis v0.10 needs to go quoted (Sven Lito)
 * Bumping build node versions (Sven Lito)
+* Additional fix for empty requests (Eugene Girshov)
 * Change the default to 1000, to match the new Node behaviour. (OrangeDog)
 * Add ability to control maxKeys in the querystring parser. (OrangeDog)
 * Adjust test case to work with node 0.9.x (Eugene Girshov)
@@ -284,120 +317,12 @@ Emitted when the entire request has been received, and all contained files have
 * Remove support for Node.js 0.4 & 0.6 (Andrew Kelley)
 * Documentation improvements (Sven Lito, Andre Azevedo)
 * Add support for application/octet-stream (Ion Lupascu, Chris Scribner)
-* Use os.tmpDir() to get tmp directory (Andrew Kelley)
+* Use os.tmpdir() to get tmp directory (Andrew Kelley)
 * Improve package.json (Andrew Kelley, Sven Lito)
 * Fix benchmark script (Andrew Kelley)
 * Fix scope issue in incoming_forms (Sven Lito)
 * Fix file handle leak on error (OrangeDog)
 
-### v1.0.11
-
-* Calculate checksums for incoming files (sreuter)
-* Add definition parameters to "IncomingForm" as an argument (Math-)
-
-### v1.0.10
-
-* Make parts to be proper Streams (Matt Robenolt)
-
-### v1.0.9
-
-* Emit progress when content length header parsed (Tim Koschützki)
-* Fix Readme syntax due to GitHub changes (goob)
-* Replace references to old 'sys' module in Readme with 'util' (Peter Sugihara)
-
-### v1.0.8
-
-* Strip potentially unsafe characters when using `keepExtensions: true`.
-* Switch to utest / urun for testing
-* Add travis build
-
-### v1.0.7
-
-* Remove file from package that was causing problems when installing on windows. (#102)
-* Fix typos in Readme (Jason Davies).
-
-### v1.0.6
-
-* Do not default to the default to the field name for file uploads where
-  filename="".
-
-### v1.0.5
-
-* Support filename="" in multipart parts
-* Explain unexpected end() errors in parser better
-
-**Note:** Starting with this version, formidable emits 'file' events for empty
-file input fields. Previously those were incorrectly emitted as regular file
-input fields with value = "".
-
-### v1.0.4
-
-* Detect a good default tmp directory regardless of platform. (#88)
-
-### v1.0.3
-
-* Fix problems with utf8 characters (#84) / semicolons in filenames (#58)
-* Small performance improvements
-* New test suite and fixture system
-
-### v1.0.2
-
-* Exclude node\_modules folder from git
-* Implement new `'aborted'` event
-* Fix files in example folder to work with recent node versions
-* Make gently a devDependency
-
-[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.1...v1.0.2)
-
-### v1.0.1
-
-* Fix package.json to refer to proper main directory. (#68, Dean Landolt)
-
-[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.0...v1.0.1)
-
-### v1.0.0
-
-* Add support for multipart boundaries that are quoted strings. (Jeff Craig)
-
-This marks the beginning of development on version 2.0 which will include
-several architectural improvements.
-
-[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.11...v1.0.0)
-
-### v0.9.11
-
-* Emit `'progress'` event when receiving data, regardless of parsing it. (Tim Koschützki)
-* Use [W3C FileAPI Draft](http://dev.w3.org/2006/webapi/FileAPI/) properties for File class
-
-**Important:** The old property names of the File class will be removed in a
-future release.
-
-[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.10...v0.9.11)
-
-### Older releases
-
-These releases were done before starting to maintain the above Changelog:
-
-* [v0.9.10](https://github.com/felixge/node-formidable/compare/v0.9.9...v0.9.10)
-* [v0.9.9](https://github.com/felixge/node-formidable/compare/v0.9.8...v0.9.9)
-* [v0.9.8](https://github.com/felixge/node-formidable/compare/v0.9.7...v0.9.8)
-* [v0.9.7](https://github.com/felixge/node-formidable/compare/v0.9.6...v0.9.7)
-* [v0.9.6](https://github.com/felixge/node-formidable/compare/v0.9.5...v0.9.6)
-* [v0.9.5](https://github.com/felixge/node-formidable/compare/v0.9.4...v0.9.5)
-* [v0.9.4](https://github.com/felixge/node-formidable/compare/v0.9.3...v0.9.4)
-* [v0.9.3](https://github.com/felixge/node-formidable/compare/v0.9.2...v0.9.3)
-* [v0.9.2](https://github.com/felixge/node-formidable/compare/v0.9.1...v0.9.2)
-* [v0.9.1](https://github.com/felixge/node-formidable/compare/v0.9.0...v0.9.1)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.1.0](https://github.com/felixge/node-formidable/commits/v0.1.0)
-
 ## License
 
 Formidable is licensed under the MIT license.
diff --git a/benchmark/bench-multipart-parser.js b/benchmark/bench-multipart-parser.js
index 49abc43..1978e58 100644
--- a/benchmark/bench-multipart-parser.js
+++ b/benchmark/bench-multipart-parser.js
@@ -44,7 +44,7 @@ parser.onEnd = function() {
 
 var start = +new Date(),
     nparsed = parser.write(buffer),
-    duration = +new Date - start,
+    duration = +new Date() - start,
     mbPerSec = (mb / (duration / 1000)).toFixed(2);
 
 console.log(mbPerSec+' mb/sec');
@@ -59,8 +59,8 @@ function createMultipartBuffer(boundary, size) {
     , tail = '\r\n--'+boundary+'--\r\n'
     , buffer = new Buffer(size);
 
-  buffer.write(head, 'ascii', 0);
-  buffer.write(tail, 'ascii', buffer.length - tail.length);
+  buffer.write(head, 0, 'ascii');
+  buffer.write(tail, buffer.length - tail.length, 'ascii');
   return buffer;
 }
 
diff --git a/debian/changelog b/debian/changelog
index d929834..d805bea 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,22 @@
+node-formidable (1.2.1-1) unstable; urgency=medium
+
+  * Team upload
+  * Bump debhelper compatibility level to 11
+  * Declare compliance with policy 4.3.0
+  * Change section to javascript
+  * Change priority to optional
+  * Update debian/watch
+  * New upstream version 1.2.1 (Closes: #924589)
+  * Add upstream/metadata
+  * Enable tests using pkg-js-tools
+  * Fix VCS fields
+  * Update debian/copyright
+  * Update debian/copyright
+  * Fix install
+  * Install examples
+
+ -- Xavier Guimard <yadd@debian.org>  Thu, 14 Mar 2019 21:17:08 +0100
+
 node-formidable (1.0.13-1) unstable; urgency=low
 
   * Initial release (Closes: #703836)
diff --git a/debian/clean b/debian/clean
new file mode 100644
index 0000000..b979df5
--- /dev/null
+++ b/debian/clean
@@ -0,0 +1 @@
+test/tmp/*
diff --git a/debian/compat b/debian/compat
index 45a4fb7..b4de394 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-8
+11
diff --git a/debian/control b/debian/control
index 115429b..1bab968 100644
--- a/debian/control
+++ b/debian/control
@@ -1,21 +1,23 @@
 Source: node-formidable
-Section: web
-Priority: extra
 Maintainer: Debian Javascript Maintainers <pkg-javascript-devel@lists.alioth.debian.org>
 Uploaders: Jérémy Lal <kapouer@melix.org>
-Build-Depends:
- debhelper (>= 8.0.0)
- , dh-buildinfo
-Standards-Version: 3.9.3
+Section: javascript
+Testsuite: autopkgtest-pkg-nodejs
+Priority: optional
+Build-Depends: debhelper (>= 11~),
+               nodejs,
+               node-hashish,
+               node-request,
+               pkg-js-tools
+Standards-Version: 4.3.0
+Vcs-Browser: https://salsa.debian.org/js-team/node-formidable
+Vcs-Git: https://salsa.debian.org/js-team/node-formidable.git
 Homepage: https://github.com/felixge/node-formidable
-Vcs-Git: git://git.debian.org/collab-maint/node-formidable.git
-Vcs-Browser: http://git.debian.org/?p=collab-maint/node-formidable.git
 
 Package: node-formidable
 Architecture: all
-Depends:
- ${misc:Depends}
- , nodejs
+Depends: ${misc:Depends},
+         nodejs
 Description: Multipart form data parser module for Node.js
  node-formidable is a well-tested parser for multipart/form-data sent by
  http clients. It emphasizes support for file uploads.
diff --git a/debian/copyright b/debian/copyright
index a68a70b..2dd5262 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,10 +1,35 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Upstream-Name: formidable
 
 Files: *
-Copyright: 2011 Felix Geisendörfer <felix@debuggable.com>
+Copyright: 2011-2013, Felix Geisendörfer <felix@debuggable.com>
 License: Expat
 
+Files: debian/*
+Copyright: 2013, Jérémy Lal <kapouer@melix.org>
+ 2019, Xavier Guimard <yadd@debian.org>
+License: Expat
+
+Files: debian/tests/node_modules/chainsaw/*
+Copyright: 2010, James Halliday <mail@substack.net>
+License: Expat
+
+Files: debian/tests/node_modules/findit/*
+Copyright: 2013-2014, James Halliday <mail@substack.net>
+License: Expat
+Comment: The upstream distribution does not contain an explicit statement of
+ copyright ownership. Pursuant to the Berne Convention for the Protection of
+ Literary and Artistic Works, it is assumed that all content is copyright by
+ its respective authors unless otherwise stated.
+
+Files: debian/tests/node_modules/seq/*
+Copyright: 2011, James Halliday <mail@substack.net>
+License: Expat
+Comment: The upstream distribution does not contain an explicit statement of
+ copyright ownership. Pursuant to the Berne Convention for the Protection of
+ Literary and Artistic Works, it is assumed that all content is copyright by
+ its respective authors unless otherwise stated.
+
 License: Expat
  Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the
diff --git a/debian/examples b/debian/examples
new file mode 100644
index 0000000..0bbe99e
--- /dev/null
+++ b/debian/examples
@@ -0,0 +1 @@
+example/*
diff --git a/debian/install b/debian/install
index bce9365..4af254f 100644
--- a/debian/install
+++ b/debian/install
@@ -1 +1,2 @@
-lib/*	usr/lib/nodejs/formidable/
+lib	usr/lib/nodejs/formidable/
+package.json	usr/lib/nodejs/formidable/
diff --git a/debian/rules b/debian/rules
index 218df65..20809a4 100755
--- a/debian/rules
+++ b/debian/rules
@@ -5,4 +5,4 @@
 #export DH_VERBOSE=1
 
 %:
-	dh $@
+	dh $@ --with nodejs
diff --git a/debian/tests/node_modules/chainsaw/README.markdown b/debian/tests/node_modules/chainsaw/README.markdown
new file mode 100644
index 0000000..9bb1259
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/README.markdown
@@ -0,0 +1,140 @@
+Chainsaw
+========
+
+Build chainable fluent interfaces the easy way in node.js.
+
+With this meta-module you can write modules with chainable interfaces.
+Chainsaw takes care of all of the boring details and makes nested flow control
+super simple too.
+
+Just call `Chainsaw` with a constructor function like in the examples below.
+In your methods, just do `saw.next()` to move along to the next event and
+`saw.nest()` to create a nested chain.
+
+Examples
+========
+
+add_do.js
+---------
+
+This silly example adds values with a chainsaw.
+
+    var Chainsaw = require('chainsaw');
+    
+    function AddDo (sum) {
+        return Chainsaw(function (saw) {
+            this.add = function (n) {
+                sum += n;
+                saw.next();
+            };
+             
+            this.do = function (cb) {
+                saw.nest(cb, sum);
+            };
+        });
+    }
+    
+    AddDo(0)
+        .add(5)
+        .add(10)
+        .do(function (sum) {
+            if (sum > 12) this.add(-10);
+        })
+        .do(function (sum) {
+            console.log('Sum: ' + sum);
+        })
+    ;
+
+Output:
+    Sum: 5
+
+prompt.js
+---------
+
+This example provides a wrapper on top of stdin with the help of
+[node-lazy](https://github.com/pkrumins/node-lazy) for line-processing.
+
+    var Chainsaw = require('chainsaw');
+    var Lazy = require('lazy');
+    
+    module.exports = Prompt;
+    function Prompt (stream) {
+        var waiting = [];
+        var lines = [];
+        var lazy = Lazy(stream).lines.map(String)
+            .forEach(function (line) {
+                if (waiting.length) {
+                    var w = waiting.shift();
+                    w(line);
+                }
+                else lines.push(line);
+            })
+        ;
+        
+        var vars = {};
+        return Chainsaw(function (saw) {
+            this.getline = function (f) {
+                var g = function (line) {
+                    saw.nest(f, line, vars);
+                };
+                
+                if (lines.length) g(lines.shift());
+                else waiting.push(g);
+            };
+            
+            this.do = function (cb) {
+                saw.nest(cb, vars);
+            };
+        });
+    }
+
+And now for the new Prompt() module in action:
+
+    var util = require('util');
+    var stdin = process.openStdin();
+     
+    Prompt(stdin)
+        .do(function () {
+            util.print('x = ');
+        })
+        .getline(function (line, vars) {
+            vars.x = parseInt(line, 10);
+        })
+        .do(function () {
+            util.print('y = ');
+        })
+        .getline(function (line, vars) {
+            vars.y = parseInt(line, 10);
+        })
+        .do(function (vars) {
+            if (vars.x + vars.y < 10) {
+                util.print('z = ');
+                this.getline(function (line) {
+                    vars.z = parseInt(line, 10);
+                })
+            }
+            else {
+                vars.z = 0;
+            }
+        })
+        .do(function (vars) {
+            console.log('x + y + z = ' + (vars.x + vars.y + vars.z));
+            process.exit();
+        })
+    ;
+
+Installation
+============
+
+With [npm](http://github.com/isaacs/npm), just do:
+    npm install chainsaw
+
+or clone this project on github:
+
+    git clone http://github.com/substack/node-chainsaw.git
+
+To run the tests with [expresso](http://github.com/visionmedia/expresso),
+just do:
+
+    expresso
+
diff --git a/debian/tests/node_modules/chainsaw/examples/add_do.js b/debian/tests/node_modules/chainsaw/examples/add_do.js
new file mode 100644
index 0000000..378705d
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/examples/add_do.js
@@ -0,0 +1,25 @@
+var Chainsaw = require('chainsaw');
+
+function AddDo (sum) {
+    return Chainsaw(function (saw) {
+        this.add = function (n) {
+            sum += n;
+            saw.next();
+        };
+        
+        this.do = function (cb) {
+            saw.nest(cb, sum);
+        };
+    });
+}
+
+AddDo(0)
+    .add(5)
+    .add(10)
+    .do(function (sum) {
+        if (sum > 12) this.add(-10);
+    })
+    .do(function (sum) {
+        console.log('Sum: ' + sum);
+    })
+;
diff --git a/debian/tests/node_modules/chainsaw/examples/prompt.js b/debian/tests/node_modules/chainsaw/examples/prompt.js
new file mode 100644
index 0000000..0a06d71
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/examples/prompt.js
@@ -0,0 +1,67 @@
+var Chainsaw = require('chainsaw');
+var Lazy = require('lazy');
+
+module.exports = Prompt;
+function Prompt (stream) {
+    var waiting = [];
+    var lines = [];
+    var lazy = Lazy(stream).lines.map(String)
+        .forEach(function (line) {
+            if (waiting.length) {
+                var w = waiting.shift();
+                w(line);
+            }
+            else lines.push(line);
+        })
+    ;
+    
+    var vars = {};
+    return Chainsaw(function (saw) {
+        this.getline = function (f) {
+            var g = function (line) {
+                saw.nest(f, line, vars);
+            };
+            
+            if (lines.length) g(lines.shift());
+            else waiting.push(g);
+        };
+        
+        this.do = function (cb) {
+            saw.nest(cb, vars);
+        };
+    });
+}
+
+var util = require('util');
+if (__filename === process.argv[1]) {
+    var stdin = process.openStdin();
+    Prompt(stdin)
+        .do(function () {
+            util.print('x = ');
+        })
+        .getline(function (line, vars) {
+            vars.x = parseInt(line, 10);
+        })
+        .do(function () {
+            util.print('y = ');
+        })
+        .getline(function (line, vars) {
+            vars.y = parseInt(line, 10);
+        })
+        .do(function (vars) {
+            if (vars.x + vars.y < 10) {
+                util.print('z = ');
+                this.getline(function (line) {
+                    vars.z = parseInt(line, 10);
+                })
+            }
+            else {
+                vars.z = 0;
+            }
+        })
+        .do(function (vars) {
+            console.log('x + y + z = ' + (vars.x + vars.y + vars.z));
+            process.exit();
+        })
+    ;
+}
diff --git a/debian/tests/node_modules/chainsaw/index.js b/debian/tests/node_modules/chainsaw/index.js
new file mode 100755
index 0000000..597cc48
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/index.js
@@ -0,0 +1,108 @@
+var Traverse = require('traverse');
+var EventEmitter = require('events').EventEmitter;
+
+module.exports = Chainsaw;
+function Chainsaw (builder) {
+    var saw = Chainsaw.saw(builder, {});
+    var r = builder.call(saw.handlers, saw);
+    if (r !== undefined) saw.handlers = r;
+    return saw.chain();
+};
+
+Chainsaw.saw = function (builder, handlers) {
+    var saw = new EventEmitter;
+    saw.handlers = handlers;
+    saw.actions = [];
+    saw.step = 0;
+    
+    saw.chain = function () {
+        var ch = Traverse(saw.handlers).map(function (node) {
+            if (this.isRoot) return node;
+            var ps = this.path;
+            
+            if (typeof node === 'function') {
+                this.update(function () {
+                    saw.actions.push({
+                        path : ps,
+                        args : [].slice.call(arguments)
+                    });
+                    return ch;
+                });
+            }
+        });
+        
+        process.nextTick(function () {
+            saw.emit('begin');
+            saw.next();
+        });
+        
+        return ch;
+    };
+    
+    saw.next = function () {
+        var action = saw.actions[saw.step];
+        saw.step ++;
+        
+        if (!action) {
+            saw.emit('end');
+        }
+        else if (!action.trap) {
+            var node = saw.handlers;
+            action.path.forEach(function (key) { node = node[key] });
+            node.apply(saw.handlers, action.args);
+        }
+    };
+    
+    saw.nest = function (cb) {
+        var args = [].slice.call(arguments, 1);
+        var autonext = true;
+        
+        if (typeof cb === 'boolean') {
+            var autonext = cb;
+            cb = args.shift();
+        }
+        
+        var s = Chainsaw.saw(builder, {});
+        var r = builder.call(s.handlers, s);
+        
+        if (r !== undefined) s.handlers = r;
+        cb.apply(s.chain(), args);
+        if (autonext !== false) s.on('end', saw.next);
+    };
+    
+    saw.trap = function (name, cb) {
+        var ps = Array.isArray(name) ? name : [name];
+        saw.actions.push({
+            path : ps,
+            step : saw.step,
+            cb : cb,
+            trap : true
+        });
+    };
+    
+    saw.down = function (name) {
+        var ps = (Array.isArray(name) ? name : [name]).join('/');
+        var i = saw.actions.slice(saw.step).map(function (x) {
+            if (x.trap && x.step <= saw.step) return false;
+            return x.path.join('/') == ps;
+        }).indexOf(true);
+        
+        if (i >= 0) saw.step += i;
+        else saw.step = saw.actions.length;
+        
+        var act = saw.actions[saw.step - 1];
+        if (act && act.trap) {
+            // It's a trap!
+            saw.step = act.step;
+            act.cb();
+        }
+        else saw.next();
+    };
+    
+    saw.jump = function (step) {
+        saw.step = step;
+        saw.next();
+    };
+    
+    return saw;
+}; 
diff --git a/debian/tests/node_modules/chainsaw/package.json b/debian/tests/node_modules/chainsaw/package.json
new file mode 100644
index 0000000..66b1b08
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/package.json
@@ -0,0 +1,61 @@
+{
+  "_from": "chainsaw@>=0.0.7 <0.1",
+  "_id": "chainsaw@0.0.9",
+  "_inBundle": false,
+  "_integrity": "sha1-EaBRAtHEx4W20EFdM21aOhYSkT4=",
+  "_location": "/chainsaw",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "chainsaw@>=0.0.7 <0.1",
+    "name": "chainsaw",
+    "escapedName": "chainsaw",
+    "rawSpec": ">=0.0.7 <0.1",
+    "saveSpec": null,
+    "fetchSpec": ">=0.0.7 <0.1"
+  },
+  "_requiredBy": [
+    "/seq"
+  ],
+  "_resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.0.9.tgz";,
+  "_shasum": "11a05102d1c4c785b6d0415d336d5a3a1612913e",
+  "_spec": "chainsaw@>=0.0.7 <0.1",
+  "_where": "/home/xavier/dev/debian/packages/node-formidable/node_modules/seq",
+  "author": {
+    "name": "James Halliday",
+    "email": "mail@substack.net",
+    "url": "http://substack.net";
+  },
+  "bugs": {
+    "url": "https://github.com/substack/node-chainsaw/issues";
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "traverse": ">=0.3.0 <0.4"
+  },
+  "deprecated": false,
+  "description": "Build chainable fluent interfaces the easy way... with a freakin' chainsaw!",
+  "engine": {
+    "node": ">=0.4.0"
+  },
+  "engines": {
+    "node": "*"
+  },
+  "homepage": "https://github.com/substack/node-chainsaw#readme";,
+  "keywords": [
+    "chain",
+    "fluent",
+    "interface",
+    "monad",
+    "monadic"
+  ],
+  "license": "MIT/X11",
+  "main": "./index.js",
+  "name": "chainsaw",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/substack/node-chainsaw.git"
+  },
+  "version": "0.0.9"
+}
diff --git a/debian/tests/node_modules/findit/README.markdown b/debian/tests/node_modules/findit/README.markdown
new file mode 100644
index 0000000..d622819
--- /dev/null
+++ b/debian/tests/node_modules/findit/README.markdown
@@ -0,0 +1,101 @@
+findit
+======
+
+Recursively walk directory trees. Think `/usr/bin/find`.
+
+example time!
+=============
+
+callback style
+--------------
+
+````javascript
+require('findit').find(__dirname, function (file) {
+    console.log(file);
+})
+````
+
+emitter style
+-------------
+
+````javascript
+var finder = require('findit').find(__dirname);
+
+finder.on('directory', function (dir, stat) {
+    console.log(dir + '/');
+});
+
+finder.on('file', function (file, stat) {
+    console.log(file);
+});
+
+finder.on('link', function (link, stat) {
+    console.log(link);
+});
+````
+
+synchronous
+-----------
+
+````javascript
+var files = require('findit').sync(__dirname);
+    console.dir(files);
+````
+
+methods
+=======
+
+find(basedir, options, cb)
+-----------------
+
+Do an asynchronous recursive walk starting at `basedir`.
+
+Optionally supply an options object. Setting the property 'follow_symlinks'
+will follow symlinks.
+
+Optionally supply a callback that will get the same arguments as the path event
+documented below in "events".
+
+If `basedir` is actually a non-directory regular file, findit emits a single
+"file" event for it then emits "end".
+
+Findit uses `fs.lstat()` so symlinks are not traversed automatically. To have it
+follow symlinks, supply the options argument with 'follow_symlinks' set to true.
+Findit won't traverse an inode that it has seen before so directories can have
+symlink cycles and findit won't blow up.
+
+Returns an EventEmitter. See "events".
+
+sync(basedir, options, cb)
+-----------------
+
+Return an array of files and directories from a synchronous recursive walk
+starting at `basedir`.
+
+Optionally supply an options object. Setting the property 'follow_symlinks'
+will follow symlinks.
+
+An optional callback `cb` will get called with `cb(file, stat)` if specified.
+
+events
+======
+
+file: [ file, stat ]
+--------------------
+
+Emitted for just files which are not directories.
+
+directory : [ directory, stat ]
+-------------------------------
+
+Emitted for directories.
+
+path : [ file, stat ]
+---------------------
+
+Emitted for both files and directories.
+
+end
+---
+
+Emitted when the recursive walk is done.
diff --git a/debian/tests/node_modules/findit/examples/callback.js b/debian/tests/node_modules/findit/examples/callback.js
new file mode 100644
index 0000000..829630e
--- /dev/null
+++ b/debian/tests/node_modules/findit/examples/callback.js
@@ -0,0 +1,3 @@
+require('findit').find(__dirname, function (file) {
+    console.log(file);
+})
diff --git a/debian/tests/node_modules/findit/examples/emitter.js b/debian/tests/node_modules/findit/examples/emitter.js
new file mode 100644
index 0000000..f97adf3
--- /dev/null
+++ b/debian/tests/node_modules/findit/examples/emitter.js
@@ -0,0 +1,9 @@
+var finder = require('findit').find(__dirname);
+
+finder.on('directory', function (dir) {
+    console.log(dir + '/');
+});
+
+finder.on('file', function (file) {
+    console.log(file);
+});
diff --git a/debian/tests/node_modules/findit/examples/sync.js b/debian/tests/node_modules/findit/examples/sync.js
new file mode 100644
index 0000000..b09e0b2
--- /dev/null
+++ b/debian/tests/node_modules/findit/examples/sync.js
@@ -0,0 +1,2 @@
+var files = require('findit').findSync(__dirname);
+console.dir(files);
diff --git a/debian/tests/node_modules/findit/index.js b/debian/tests/node_modules/findit/index.js
new file mode 100644
index 0000000..c1d9eb9
--- /dev/null
+++ b/debian/tests/node_modules/findit/index.js
@@ -0,0 +1,142 @@
+var fs = require('fs');
+var path = require('path');
+var EventEmitter = require('events').EventEmitter;
+var Seq = require('seq');
+
+function createInodeChecker() {
+    var inodes = {};
+    return function inodeSeen(inode) {
+        if (inodes[inode]) {
+            return true;
+        } else {
+            inodes[inode] = true;
+            return false;
+        }
+    }
+}
+
+exports = module.exports = find;
+exports.find = find;
+function find (base, options, cb) {
+    cb = arguments[arguments.length - 1];
+    if (typeof(cb) !== 'function') {
+        cb = undefined;
+    }
+    var em = new EventEmitter;
+    var inodeSeen = createInodeChecker();
+    
+    function finder (dir, f) {
+        Seq()
+            .seq(fs.readdir, dir, Seq)
+            .flatten()
+            .seqEach(function (file) {
+                var p = dir + '/' + file;
+                fs.lstat(p, this.into(p));
+            })
+            .seq(function () {
+                this(null, Object.keys(this.vars));
+            })
+            .flatten()
+            .seqEach(function (file) {
+                var stat = this.vars[file];
+                if (cb) cb(file, stat);
+                
+                if (inodeSeen(stat.ino)) {
+                    // already seen this inode, probably a recursive symlink
+                    this(null);
+                }
+                else {
+                    em.emit('path', file, stat);
+                    
+                    if (stat.isSymbolicLink()) {
+                        em.emit('link', file, stat);
+                        if (options && options.follow_symlinks) {
+                          path.exists(file, function(exists) {
+                            if (exists) {
+                              fs.readlink(file, function(err, resolvedPath) {
+                                if (err) {
+                                  em.emit('error', err);
+                                } else {
+                                  finder(path.resolve(path.dir(file), resolvedPath));
+                                }
+                              });
+                            }
+                          });
+                        } else {
+                          this(null);
+                        }
+                    }
+                    else if (stat.isDirectory()) {
+                        em.emit('directory', file, stat);
+                        finder(file, this);
+                    }
+                    else {
+                        em.emit('file', file, stat);
+                        this(null);
+                    }
+                }
+            })
+            .seq(f.bind({}, null))
+            .catch(em.emit.bind(em, 'error'))
+        ;
+    }
+    
+    fs.lstat(base, function (err, s) {
+        if (err) {
+            em.emit('error', err);
+        }
+        if (s.isDirectory()) {
+            finder(base, em.emit.bind(em, 'end'));
+        }
+        else if (s.isSymbolicLink()) {
+            if (cb) cb(base, s);
+            em.emit('link', base, s);
+            em.emit('end');
+        }
+        else {
+            if (cb) cb(base, s);
+            em.emit('file', base, s);
+            em.emit('end');
+        }
+    });
+    
+    return em;
+};
+
+exports.findSync = function findSync(dir, options, callback) {
+    cb = arguments[arguments.length - 1];
+    if (typeof(cb) !== 'function') {
+        cb = undefined;
+    }
+    var inodeSeen = createInodeChecker();
+    var files = [];
+    var fileQueue = [];
+    var processFile = function processFile(file) {
+        var stat = fs.lstatSync(file);
+        if (inodeSeen(stat.ino)) {
+            return;
+        }
+        files.push(file);
+        cb && cb(file, stat)
+        if (stat.isDirectory()) {
+            fs.readdirSync(file).forEach(function(f) { fileQueue.push(path.join(file, f)); });
+        } else if (stat.isSymbolicLink()) {
+            if (options && options.follow_symlinks && path.existsSync(file)) {
+                fileQueue.push(fs.realpathSync(file));
+            }
+        }
+    };
+    /* we don't include the starting directory unless it is a file */
+    var stat = fs.lstatSync(dir);
+    if (stat.isDirectory()) {
+        fs.readdirSync(dir).forEach(function(f) { fileQueue.push(path.join(dir, f)); });
+    } else {
+        fileQueue.push(dir);
+    }
+    while (fileQueue.length > 0) {
+        processFile(fileQueue.shift());
+    }
+    return files;
+};
+
+exports.find.sync = exports.findSync;
diff --git a/debian/tests/node_modules/findit/package.json b/debian/tests/node_modules/findit/package.json
new file mode 100644
index 0000000..0b4cac9
--- /dev/null
+++ b/debian/tests/node_modules/findit/package.json
@@ -0,0 +1,68 @@
+{
+  "_from": "findit@^0.1.2",
+  "_id": "findit@0.1.2",
+  "_inBundle": false,
+  "_integrity": "sha1-rH/mAM1qMqNWcoNrdM9vHd4uEfg=",
+  "_location": "/findit",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "findit@^0.1.2",
+    "name": "findit",
+    "escapedName": "findit",
+    "rawSpec": "^0.1.2",
+    "saveSpec": null,
+    "fetchSpec": "^0.1.2"
+  },
+  "_requiredBy": [
+    "#DEV:/"
+  ],
+  "_resolved": "https://registry.npmjs.org/findit/-/findit-0.1.2.tgz";,
+  "_shasum": "ac7fe600cd6a32a35672836b74cf6f1dde2e11f8",
+  "_spec": "findit@^0.1.2",
+  "_where": "/home/xavier/dev/debian/packages/node-formidable",
+  "author": {
+    "name": "James Halliday",
+    "email": "mail@substack.net",
+    "url": "http://substack.net";
+  },
+  "bugs": {
+    "url": "https://github.com/substack/node-findit/issues";
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "seq": ">=0.1.7"
+  },
+  "deprecated": false,
+  "description": "Walk a directory tree.",
+  "devDependencies": {
+    "expresso": "0.7.x",
+    "hashish": ">=0.0.2 <0.1"
+  },
+  "engine": [
+    "node >=0.2.0"
+  ],
+  "engines": {
+    "node": "*"
+  },
+  "homepage": "https://github.com/substack/node-findit#readme";,
+  "keywords": [
+    "find",
+    "walk",
+    "directory",
+    "recursive",
+    "tree"
+  ],
+  "license": "MIT/X11",
+  "main": "./index.js",
+  "name": "findit",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/substack/node-findit.git"
+  },
+  "scripts": {
+    "test": "expresso"
+  },
+  "version": "0.1.2"
+}
diff --git a/debian/tests/node_modules/gently/Makefile b/debian/tests/node_modules/gently/Makefile
new file mode 100644
index 0000000..01f7140
--- /dev/null
+++ b/debian/tests/node_modules/gently/Makefile
@@ -0,0 +1,4 @@
+test:
+	@find test/simple/test-*.js | xargs -n 1 -t node
+
+.PHONY: test
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/Readme.md b/debian/tests/node_modules/gently/Readme.md
new file mode 100644
index 0000000..f8f0c66
--- /dev/null
+++ b/debian/tests/node_modules/gently/Readme.md
@@ -0,0 +1,167 @@
+# Gently
+
+## Purpose
+
+A node.js module that helps with stubbing and behavior verification. It allows you to test the most remote and nested corners of your code while keeping being fully unobtrusive.
+
+## Features
+
+* Overwrite and stub individual object functions
+* Verify that all expected calls have been made in the expected order
+* Restore stubbed functions to their original behavior
+* Detect object / class names from obj.constructor.name and obj.toString()
+* Hijack any required module function or class constructor
+
+## Installation
+
+Via [npm](http://github.com/isaacs/npm):
+
+    npm install gently@latest
+
+## Example
+
+Make sure your dog is working properly:
+
+    function Dog() {}
+
+    Dog.prototype.seeCat = function() {
+      this.bark('whuf, whuf');
+      this.run();
+    }
+
+    Dog.prototype.bark = function(bark) {
+      require('sys').puts(bark);
+    }
+
+    var gently = new (require('gently'))
+      , assert = require('assert')
+      , dog = new Dog();
+
+    gently.expect(dog, 'bark', function(bark) {
+      assert.equal(bark, 'whuf, whuf');
+    });
+    gently.expect(dog, 'run');
+
+    dog.seeCat();
+
+You can also easily test event emitters with this, for example a simple sequence of 2 events emitted by `fs.WriteStream`:
+
+    var gently = new (require('gently'))
+      , stream = new (require('fs').WriteStream)('my_file.txt');
+
+    gently.expect(stream, 'emit', function(event) {
+      assert.equal(event, 'open');
+    });
+
+    gently.expect(stream, 'emit', function(event) {
+      assert.equal(event, 'drain');
+    });
+
+For a full read world example, check out this test case: [test-incoming-form.js](http://github.com/felixge/node-formidable/blob/master/test/simple/test-incoming-form.js) (in [node-formdiable](http://github.com/felixge/node-formidable)).
+
+## API
+
+### Gently
+
+#### new Gently()
+
+Creates a new gently instance. It listens to the process `'exit'` event to make sure all expectations have been verified.
+
+#### gently.expect(obj, method, [[count], stubFn])
+
+Creates an expectation for an objects method to be called. You can optionally specify the call `count` you are expecting, as well as `stubFn` function that will run instead of the original function.
+
+Returns a reference to the function that is getting overwritten.
+
+#### gently.expect([count], stubFn)
+
+Returns a function that is supposed to be executed `count` times, delegating any calls to the provided `stubFn` function. Naming your stubFn closure will help to properly diagnose errors that are being thrown:
+
+    childProcess.exec('ls', gently.expect(function lsCallback(code) {
+      assert.equal(0, code);
+    }));
+
+#### gently.restore(obj, method)
+
+Restores an object method that has been previously overwritten using `gently.expect()`.
+
+#### gently.hijack(realRequire)
+
+Returns a new require functions that catches a reference to all required modules into `gently.hijacked`.
+
+To use this function, include a line like this in your `'my-module.js'`.
+
+    if (global.GENTLY) require = GENTLY.hijack(require);
+
+    var sys = require('sys');
+    exports.hello = function() {
+      sys.log('world');
+    };
+
+Now you can write a test for the module above:
+
+    var gently = global.GENTLY = new (require('gently'))
+      , myModule = require('./my-module');
+
+    gently.expect(gently.hijacked.sys, 'log', function(str) {
+      assert.equal(str, 'world');
+    });
+
+    myModule.hello();
+
+#### gently.stub(location, [exportsName])
+
+Returns a stub class that will be used instead of the real class from the module at `location` with the given `exportsName`.
+
+This allows to test an OOP version of the previous example, where `'my-module.js'`.
+
+    if (global.GENTLY) require = GENTLY.hijack(require);
+
+    var World = require('./world');
+
+    exports.hello = function() {
+      var world = new World();
+      world.hello();
+    }
+
+And `world.js` looks like this:
+
+    var sys = require('sys');
+
+    function World() {
+
+    }
+    module.exports = World;
+
+    World.prototype.hello = function() {
+      sys.log('world');
+    };
+
+Testing `'my-module.js'` can now easily be accomplished:
+
+    var gently = global.GENTLY = new (require('gently'))
+      , WorldStub = gently.stub('./world')
+      , myModule = require('./my-module')
+      , WORLD;
+
+    gently.expect(WorldStub, 'new', function() {
+      WORLD = this;
+    });
+
+    gently.expect(WORLD, 'hello');
+
+    myModule.hello();
+
+#### gently.hijacked
+
+An object that holds the references to all hijacked modules.
+
+#### gently.verify([msg])
+
+Verifies that all expectations of this gently instance have been satisfied. If not called manually, this method is called when the process `'exit'` event is fired.
+
+If `msg` is given, it will appear in any error that might be thrown.
+
+## License
+
+Gently is licensed under the MIT license.
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/example/dog.js b/debian/tests/node_modules/gently/example/dog.js
new file mode 100644
index 0000000..022fae0
--- /dev/null
+++ b/debian/tests/node_modules/gently/example/dog.js
@@ -0,0 +1,22 @@
+require('../test/common');
+function Dog() {}
+
+Dog.prototype.seeCat = function() {
+  this.bark('whuf, whuf');
+  this.run();
+}
+
+Dog.prototype.bark = function(bark) {
+  require('sys').puts(bark);
+}
+
+var gently = new (require('gently'))
+  , assert = require('assert')
+  , dog = new Dog();
+
+gently.expect(dog, 'bark', function(bark) {
+  assert.equal(bark, 'whuf, whuf');
+});
+gently.expect(dog, 'run');
+
+dog.seeCat();
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/example/event_emitter.js b/debian/tests/node_modules/gently/example/event_emitter.js
new file mode 100644
index 0000000..7def134
--- /dev/null
+++ b/debian/tests/node_modules/gently/example/event_emitter.js
@@ -0,0 +1,11 @@
+require('../test/common');
+var gently = new (require('gently'))
+  , stream = new (require('fs').WriteStream)('my_file.txt');
+
+gently.expect(stream, 'emit', function(event) {
+  assert.equal(event, 'open');
+});
+
+gently.expect(stream, 'emit', function(event) {
+  assert.equal(event, 'drain');
+});
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/index.js b/debian/tests/node_modules/gently/index.js
new file mode 100644
index 0000000..69122bd
--- /dev/null
+++ b/debian/tests/node_modules/gently/index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/gently');
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/lib/gently/.gently.js.swp b/debian/tests/node_modules/gently/lib/gently/.gently.js.swp
new file mode 100644
index 0000000..f2ce523
Binary files /dev/null and b/debian/tests/node_modules/gently/lib/gently/.gently.js.swp differ
diff --git a/debian/tests/node_modules/gently/lib/gently/gently.js b/debian/tests/node_modules/gently/lib/gently/gently.js
new file mode 100644
index 0000000..7ff7e51
--- /dev/null
+++ b/debian/tests/node_modules/gently/lib/gently/gently.js
@@ -0,0 +1,151 @@
+var path = require('path');
+
+function Gently() {
+  this.expectations = [];
+  this.hijacked = {};
+
+  var self = this;
+  process.addListener('exit', function() {
+    self.verify('process exit');
+  });
+};
+module.exports = Gently;
+
+Gently.prototype.stub = function(location, exportsName) {
+  function Stub() {
+    Stub['new'].apply(this, arguments);
+  };
+
+  Stub['new'] = function () {};
+
+  var stubName = 'require('+JSON.stringify(location)+')';
+  if (exportsName) {
+    stubName += '.'+exportsName;
+  }
+
+  Stub.prototype.toString = Stub.toString = function() {
+    return stubName;
+  };
+
+  var exports = this.hijacked[location] || {};
+  if (exportsName) {
+    exports[exportsName] = Stub;
+  } else {
+    exports = Stub;
+  }
+
+  this.hijacked[location] = exports;
+  return Stub;
+};
+
+Gently.prototype.hijack = function(realRequire) {
+  var self = this;
+  return function(location) {
+    return self.hijacked[location] = (self.hijacked[location])
+      ? self.hijacked[location]
+      : realRequire(location);
+  };
+};
+
+Gently.prototype.expect = function(obj, method, count, stubFn) {
+  if (typeof obj != 'function' && typeof obj != 'object') {
+    throw new Error
+      ( 'Bad 1st argument for gently.expect(), '
+      + 'object or function expected, got: '+(typeof obj)
+      );
+  } else if (typeof obj == 'function' && (typeof method != 'string')) {
+    // expect(stubFn) interface
+    stubFn = obj;
+    obj = null;
+    method = null;
+    count = 1;
+  } else if (typeof method == 'function') {
+    // expect(count, stubFn) interface
+    count = obj;
+    stubFn = method;
+    obj = null;
+    method = null;
+  } else if (typeof count == 'function') {
+    // expect(obj, method, stubFn) interface
+    stubFn = count;
+    count = 1;
+  } else if (count === undefined) {
+    // expect(obj, method) interface
+    count = 1;
+  }
+
+  var name = this._name(obj, method, stubFn);
+  while (count-- > 0) {
+    this.expectations.push({obj: obj, method: method, stubFn: stubFn, name: name});
+  }
+
+  var self = this;
+  function delegate() {
+    return self._stubFn(this, obj, method, name, Array.prototype.slice.call(arguments));
+  }
+
+  if (!obj) {
+    return delegate;
+  }
+
+  var original = (obj[method])
+    ? obj[method]._original || obj[method]
+    : undefined;
+
+  obj[method] = delegate;
+  return obj[method]._original = original;
+};
+
+Gently.prototype.restore = function(obj, method) {
+  if (!obj[method] || !obj[method]._original) {
+    throw new Error(this._name(obj, method)+' is not gently stubbed');
+  }
+  obj[method] = obj[method]._original;
+};
+
+Gently.prototype.verify = function(msg) {
+  if (!this.expectations.length) {
+    return;
+  }
+
+  var expectation = this.expectations[0];
+  throw new Error
+    ( 'Expected call to '+expectation.name+' did not happen'
+    + ( (msg)
+        ? ' ('+msg+')'
+        : ''
+      )
+    );
+};
+
+Gently.prototype._stubFn = function(self, obj, method, name, args) {
+  var expectation = this.expectations.shift();
+  if (!expectation) {
+    throw new Error('Unexpected call to '+name+', no call was expected');
+  }
+
+  if (expectation.obj !== obj || expectation.method !== method) {
+    this.expectations.unshift(expectation);
+    throw new Error('Unexpected call to '+name+', expected call to '+ expectation.name);
+  }
+
+  if (expectation.stubFn) {
+    return expectation.stubFn.apply(self, args);
+  }
+};
+
+Gently.prototype._name = function(obj, method, stubFn) {
+  if (obj) {
+    var objectName = obj.toString();
+    if (objectName == '[object Object]' && obj.constructor.name) {
+      objectName = '['+obj.constructor.name+']';
+    }
+    return (objectName)+'.'+method+'()';
+  }
+
+  if (stubFn.name) {
+    return stubFn.name+'()';
+  }
+
+  return '>> '+stubFn.toString()+' <<';
+};
diff --git a/debian/tests/node_modules/gently/lib/gently/index.js b/debian/tests/node_modules/gently/lib/gently/index.js
new file mode 100644
index 0000000..64c1977
--- /dev/null
+++ b/debian/tests/node_modules/gently/lib/gently/index.js
@@ -0,0 +1 @@
+module.exports = require('./gently');
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/package.json b/debian/tests/node_modules/gently/package.json
new file mode 100644
index 0000000..22feffe
--- /dev/null
+++ b/debian/tests/node_modules/gently/package.json
@@ -0,0 +1,37 @@
+{
+  "_from": "gently@^0.8.0",
+  "_id": "gently@0.8.0",
+  "_inBundle": false,
+  "_integrity": "sha1-vDhduZ7BmU3WpENo4KvrSCsZKyw=",
+  "_location": "/gently",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "gently@^0.8.0",
+    "name": "gently",
+    "escapedName": "gently",
+    "rawSpec": "^0.8.0",
+    "saveSpec": null,
+    "fetchSpec": "^0.8.0"
+  },
+  "_requiredBy": [
+    "#DEV:/"
+  ],
+  "_resolved": "https://registry.npmjs.org/gently/-/gently-0.8.0.tgz";,
+  "_shasum": "bc385db99ec1994dd6a44368e0abeb482b192b2c",
+  "_spec": "gently@^0.8.0",
+  "_where": "/home/xavier/dev/debian/packages/node-formidable",
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "## Purpose",
+  "directories": {
+    "lib": "./lib/gently"
+  },
+  "engines": {
+    "node": "*"
+  },
+  "main": "./lib/gently/index",
+  "name": "gently",
+  "version": "0.8.0"
+}
diff --git a/debian/tests/node_modules/seq/README.markdown b/debian/tests/node_modules/seq/README.markdown
new file mode 100644
index 0000000..3689261
--- /dev/null
+++ b/debian/tests/node_modules/seq/README.markdown
@@ -0,0 +1,442 @@
+Seq
+===
+
+Seq is an asynchronous flow control library with a chainable interface for
+sequential and parallel actions. Even the error handling is chainable.
+
+Each action in the chain operates on a stack of values.
+There is also a variables hash for storing values by name.
+
+[TOC]
+
+
+
+Examples
+========
+
+stat_all.js
+-----------
+
+````javascript
+var fs = require('fs');
+var Hash = require('hashish');
+var Seq = require('seq');
+
+Seq()
+    .seq(function () {
+        fs.readdir(__dirname, this);
+    })
+    .flatten()
+    .parEach(function (file) {
+        fs.stat(__dirname + '/' + file, this.into(file));
+    })
+    .seq(function () {
+        var sizes = Hash.map(this.vars, function (s) { return s.size })
+        console.dir(sizes);
+    })
+;
+````
+
+Output:
+
+    { 'stat_all.js': 404, 'parseq.js': 464 }
+
+parseq.js
+---------
+
+````javascript
+var fs = require('fs');
+var exec = require('child_process').exec;
+
+var Seq = require('seq');
+Seq()
+    .seq(function () {
+        exec('whoami', this)
+    })
+    .par(function (who) {
+        exec('groups ' + who, this);
+    })
+    .par(function (who) {
+        fs.readFile(__filename, 'ascii', this);
+    })
+    .seq(function (groups, src) {
+        console.log('Groups: ' + groups.trim());
+        console.log('This file has ' + src.length + ' bytes');
+    })
+;
+````
+
+Output:
+
+    Groups: substack : substack dialout cdrom floppy audio src video plugdev games netdev fuse www
+    This file has 464 bytes
+
+
+
+
+API
+===
+
+Each method executes callbacks with a context (its `this`) described in the next
+section. Every method returns `this`.
+
+Whenever `this()` is called with a non-falsy first argument, the error value
+propagates down to the first `catch` it sees, skipping over all actions in
+between. There is an implicit `catch` at the end of all chains that prints the
+error stack if available and otherwise just prints the error.
+
+
+
+Seq(xs=[])
+----------
+
+The constructor function creates a new `Seq` chain with the methods described
+below. The optional array argument becomes the new context stack.
+
+Array argument is new in 0.3. `Seq()` now behaves like `Seq.ap()`.
+
+
+.seq(cb)
+--------
+.seq(key, cb, *args)
+--------------------
+
+This eponymous function executes actions sequentially.
+Once all running parallel actions are finished executing,
+the supplied callback is `apply()`'d with the context stack.
+
+To execute the next action in the chain, call `this()`. The first
+argument must be the error value. The rest of the values will become the stack
+for the next action in the chain and are also available at `this.args`.
+
+If `key` is specified, the second argument sent to `this` goes to
+`this.vars[key]` in addition to the stack and `this.args`.
+`this.vars` persists across all requests unless it is overwritten.
+
+All arguments after `cb` will be bound to `cb`, which is useful because
+`.bind()` makes you set `this`. If you pass in `Seq` in the arguments list,
+it'll get transformed into `this` so that you can do:
+
+````javascript
+Seq()
+    .seq(fs.readdir, __dirname, Seq)
+    .seq(function (files) { console.dir(files) })
+;
+````
+
+which prints an array of files in `__dirname`.
+
+
+.par(cb)
+--------
+.par(key, cb, *args)
+--------------------
+
+Use `par` to execute actions in parallel.
+Chain multiple parallel actions together and collect all the responses on the
+stack with a sequential operation like `seq`.
+
+Each `par` sets one element in the stack with the second argument to `this()` in
+the order in which it appears, so multiple `par`s can be chained together.
+
+Like with `seq`, the first argument to `this()` should be the error value and
+the second will get pushed to the stack. Further arguments are available in
+`this.args`.
+
+If `key` is specified, the result from the second argument send to `this()` goes
+to `this.vars[key]`.
+`this.vars` persists across all requests unless it is overwritten.
+
+All arguments after `cb` will be bound to `cb`, which is useful because
+`.bind()` makes you set `this`. Like `.seq()`, you can pass along `Seq` in these
+bound arguments and it will get tranformed into `this`.
+
+
+.catch(cb)
+----------
+
+Catch errors. Whenever a function calls `this` with a non-falsy first argument,
+the message propagates down the chain to the first `catch` it sees.
+The callback `cb` fires with the error object as its first argument and the key
+that the action that caused the error was populating, which may be undefined.
+
+`catch` is a sequential action and further actions may appear after a `catch` in
+a chain. If the execution reaches a `catch` in a chain and no error has occured,
+the `catch` is skipped over.
+
+For convenience, there is a default error handler at the end of all chains.
+This default error handler looks like this:
+
+````javascript
+.catch(function (err) {
+    console.error(err.stack ? err.stack : err)
+})
+````
+
+
+.forEach(cb)
+------------
+
+Execute each action in the stack under the context of the chain object.
+`forEach` does not wait for any of the actions to finish and does not itself
+alter the stack, but the callback may alter the stack itself by modifying
+`this.stack`.
+
+The callback is executed `cb(x,i)` where `x` is the element and `i` is the
+index. 
+
+`forEach` is a sequential operation like `seq` and won't run until all pending
+parallel requests yield results.
+
+
+.seqEach(cb)
+------------
+
+Like `forEach`, call `cb` for each element on the stack, but unlike `forEach`,
+`seqEach` waits for the callback to yield with `this` before moving on to the
+next element in the stack.
+
+The callback is executed `cb(x,i)` where `x` is the element and `i` is the
+index. 
+
+If `this()` is supplied non-falsy error, the error propagates downward but any
+other arguments are ignored. `seqEach` does not modify the stack itself.
+
+
+.parEach(cb)
+------------
+.parEach(limit, cb)
+-------------------
+
+Like `forEach`, calls cb for each element in the stack and doesn't wait for the
+callback to yield a result with `this()` before moving on to the next iteration.
+Unlike `forEach`, `parEach` waits for all actions to call `this()` before moving
+along to the next action in the chain.
+
+The callback is executed `cb(x,i)` where `x` is the element and `i` is the
+index. 
+
+`parEach` does not modify the stack itself and errors supplied to `this()`
+propagate.
+
+Optionally, if limit is supplied to `parEach`, at most `limit` callbacks will be
+active at a time.
+
+
+.seqMap(cb)
+-----------
+
+Like `seqEach`, but collect the values supplied to `this` and set the stack to
+these values.
+
+
+.parMap(cb)
+-----------
+.parMap(limit, cb)
+------------------
+
+Like `parEach`, but collect the values supplied to `this` and set the stack to
+these values.
+
+
+.seqFilter(cb)
+-----------
+
+Executes the callback `cb(x, idx)` against each element on the stack, waiting for the
+callback to yield with `this` before moving on to the next element. If the callback 
+returns an error or a falsey value, the element will not be included in the resulting
+stack.
+
+Any errors from the callback are consumed and **do not** propagate.
+
+Calls to `this.into(i)` will place the value, if accepted by the callback, at the index in
+the results as if it were ordered at i-th index on the stack before filtering (with ties
+broken by the values). This implies `this.into` will never override another stack value
+even if their indices collide. Finally, the value will only actually appear at `i` if the
+callback accepts or moves enough values before `i`.
+
+
+.parFilter(cb)
+-----------
+.parFilter(limit, cb)
+------------------
+
+Executes the callback `cb(x, idx)` against each element on the stack, but **does not**
+wait for it to yield before moving on to the next element. If the callback returns an
+error or a falsey value, the element will not be included in the resulting stack.
+
+Any errors from the callback are consumed and **do not** propagate.
+
+Calls to `this.into(i)` will place the value, if accepted by the callback, at the index in
+the results as if it were ordered at i-th index on the stack before filtering (with ties
+broken by the values). This implies `this.into` will never override another stack value
+even if their indices collide. Finally, the value will only actually appear at `i` if the
+callback accepts or moves enough values before `i`.
+
+Optionally, if limit is supplied to `parEach`, at most `limit` callbacks will be
+active at a time.
+
+
+.do(cb)
+-------
+Create a new nested context. `cb`'s first argument is the previous context, and `this`
+is the nested `Seq` object.
+
+
+.flatten(fully=true)
+--------------------
+
+Recursively flatten all the arrays in the stack. Set `fully=false` to flatten
+only one level.
+
+
+.unflatten()
+------------
+
+Turn the contents of the stack into a single array item. You can think of it
+as the inverse of `flatten(false)`.
+
+
+.extend([x,y...])
+-----------------
+
+Like `push`, but takes an array. This is like python's `[].extend()`.
+
+
+.set(xs)
+--------
+
+Set the stack to a new array. This assigns the reference, it does not copy.
+
+
+.empty()
+--------
+
+Set the stack to [].
+
+
+.push(x,y...), .pop(), .shift(), .unshift(x), .splice(...), reverse()
+---------------------------------------------------------------------
+.map(...), .filter(...), .reduce(...)
+-------------------------------------
+
+Executes an array operation on the stack.
+
+The methods `map`, `filter`, and `reduce` are also proxies to their Array counterparts:
+they have identical signatures to the Array methods, operate synchronously on the context
+stack, and do not pass a Context object (unlike `seqMap` and `parMap`).
+
+The result of the transformation is assigned to the context stack; in the case of `reduce`,
+if you do not return an array, the value will be wrapped in one.
+
+````javascript
+Seq([1, 2, 3])
+    .reduce(function(sum, x){ return sum + x; }, 0)
+    .seq(function(sum){
+        console.log('sum: %s', sum);
+        // sum: 6
+        console.log('stack is Array?', Array.isArray(this.stack));
+        // stack is Array: true
+        console.log('stack:', this.stack);
+        // stack: [6]
+    })
+;
+````
+
+
+
+
+Explicit Parameters
+-------------------
+
+For environments like coffee-script or nested logic where threading `this` is
+bothersome, you can use:
+
+* seq_
+* par_
+* forEach_
+* seqEach_
+* parEach_
+* seqMap_
+* parMap_
+
+which work exactly like their un-underscored counterparts except for the first
+parameter to the supplied callback is set to the context, `this`.
+
+
+
+Context Object
+==============
+
+Each callback gets executed with its `this` set to a function in order to yield
+results, error values, and control. The function also has these useful fields:
+
+this.stack
+----------
+
+The execution stack.
+
+this.stack_
+-----------
+
+The previous stack value, mostly used internally for hackish purposes.
+
+this.vars
+---------
+
+A hash of key/values populated with `par(key, ...)`, `seq(key, ...)` and
+`this.into(key)`.
+
+this.into(key)
+--------------
+
+Instead of sending values to the stack, sets a key and returns `this`.
+Use `this.into(key)` interchangeably with `this` for yielding keyed results.
+`into` overrides the optional key set by `par(key, ...)` and `seq(key, ...)`.
+
+this.ok
+-------
+
+Set the `err` to null. Equivalent to `this.bind(this, null)`.
+
+this.args
+---------
+
+`this.args` is like `this.stack`, but it contains all the arguments to `this()`
+past the error value, not just the first. `this.args` is an array with the same
+indices as `this.stack` but also stores keyed values for the last sequential
+operation. Each element in `this.array` is set to `[].slice.call(arguments, 1)`
+from inside `this()`.
+
+this.error
+----------
+
+This is used for error propagation. You probably shouldn't mess with it.
+
+
+
+Installation
+============
+
+With [npm](http://github.com/isaacs/npm), just do:
+
+    npm install seq
+
+or clone this project on github:
+
+    git clone http://github.com/substack/node-seq.git
+
+To run the tests with [expresso](http://github.com/visionmedia/expresso),
+just do:
+
+    expresso
+
+
+
+Dependencies
+------------
+
+This module uses [chainsaw](http://github.com/substack/node-chainsaw)
+When you `npm install seq` this dependency will automatically be installed.
+
+
diff --git a/debian/tests/node_modules/seq/examples/join.js b/debian/tests/node_modules/seq/examples/join.js
new file mode 100644
index 0000000..cc05c4f
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/join.js
@@ -0,0 +1,18 @@
+var Seq = require('seq');
+Seq()
+    .par(function () {
+        var that = this;
+        setTimeout(function () { that(null, 'a') }, 300);
+    })
+    .par(function () {
+        var that = this;
+        setTimeout(function () { that(null, 'b') }, 200);
+    })
+    .par(function () {
+        var that = this;
+        setTimeout(function () { that(null, 'c') }, 100);
+    })
+    .seq(function (a, b, c) {
+        console.dir([ a, b, c ])
+    })
+;
diff --git a/debian/tests/node_modules/seq/examples/parseq.coffee b/debian/tests/node_modules/seq/examples/parseq.coffee
new file mode 100644
index 0000000..d4ca0ab
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/parseq.coffee
@@ -0,0 +1,12 @@
+fs = require 'fs'
+exec = require('child_process').exec
+Seq = require 'seq'
+
+Seq()
+    .seq_((next) -> exec 'whoami', next)
+    .par_((next, who) -> exec('groups ' + who, next))
+    .par_((next, who) -> fs.readFile(__filename, 'utf8', next))
+    .seq_((next, groups, src) ->
+        console.log('Groups: ' + groups.trim())
+        console.log('This file has ' + src.length + ' bytes')
+    )
diff --git a/debian/tests/node_modules/seq/examples/parseq.js b/debian/tests/node_modules/seq/examples/parseq.js
new file mode 100644
index 0000000..2cdcf21
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/parseq.js
@@ -0,0 +1,19 @@
+var fs = require('fs');
+var exec = require('child_process').exec;
+
+var Seq = require('seq');
+Seq()
+    .seq(function () {
+        exec('whoami', this)
+    })
+    .par(function (who) {
+        exec('groups ' + who, this);
+    })
+    .par(function (who) {
+        fs.readFile(__filename, 'utf8', this);
+    })
+    .seq(function (groups, src) {
+        console.log('Groups: ' + groups.trim());
+        console.log('This file has ' + src.length + ' bytes');
+    })
+;
diff --git a/debian/tests/node_modules/seq/examples/stat_all.coffee b/debian/tests/node_modules/seq/examples/stat_all.coffee
new file mode 100644
index 0000000..83ec0b2
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/stat_all.coffee
@@ -0,0 +1,16 @@
+fs = require 'fs'
+Hash = require 'hashish'
+Seq = require 'seq'
+
+Seq()
+    .seq_((next) ->
+        fs.readdir(__dirname, next)
+    )
+    .flatten()
+    .parEach_((next, file) ->
+        fs.stat(__dirname + '/' + file, next.into(file))
+    )
+    .seq_((next) ->
+        sizes = Hash.map(next.vars, (s) -> s.size)
+        console.dir sizes
+    )
diff --git a/debian/tests/node_modules/seq/examples/stat_all.js b/debian/tests/node_modules/seq/examples/stat_all.js
new file mode 100644
index 0000000..b9962eb
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/stat_all.js
@@ -0,0 +1,17 @@
+var fs = require('fs');
+var Hash = require('hashish');
+var Seq = require('seq');
+
+Seq()
+    .seq(function () {
+        fs.readdir(__dirname, this);
+    })
+    .flatten()
+    .parEach(function (file) {
+        fs.stat(__dirname + '/' + file, this.into(file));
+    })
+    .seq(function () {
+        var sizes = Hash.map(this.vars, function (s) { return s.size })
+        console.dir(sizes);
+    })
+;
diff --git a/debian/tests/node_modules/seq/index.js b/debian/tests/node_modules/seq/index.js
new file mode 100755
index 0000000..4e0888b
--- /dev/null
+++ b/debian/tests/node_modules/seq/index.js
@@ -0,0 +1,520 @@
+var EventEmitter = require('events').EventEmitter;
+var Hash = require('hashish');
+var Chainsaw = require('chainsaw');
+
+module.exports = Seq;
+function Seq (xs) {
+    if (xs && !Array.isArray(xs) || arguments.length > 1) {
+        throw new Error('Optional argument to Seq() is exactly one Array');
+    }
+    
+    var ch = Chainsaw(function (saw) {
+        builder.call(this, saw, xs || []);
+    });
+    
+    process.nextTick(function () {
+        ch['catch'](function (err) {
+            console.error(err.stack ? err.stack : err)
+        });
+    });
+    return ch;
+}
+
+Seq.ap = Seq; // for compatability with versions <0.3
+
+function builder (saw, xs) {
+    var context = {
+        vars : {},
+        args : {},
+        stack : xs,
+        error : null
+    };
+    context.stack_ = context.stack;
+    
+    function action (step, key, f, g) {
+        var cb = function (err) {
+            var args = [].slice.call(arguments, 1);
+            if (err) {
+                context.error = { message : err, key : key };
+                saw.jump(lastPar);
+                saw.down('catch');
+                g();
+            }
+            else {
+                if (typeof key == 'number') {
+                    context.stack_[key] = args[0];
+                    context.args[key] = args;
+                }
+                else {
+                    context.stack_.push.apply(context.stack_, args);
+                    if (key !== undefined) {
+                        context.vars[key] = args[0];
+                        context.args[key] = args;
+                    }
+                }
+                if (g) g(args, key);
+            }
+        };
+        Hash(context).forEach(function (v,k) { cb[k] = v });
+        
+        cb.into = function (k) {
+            key = k;
+            return cb;
+        };
+        
+        cb.next = function (err, xs) {
+            context.stack_.push.apply(context.stack_, xs);
+            cb.apply(cb, [err].concat(context.stack));
+        };
+        
+        cb.pass = function (err) {
+            cb.apply(cb, [err].concat(context.stack));
+        };
+        
+        cb.ok = cb.bind(cb, null);
+        
+        f.apply(cb, context.stack);
+    }
+    
+    var running = 0;
+    var errors = 0;
+    
+    this.seq = function (key, cb) {
+        var bound = [].slice.call(arguments, 2);
+        
+        if (typeof key === 'function') {
+            if (arguments.length > 1) bound.unshift(cb);
+            cb = key;
+            key = undefined;
+        }
+        
+        if (context.error) saw.next()
+        else if (running === 0) {
+            action(saw.step, key,
+                function () {
+                    context.stack_ = [];
+                    var args = [].slice.call(arguments);
+                    args.unshift.apply(args, bound.map(function (arg) {
+                        return arg === Seq ? this : arg
+                    }, this));
+                    
+                    cb.apply(this, args);
+                }, function () {
+                    context.stack = context.stack_;
+                    saw.next()
+                }
+            );
+        }
+    };
+    
+    var lastPar = null;
+    this.par = function (key, cb) {
+        lastPar = saw.step;
+        
+        if (running == 0) {
+            // empty the active stack for the first par() in a chain
+            context.stack_ = [];
+        }
+        
+        var bound = [].slice.call(arguments, 2);
+        if (typeof key === 'function') {
+            if (arguments.length > 1) bound.unshift(cb);
+            cb = key;
+            key = context.stack_.length;
+            context.stack_.push(null);
+        }
+        var cb_ = function () {
+            var args = [].slice.call(arguments);
+            args.unshift.apply(args, bound.map(function (arg) {
+                return arg === Seq ? this : arg
+            }, this));
+            
+            cb.apply(this, args);
+        };
+        
+        running ++;
+        
+        var step = saw.step;
+        process.nextTick(function () {
+            action(step, key, cb_, function (args) {
+                if (!args) errors ++;
+                
+                running --;
+                if (running == 0) {
+                    context.stack = context.stack_.slice();
+                    saw.step = lastPar;
+                    if (errors > 0) saw.down('catch');
+                    errors = 0;
+                    saw.next();
+                }
+            });
+        });
+        saw.next();
+    };
+    
+    [ 'seq', 'par' ].forEach(function (name) {
+        this[name + '_'] = function (key) {
+            var args = [].slice.call(arguments);
+            
+            var cb = typeof key === 'function'
+                ? args[0] : args[1];
+            
+            var fn = function () {
+                var argv = [].slice.call(arguments);
+                argv.unshift(this);
+                cb.apply(this, argv);
+            };
+            
+            if (typeof key === 'function') {
+                args[0] = fn;
+            }
+            else {
+                args[1] = fn;
+            }
+            
+            this[name].apply(this, args);
+        };
+    }, this);
+    
+    this['catch'] = function (cb) {
+        if (context.error) {
+            cb.call(context, context.error.message, context.error.key);
+            context.error = null;
+        }
+        saw.next();
+    };
+    
+    this.forEach = function (cb) {
+        this.seq(function () {
+            context.stack_ = context.stack.slice();
+            var end = context.stack.length;
+            
+            if (end === 0) this(null)
+            else context.stack.forEach(function (x, i) {
+                action(saw.step, i, function () {
+                    cb.call(this, x, i);
+                    if (i == end - 1) saw.next();
+                });
+            });
+        });
+    };
+    
+    this.seqEach = function (cb) {
+        this.seq(function () {
+            context.stack_ = context.stack.slice();
+            var xs = context.stack.slice();
+            if (xs.length === 0) this(null);
+            else (function next (i) {
+                action(
+                    saw.step, i,
+                    function () { cb.call(this, xs[i], i) },
+                    function (args) {
+                        if (!args || i === xs.length - 1) saw.next();
+                        else next(i + 1);
+                    }
+                );
+            }).bind(this)(0);
+        });
+    };
+    
+    this.parEach = function (limit, cb) {
+        var xs = context.stack.slice();
+        if (cb === undefined) { cb = limit; limit = xs.length }
+        context.stack_ = [];
+        
+        var active = 0;
+        var finished = 0;
+        var queue = [];
+        
+        if (xs.length === 0) saw.next()
+        else xs.forEach(function call (x, i) {
+            if (active >= limit) {
+                queue.push(call.bind(this, x, i));
+            }
+            else {
+                active ++;
+                action(saw.step, i,
+                    function () {
+                        cb.call(this, x, i);
+                    },
+                    function () {
+                        active --;
+                        finished ++;
+                        if (queue.length > 0) queue.shift()();
+                        else if (finished === xs.length) {
+                            saw.next();
+                        }
+                    }
+                );
+            }
+        });
+    };
+    
+    this.parMap = function (limit, cb) {
+        var res = [];
+        var len = context.stack.length;
+        if (cb === undefined) { cb = limit; limit = len }
+        var res = [];
+        
+        Seq()
+            .extend(context.stack)
+            .parEach(limit, function (x, i) {
+                var self = this;
+                
+                var next = function () {
+                    res[i] = arguments[1];
+                    self.apply(self, arguments);
+                };
+                
+                next.stack = self.stack;
+                next.stack_ = self.stack_;
+                next.vars = self.vars;
+                next.args = self.args;
+                next.error = self.error;
+                
+                next.into = function (key) {
+                    return function () {
+                        res[key] = arguments[1];
+                        self.apply(self, arguments);
+                    };
+                };
+                
+                next.ok = function () {
+                    var args = [].slice.call(arguments);
+                    args.unshift(null);
+                    return next.apply(next, args);
+                };
+                
+                cb.apply(next, arguments);
+            })
+            .seq(function () {
+                context.stack = res;
+                saw.next();
+            })
+        ;
+    };
+    
+    this.seqMap = function (cb) {
+        var res = [];
+        var lastIdx = context.stack.length - 1;
+        
+        this.seqEach(function (x, i) {
+            var self = this;
+            
+            var next = function () {
+                res[i] = arguments[1];
+                if (i === lastIdx)
+                    context.stack = res;
+                self.apply(self, arguments);
+            };
+            
+            next.stack = self.stack;
+            next.stack_ = self.stack_;
+            next.vars = self.vars;
+            next.args = self.args;
+            next.error = self.error;
+            
+            next.into = function (key) {
+                return function () {
+                    res[key] = arguments[1];
+                    if (i === lastIdx)
+                        context.stack = res;
+                    self.apply(self, arguments);
+                };
+            };
+            
+            next.ok = function () {
+                var args = [].slice.call(arguments);
+                args.unshift(null);
+                return next.apply(next, args);
+            };
+            
+            cb.apply(next, arguments);
+        });
+    };
+    
+    /**
+     * Consumes any errors that occur in `cb`. Calls to `this.into(i)` will place
+     * that value, if accepted by the filter, at the index in the results as
+     * if it were the i-th index before filtering. (This means it will never 
+     * override another value, and will only actually appear at i if the filter
+     * accepts all values before i.)
+     */
+    this.parFilter = function (limit, cb) {
+        var res = [];
+        var len = context.stack.length;
+        if (cb === undefined) { cb = limit; limit = len }
+        var res = [];
+        
+        Seq()
+            .extend(context.stack)
+            .parEach(limit, function (x, i) {
+                var self = this;
+                
+                var next = function (err, ok) {
+                    if (!err && ok)
+                        res.push([i, x]);
+                    arguments[0] = null; // discard errors
+                    self.apply(self, arguments);
+                };
+                
+                next.stack = self.stack;
+                next.stack_ = self.stack_;
+                next.vars = self.vars;
+                next.args = self.args;
+                next.error = self.error;
+                
+                next.into = function (key) {
+                    return function (err, ok) {
+                        if (!err && ok)
+                            res.push([key, x]);
+                        arguments[0] = null; // discard errors
+                        self.apply(self, arguments);
+                    };
+                };
+                
+                next.ok = function () {
+                    var args = [].slice.call(arguments);
+                    args.unshift(null);
+                    return next.apply(next, args);
+                };
+                
+                cb.apply(next, arguments);
+            })
+            .seq(function () {
+                context.stack = res.sort().map(function(pair){ return pair[1]; });
+                saw.next();
+            })
+        ;
+    };
+    
+    /**
+     * Consumes any errors that occur in `cb`. Calls to `this.into(i)` will place
+     * that value, if accepted by the filter, at the index in the results as
+     * if it were the i-th index before filtering. (This means it will never 
+     * override another value, and will only actually appear at i if the filter
+     * accepts all values before i.)
+     */
+    this.seqFilter = function (cb) {
+        var res = [];
+        var lastIdx = context.stack.length - 1;
+        
+        this.seqEach(function (x, i) {
+            var self = this;
+            
+            var next = function (err, ok) {
+                if (!err && ok)
+                    res.push([i, x]);
+                if (i === lastIdx)
+                    context.stack = res.sort().map(function(pair){ return pair[1]; });
+                arguments[0] = null; // discard errors
+                self.apply(self, arguments);
+            };
+            
+            next.stack = self.stack;
+            next.stack_ = self.stack_;
+            next.vars = self.vars;
+            next.args = self.args;
+            next.error = self.error;
+            
+            next.into = function (key) {
+                return function (err, ok) {
+                    if (!err && ok)
+                        res.push([key, x]);
+                    if (i === lastIdx)
+                        context.stack = res.sort().map(function(pair){ return pair[1]; });
+                    arguments[0] = null; // discard errors
+                    self.apply(self, arguments);
+                };
+            };
+            
+            next.ok = function () {
+                var args = [].slice.call(arguments);
+                args.unshift(null);
+                return next.apply(next, args);
+            };
+            
+            cb.apply(next, arguments);
+        });
+    };
+    
+    [ 'forEach', 'seqEach', 'parEach', 'seqMap', 'parMap', 'seqFilter', 'parFilter' ]
+        .forEach(function (name) {
+            this[name + '_'] = function (cb) {
+                this[name].call(this, function () {
+                    var args = [].slice.call(arguments);
+                    args.unshift(this);
+                    cb.apply(this, args);
+                });
+            };
+        }, this)
+    ;
+    
+    ['push','pop','shift','unshift','splice','reverse']
+        .forEach(function (name) {
+            this[name] = function () {
+                context.stack[name].apply(
+                    context.stack,
+                    [].slice.call(arguments)
+                );
+                saw.next();
+                return this;
+            };
+        }, this)
+    ;
+    
+    [ 'map', 'filter', 'reduce' ]
+        .forEach(function (name) {
+            this[name] = function () {
+                var res = context.stack[name].apply(
+                    context.stack,
+                    [].slice.call(arguments)
+                );
+                // stack must be an array, or bad things happen
+                context.stack = (Array.isArray(res) ? res : [res]);
+                saw.next();
+                return this;
+            };
+        }, this)
+    ;
+    
+    this.extend = function (xs) {
+        if (!Array.isArray(xs)) {
+            throw new Error('argument to .extend() is not an Array');
+        }
+        context.stack.push.apply(context.stack, xs);
+        saw.next();
+    };
+    
+    this.flatten = function (pancake) {
+        var xs = [];
+        // should we fully flatten this array? (default: true)
+        if (pancake === undefined) { pancake = true; }
+        context.stack.forEach(function f (x) {
+            if (Array.isArray(x) && pancake) x.forEach(f);
+            else if (Array.isArray(x)) xs = xs.concat(x);
+            else xs.push(x);
+        });
+        context.stack = xs;
+        saw.next();
+    };
+    
+    this.unflatten = function () {
+        context.stack = [context.stack];
+        saw.next();
+    };
+    
+    this.empty = function () {
+        context.stack = [];
+        saw.next();
+    };
+    
+    this.set = function (stack) {
+        context.stack = stack;
+        saw.next();
+    };
+    
+    this['do'] = function (cb) {
+        saw.nest(cb, context);
+    };
+}
diff --git a/debian/tests/node_modules/seq/package.json b/debian/tests/node_modules/seq/package.json
new file mode 100644
index 0000000..39784d1
--- /dev/null
+++ b/debian/tests/node_modules/seq/package.json
@@ -0,0 +1,74 @@
+{
+  "_from": "seq@>=0.1.7",
+  "_id": "seq@0.3.5",
+  "_inBundle": false,
+  "_integrity": "sha1-rgKvOkJHk9jMvyEtaRdODFTf/jg=",
+  "_location": "/seq",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "seq@>=0.1.7",
+    "name": "seq",
+    "escapedName": "seq",
+    "rawSpec": ">=0.1.7",
+    "saveSpec": null,
+    "fetchSpec": ">=0.1.7"
+  },
+  "_requiredBy": [
+    "/findit"
+  ],
+  "_resolved": "https://registry.npmjs.org/seq/-/seq-0.3.5.tgz";,
+  "_shasum": "ae02af3a424793d8ccbf212d69174e0c54dffe38",
+  "_spec": "seq@>=0.1.7",
+  "_where": "/home/xavier/dev/debian/packages/node-formidable/node_modules/findit",
+  "author": {
+    "name": "James Halliday",
+    "email": "mail@substack.net",
+    "url": "http://substack.net";
+  },
+  "bugs": {
+    "url": "https://github.com/substack/node-seq/issues";
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "chainsaw": ">=0.0.7 <0.1",
+    "hashish": ">=0.0.2 <0.1"
+  },
+  "deprecated": false,
+  "description": "Chainable asynchronous flow control with sequential and parallel primitives and pipeline-style error handling",
+  "devDependencies": {
+    "expresso": ">=0.7.x"
+  },
+  "engine": {
+    "node": ">=0.4.0"
+  },
+  "engines": {
+    "node": "*"
+  },
+  "homepage": "https://github.com/substack/node-seq#readme";,
+  "keywords": [
+    "flow-control",
+    "flow",
+    "control",
+    "async",
+    "asynchronous",
+    "chain",
+    "pipeline",
+    "sequence",
+    "sequential",
+    "parallel",
+    "error"
+  ],
+  "license": "MIT/X11",
+  "main": "./index.js",
+  "name": "seq",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/substack/node-seq.git"
+  },
+  "script": {
+    "test": "expresso"
+  },
+  "version": "0.3.5"
+}
diff --git a/debian/tests/node_modules/urun/.travis.yml b/debian/tests/node_modules/urun/.travis.yml
new file mode 100644
index 0000000..f1d0f13
--- /dev/null
+++ b/debian/tests/node_modules/urun/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+  - 0.4
+  - 0.6
diff --git a/debian/tests/node_modules/urun/Makefile b/debian/tests/node_modules/urun/Makefile
new file mode 100644
index 0000000..6a355bb
--- /dev/null
+++ b/debian/tests/node_modules/urun/Makefile
@@ -0,0 +1,6 @@
+SHELL := /bin/bash
+
+test:
+	@find test -name test-*.js -type f | xargs -tn1 node
+
+.PHONY: test
diff --git a/debian/tests/node_modules/urun/Readme.md b/debian/tests/node_modules/urun/Readme.md
new file mode 100644
index 0000000..0d9ea23
--- /dev/null
+++ b/debian/tests/node_modules/urun/Readme.md
@@ -0,0 +1,45 @@
+# urun
+
+[![Build Status](https://secure.travis-ci.org/felixge/node-urun.png)](http://travis-ci.org/felixge/node-urun)
+
+The minimal test runner.
+
+## Why yet another test runner?
+
+I wanted something simple, that just runs test files, shows progress, and
+behaves like a good UNIX citizen. Now it exists.
+
+## Install
+
+```
+npm install urun
+```
+
+## Usage
+
+In order to execute all test-*.js files inside a given directory, simply do:
+
+```js
+require('urun')(__dirname);
+```
+
+You now get a nice progress indication, as well as detailed output for each
+test that fails.
+
+The only other feature is specifying a regex for the files to run (default is
+`/test-.+\.js$/`), for example:
+
+```js
+require('urun')(__dirname, { include: /.+Test\.js$/ });
+```
+
+## Reporter
+
+```js
+require('urun')(__dirname, { reporter: 'BashReporter' }); // default
+require('urun')(__dirname, { reporter: 'BashTapReporter' }); // tap compliant output
+```
+
+## License
+
+This module is licensed under the MIT license.
diff --git a/debian/tests/node_modules/urun/index.js b/debian/tests/node_modules/urun/index.js
new file mode 100644
index 0000000..05ad807
--- /dev/null
+++ b/debian/tests/node_modules/urun/index.js
@@ -0,0 +1,23 @@
+var FileFilter   = require('./lib/FileFilter');
+var FileFinder   = require('./lib/FileFinder');
+var Runner       = require('./lib/Runner');
+
+module.exports = function(dir, options) {
+  var options  = options || {};
+  var include  = options.include  || /test-.+\.js$/;
+  var Reporter = require('./lib/reporter/'
+    + (process.env.REPORTER || options.reporter || 'BashReporter'));
+
+  var finder   = new FileFinder(dir);
+  var filter   = new FileFilter({include: include});
+
+  finder.execute(function(err, files) {
+    if (err) throw err;
+
+    files = filter.filter(files);
+
+    var runner   = new Runner({files: files});
+    var reporter = new Reporter({runner: runner});
+    runner.execute();
+  });
+};
diff --git a/debian/tests/node_modules/urun/lib/FileExecutor.js b/debian/tests/node_modules/urun/lib/FileExecutor.js
new file mode 100644
index 0000000..0d33451
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/FileExecutor.js
@@ -0,0 +1,46 @@
+var spawn = require('child_process').spawn;
+
+module.exports = FileExecutor;
+function FileExecutor(options) {
+  this._file   = options.file;
+  this._bin    = process.execPath;
+  this._cwd    = options.cwd || process.cwd();
+  this._output = '';
+}
+
+FileExecutor.prototype.execute = function(cb) {
+  var self  = this;
+  var child = spawn(this._bin, [this._file]);
+
+  this._capture(child.stdout);
+  this._capture(child.stderr);
+
+  child.on('exit', function(code, signal) {
+    cb(self._errorFor(code, signal), self._output);
+  });
+};
+
+FileExecutor.prototype._capture = function(stream) {
+  var self = this;
+
+  stream.setEncoding('utf8');
+  stream.on('data', function(chunk) {
+    self._output += chunk;
+  });
+};
+
+FileExecutor.prototype._errorFor = function(code, signal) {
+    if (!code && !signal) return null;
+
+    var prefix = 'node ' + this.relativePath() + ' died with ';
+
+    if (code) return new Error(prefix + 'code: ' + code);
+    if (signal) return new Error(prefix + 'signal: ' + signal);
+};
+
+FileExecutor.prototype.relativePath = function() {
+  var path = this._file;
+  return (path.indexOf(this._cwd) === 0)
+    ? path = path.substr(this._cwd.length + 1)
+    : path;
+};
diff --git a/debian/tests/node_modules/urun/lib/FileFilter.js b/debian/tests/node_modules/urun/lib/FileFilter.js
new file mode 100644
index 0000000..0ab530a
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/FileFilter.js
@@ -0,0 +1,16 @@
+module.exports = FileFilter;
+function FileFilter(options) {
+  options = options || {};
+
+  this._include = options.include;
+}
+
+FileFilter.prototype.filter = function(files) {
+  var self = this;
+
+  return files.filter(function(file) {
+    if (!self._include) return true;
+
+    return self._include.test(file);
+  });
+};
diff --git a/debian/tests/node_modules/urun/lib/FileFinder.js b/debian/tests/node_modules/urun/lib/FileFinder.js
new file mode 100644
index 0000000..a1f6c60
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/FileFinder.js
@@ -0,0 +1,66 @@
+var path = require('path');
+var fs   = require('fs');
+var noOp = function() {};
+
+module.exports = FileFinder;
+function FileFinder(dir) {
+  this._dir = dir;
+}
+
+FileFinder.prototype.execute = function(cb) {
+  var files = [];
+  this._readdir(this._dir, files, function(err) {
+    cb(err, files);
+  });
+};
+
+FileFinder.prototype._readdir = function(dir, results, cb) {
+  var self = this;
+  fs.readdir(dir, function(err, files) {
+    if (err) {
+      cb(err);
+      cb = noOp;
+      return;
+    }
+
+    self._inspect(dir, files, results, cb);
+  });
+};
+
+FileFinder.prototype._inspect = function(dir, files, results, cb) {
+  var remaining = files.length;
+  var self      = this;
+
+  if (!remaining) return cb(null);
+
+  files.forEach(function(file) {
+    var filePath = path.join(dir, file);
+
+    fs.stat(filePath, function(err, stat) {
+      if (err) {
+        cb(err);
+        cb = noOp;
+        return;
+      }
+
+      remaining--;
+      if (stat.isDirectory()) {
+        remaining++;
+        self._readdir(filePath, results, function(err) {
+          if (err) {
+            cb(err);
+            cb = noOp;
+            return;
+          }
+
+          remaining--;
+          if (!remaining) cb(null);
+        });
+      } else {
+        results.push(filePath);
+      }
+
+      if (!remaining) cb(null);
+    });
+  });
+};
diff --git a/debian/tests/node_modules/urun/lib/Runner.js b/debian/tests/node_modules/urun/lib/Runner.js
new file mode 100644
index 0000000..8a30375
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/Runner.js
@@ -0,0 +1,33 @@
+var FileExecutor = require('./FileExecutor');
+var EventEmitter = require('events').EventEmitter;
+var util         = require('util');
+
+module.exports = Runner;
+util.inherits(Runner, EventEmitter);
+function Runner(options) {
+  this._files = [].concat(options.files);
+  this._cwd   = options.cwd || process.cwd();
+}
+
+Runner.prototype.execute = function() {
+  this.emit('start', [].concat(this._files));
+  this._nextFile();
+};
+
+Runner.prototype._nextFile = function() {
+  var file = this._files.shift();
+  if (!file) {
+    this.emit('end');
+    return;
+  }
+
+  var self         = this;
+  var executor     = new FileExecutor({file: file, cwd: this._cwd});
+  var relativePath = executor.relativePath();
+
+  this.emit('fileStart', relativePath);
+  executor.execute(function(err, output) {
+    self.emit('fileEnd', relativePath, err, output);
+    self._nextFile();
+  });
+};
diff --git a/debian/tests/node_modules/urun/lib/reporter/BashReporter.js b/debian/tests/node_modules/urun/lib/reporter/BashReporter.js
new file mode 100644
index 0000000..22ca0f1
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/reporter/BashReporter.js
@@ -0,0 +1,101 @@
+var str = require('../str');
+
+module.exports = BashReporter;
+function BashReporter(options) {
+  this._runner      = options.runner;
+  this._currentFile = null;
+  this._lastLine    = null;
+  this._start       = null;
+  this._fail        = 0;
+  this._pass        = 0;
+  this._total       = 0;
+  this._interval    = null;
+
+  this._runner.on('start', this._handleStart.bind(this));
+  this._runner.on('fileStart', this._handleFileStart.bind(this));
+  this._runner.on('fileEnd', this._handleFileEnd.bind(this));
+  this._runner.on('end', this._handleEnd.bind(this));
+}
+
+BashReporter.prototype._handleStart = function(files) {
+  this._start    = Date.now();
+  this._total    = files.length;
+  this._interval = setInterval(this.updateProgress.bind(this), 1000);
+};
+
+BashReporter.prototype._handleFileStart = function(file) {
+  this._currentFile = file;
+  this.updateProgress();
+};
+
+BashReporter.prototype._handleFileEnd = function(file, err, output) {
+  if (err) {
+    this._fail++;
+
+    if (output.substr(0, 1) !== '\n') output = '\n' + output;
+    output = output.replace(/^/mg, '  ');
+
+    process.stdout.write('\n' + output + '\n');
+  } else {
+    this._pass++;
+  }
+
+  this.updateProgress();
+};
+
+BashReporter.prototype._handleEnd = function() {
+  process.stdout.write('\n');
+  clearInterval(this._interval);
+
+  var exitCode = (this._fail > 0)
+    ? 1
+    : 0;
+
+  process.exit(exitCode);
+};
+
+BashReporter.prototype.updateProgress = function() {
+  var template = '\r[%s %s %s/%s %s node %s]';
+
+  var line = str.sprintf(
+    template,
+    this.elapsedTime(),
+    this._fail,
+    this._pass,
+    this._total,
+    this.progress(),
+    this._currentFile
+  );
+
+  this.clearLine();
+  process.stdout.write(line);
+  this._lastLine = line;
+};
+
+BashReporter.prototype.clearLine = function() {
+  if (!this._lastLine) return;
+
+  var spaces = str.repeat(' ', this._lastLine.length);
+  process.stdout.write('\r' + spaces + '\r');
+};
+
+BashReporter.prototype.elapsedTime = function(showMs) {
+  var duration = new Date - this._start;
+
+  var seconds = Math.floor((duration) / 1000);
+  var minutes = Math.floor(seconds / 60);
+  var hours   = Math.floor(minutes / 60);
+
+  seconds -= (minutes * 60) - (hours * 60 * 60);
+  minutes -= hours * 60;
+
+  if (minutes < 10) minutes = '0' + minutes;
+  if (seconds < 10) seconds = '0' + seconds;
+
+  return hours + ':' + minutes + ':' + seconds;
+};
+
+BashReporter.prototype.progress = function() {
+  var index = this._fail + this._pass;
+  return ((index) * 100 / this._total).toFixed(1) + '%';
+};
diff --git a/debian/tests/node_modules/urun/lib/reporter/BashTapReporter.js b/debian/tests/node_modules/urun/lib/reporter/BashTapReporter.js
new file mode 100644
index 0000000..2694cda
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/reporter/BashTapReporter.js
@@ -0,0 +1,38 @@
+module.exports = BashTapReporter;
+
+function BashTapReporter(options) {
+  this._runner      = options.runner;
+  this._fail        = false;
+  this._count       = 1;
+
+  this._runner.on('start', this._handleStart.bind(this));
+  this._runner.on('fileEnd', this._handleFileEnd.bind(this));
+  this._runner.on('end', this._handleEnd.bind(this));
+}
+
+BashTapReporter.prototype._handleStart = function(files) {
+  console.log('%d..%d', 1, files.length);
+};
+
+BashTapReporter.prototype._handleFileEnd = function(file, err, output) {
+  if (err) {
+    console.log('not ok %d %s', this._count, this._tapTitle(file));
+    console.log(output.replace(/^/gm, '  '));
+    this._fail = true;
+  } else {
+    console.log('ok %d %s', this._count, this._tapTitle(file));
+  }
+  this._count++;
+};
+
+BashTapReporter.prototype._handleEnd = function() {
+  var exitCode = (this._fail)
+    ? 1
+    : 0;
+
+  process.exit(exitCode);
+};
+
+BashTapReporter.prototype._tapTitle = function(title) {
+  return title.replace(/#/g, '');
+}
diff --git a/debian/tests/node_modules/urun/lib/str.js b/debian/tests/node_modules/urun/lib/str.js
new file mode 100644
index 0000000..c6baf73
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/str.js
@@ -0,0 +1,30 @@
+var str  = module.exports;
+var util = require('util');
+
+// custom / simplified flavor of sprintf
+str.sprintf = function() {
+  var args = Array.prototype.slice.call(arguments);
+  var str = args.shift();
+
+  return str.replace(/%[so]/g, function(m, i, s) {
+    var arg = args.shift();
+    if (m == '%o') {
+      return util.inspect(arg);
+    }
+
+    if (!arg && arg !== 0) {
+      return '';
+    }
+
+    return arg.toString();
+  });
+};
+
+str.repeat = function(string, times) {
+  var repeated = '';
+  for (var i = 0; i < times; i++) {
+    repeated += string;
+  }
+
+  return repeated;
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/Makefile b/debian/tests/node_modules/urun/node_modules/utest/Makefile
new file mode 100644
index 0000000..6a355bb
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/Makefile
@@ -0,0 +1,6 @@
+SHELL := /bin/bash
+
+test:
+	@find test -name test-*.js -type f | xargs -tn1 node
+
+.PHONY: test
diff --git a/debian/tests/node_modules/urun/node_modules/utest/Readme.md b/debian/tests/node_modules/urun/node_modules/utest/Readme.md
new file mode 100644
index 0000000..674a92c
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/Readme.md
@@ -0,0 +1,76 @@
+# utest
+
+The minimal unit testing library.
+
+## Why yet another test library?
+
+I wanted something simple, that just does unit tests (no async) and nothing
+else. And each test is supposed to be a standalone UNIX program. Now it exists.
+
+## Install
+
+```
+npm install utest
+```
+
+## Usage
+
+Running a test with utest is very simple:
+
+```js
+var test   = require('utest');
+var assert = require('assert');
+
+test('Number#toFixed', {
+  'returns a string': function() {
+    assert.equal(typeof (5).toFixed(), 'string');
+  },
+
+  'takes number of decimal places': function() {
+    assert.equal((5).toFixed(1), '5.0');
+  },
+
+  'does not round': function() {
+    assert.equal((5.55).toFixed(1), '5.5');
+  },
+});
+```
+
+The only additional feature is running a before/after method:
+
+```js
+var test   = require('utest');
+var assert = require('assert');
+
+test('Date', {
+  before: function() {
+    this.date = new Date;
+  },
+
+  after: function() {
+    this.date = null;
+  },
+
+  'lets you manipulate the year': function() {
+    this.date.setYear(2012);
+    assert.equal(this.date.getFullYear(), 2012);
+  },
+
+  'can be coerced into a number': function() {
+    assert.equal(typeof +this.date, 'number');
+  },
+});
+```
+
+## Future Features
+
+I want to keep this library as minimal as possible, but I do consider the
+addition of the following features:
+
+* TAP output (if TAP=1 in the environment, switch to TapReporter class)
+* Leak detection (automatically add a final test that fails if there are global
+  leaks).
+
+## License
+
+This module is licensed under the MIT license.
diff --git a/debian/tests/node_modules/urun/node_modules/utest/index.js b/debian/tests/node_modules/urun/node_modules/utest/index.js
new file mode 100644
index 0000000..ec222e1
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/index.js
@@ -0,0 +1,16 @@
+module.exports     = utest;
+utest.Collection   = require('./lib/Collection');
+utest.TestCase     = require('./lib/TestCase');
+utest.BashReporter = require('./lib/reporter/BashReporter');
+
+var collection;
+var reporter;
+function utest(name, tests) {
+  if (!collection) {
+    collection = new utest.Collection();
+    reporter   = new utest.BashReporter({collection: collection});
+  }
+
+  var testCase = new utest.TestCase({name: name, tests: tests});
+  collection.add(testCase);
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/lib/Collection.js b/debian/tests/node_modules/urun/node_modules/utest/lib/Collection.js
new file mode 100644
index 0000000..db9be5c
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/lib/Collection.js
@@ -0,0 +1,33 @@
+var util         = require('util');
+var EventEmitter = require('events').EventEmitter;
+
+module.exports = Collection;
+util.inherits(Collection, EventEmitter);
+function Collection(options) {
+  this._pass = 0;
+  this._fail = 0;
+}
+
+Collection.prototype.add = function(testCase) {
+  this._start = this._start || Date.now();
+
+  var self = this;
+  testCase
+    .on('pass', function(name) {
+      self._pass++;
+      self.emit('pass', testCase, name);
+    })
+    .on('fail', function(name, err) {
+      self._fail++;
+      self.emit('fail', testCase, name, err);
+    })
+    .run();
+};
+
+Collection.prototype.stats = function() {
+  return {
+    pass     : this._pass,
+    fail     : this._fail,
+    duration : Date.now() - this._start,
+  };
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/lib/TestCase.js b/debian/tests/node_modules/urun/node_modules/utest/lib/TestCase.js
new file mode 100644
index 0000000..9e2a017
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/lib/TestCase.js
@@ -0,0 +1,36 @@
+var util         = require('util');
+var EventEmitter = require('events').EventEmitter;
+
+module.exports = TestCase;
+util.inherits(TestCase, EventEmitter);
+function TestCase(properties) {
+  this.name   = properties.name;
+  this._tests = properties.tests;
+}
+
+TestCase.prototype.run = function() {
+  var noop   = function() {};
+  var before = this._tests.before || noop;
+  var after  = this._tests.after || noop;
+
+  for (var test in this._tests) {
+    if (test === 'before' || test === 'after') continue;
+
+    var fn      = this._tests[test];
+    var context = {};
+
+    try {
+      before.call(context);
+      fn.call(context);
+      after.call(context);
+    } catch (_err) {
+      var err = _err;
+    }
+
+    if (!err) {
+      this.emit('pass', test);
+    } else {
+      this.emit('fail', test, err);
+    }
+  }
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/lib/reporter/BashReporter.js b/debian/tests/node_modules/urun/node_modules/utest/lib/reporter/BashReporter.js
new file mode 100644
index 0000000..69308fc
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/lib/reporter/BashReporter.js
@@ -0,0 +1,26 @@
+module.exports = BashReporter;
+function BashReporter(options) {
+  this._process    = options.process || process;
+  this._collection = options.collection;
+
+  this._collection.on('fail', this._handleFail.bind(this));
+  this._process.on('exit', this._handleExit.bind(this));
+}
+
+BashReporter.prototype._handleFail = function(testCase, test, error) {
+  this._process.stdout.write('Failed: ' + testCase.name + ' ' + test + '\n\n');
+  var stack = error.stack.replace(/^/gm, '  ');
+  this._process.stdout.write(stack + '\n\n');
+};
+
+BashReporter.prototype._handleExit = function() {
+  var stats = this._collection.stats();
+  this._process.stdout.write(
+    stats.fail + ' fail | ' +
+    stats.pass + ' pass | ' +
+    stats.duration + ' ms ' +
+    '\n'
+  );
+
+  if (stats.fail) this._process.reallyExit(1);
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/package.json b/debian/tests/node_modules/urun/node_modules/utest/package.json
new file mode 100644
index 0000000..47b5572
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/package.json
@@ -0,0 +1,48 @@
+{
+  "_from": "utest@0.0.2",
+  "_id": "utest@0.0.2",
+  "_inBundle": false,
+  "_integrity": "sha1-OGLil1MJ6l3glAREpsbuAXlyahY=",
+  "_location": "/urun/utest",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "utest@0.0.2",
+    "name": "utest",
+    "escapedName": "utest",
+    "rawSpec": "0.0.2",
+    "saveSpec": null,
+    "fetchSpec": "0.0.2"
+  },
+  "_requiredBy": [
+    "/urun"
+  ],
+  "_resolved": "https://registry.npmjs.org/utest/-/utest-0.0.2.tgz";,
+  "_shasum": "3862e2975309ea5de0940444a6c6ee0179726a16",
+  "_spec": "utest@0.0.2",
+  "_where": "/home/xavier/dev/debian/packages/node-formidable/node_modules/urun",
+  "author": {
+    "name": "Felix Geisendörfer",
+    "email": "felix@debuggable.com",
+    "url": "http://debuggable.com/";
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "The minimal unit testing library.",
+  "devDependencies": {},
+  "engines": {
+    "node": "*"
+  },
+  "homepage": "https://github.com/felixge/node-utest";,
+  "main": "./index",
+  "name": "utest",
+  "repository": {
+    "url": ""
+  },
+  "scripts": {
+    "test": "make test"
+  },
+  "version": "0.0.2"
+}
diff --git a/debian/tests/node_modules/urun/package.json b/debian/tests/node_modules/urun/package.json
new file mode 100644
index 0000000..c4b7633
--- /dev/null
+++ b/debian/tests/node_modules/urun/package.json
@@ -0,0 +1,54 @@
+{
+  "_from": "urun@^0.0.6",
+  "_id": "urun@0.0.6",
+  "_inBundle": false,
+  "_integrity": "sha1-4PqFaYA2fYa/FG4YC8OJAyCrHS8=",
+  "_location": "/urun",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "urun@^0.0.6",
+    "name": "urun",
+    "escapedName": "urun",
+    "rawSpec": "^0.0.6",
+    "saveSpec": null,
+    "fetchSpec": "^0.0.6"
+  },
+  "_requiredBy": [
+    "#DEV:/"
+  ],
+  "_resolved": "https://registry.npmjs.org/urun/-/urun-0.0.6.tgz";,
+  "_shasum": "e0fa856980367d86bf146e180bc3890320ab1d2f",
+  "_spec": "urun@^0.0.6",
+  "_where": "/home/xavier/dev/debian/packages/node-formidable",
+  "author": {
+    "name": "Felix Geisendörfer",
+    "email": "felix@debuggable.com",
+    "url": "http://debuggable.com/";
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "utest": "0.0.2"
+  },
+  "deprecated": false,
+  "description": "The minimal test runner.",
+  "devDependencies": {
+    "sinon": "1.2.0",
+    "utest": "0.0.1"
+  },
+  "engines": {
+    "node": "*"
+  },
+  "homepage": "https://github.com/felixge/node-urun";,
+  "main": "./index",
+  "name": "urun",
+  "optionalDependencies": {},
+  "repository": {
+    "url": ""
+  },
+  "scripts": {
+    "test": "make test"
+  },
+  "version": "0.0.6"
+}
diff --git a/debian/tests/node_modules/utest/.travis.yml b/debian/tests/node_modules/utest/.travis.yml
new file mode 100644
index 0000000..f1d0f13
--- /dev/null
+++ b/debian/tests/node_modules/utest/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+  - 0.4
+  - 0.6
diff --git a/debian/tests/node_modules/utest/Makefile b/debian/tests/node_modules/utest/Makefile
new file mode 100644
index 0000000..6a355bb
--- /dev/null
+++ b/debian/tests/node_modules/utest/Makefile
@@ -0,0 +1,6 @@
+SHELL := /bin/bash
+
+test:
+	@find test -name test-*.js -type f | xargs -tn1 node
+
+.PHONY: test
diff --git a/debian/tests/node_modules/utest/Readme.md b/debian/tests/node_modules/utest/Readme.md
new file mode 100644
index 0000000..0d789fe
--- /dev/null
+++ b/debian/tests/node_modules/utest/Readme.md
@@ -0,0 +1,106 @@
+# utest
+
+[![Build Status](https://secure.travis-ci.org/felixge/node-utest.png)](http://travis-ci.org/felixge/node-utest)
+
+The minimal unit testing library.
+
+## Why yet another test library?
+
+I wanted something simple, that just does unit tests (no async) and where each
+test is a standalone UNIX program. Now it exists.
+
+## How do I run async tests?
+
+Currently there is only one sane way: Do not use a framework. Instead use one
+file per test.
+
+If that becomes an issue, you should write more unit tests. (It is not a unit
+test if it does I/O).
+
+## Install
+
+```
+npm install utest
+```
+
+## Usage
+
+Running a test with utest is very simple:
+
+```js
+var test   = require('utest');
+var assert = require('assert');
+
+test('Number#toFixed', {
+  'returns a string': function() {
+    assert.equal(typeof (5).toFixed(), 'string');
+  },
+
+  'takes number of decimal places': function() {
+    assert.equal((5).toFixed(1), '5.0');
+  },
+
+  'does not round': function() {
+    assert.equal((5.55).toFixed(1), '5.5');
+  },
+});
+```
+
+It is also possible to define a before/after method:
+
+```js
+var test   = require('utest');
+var assert = require('assert');
+
+test('Date', {
+  before: function() {
+    this.date = new Date;
+  },
+
+  after: function() {
+    this.date = null;
+  },
+
+  'lets you manipulate the year': function() {
+    this.date.setYear(2012);
+    assert.equal(this.date.getFullYear(), 2012);
+  },
+
+  'can be coerced into a number': function() {
+    assert.equal(typeof +this.date, 'number');
+  },
+});
+```
+
+Last but not least, you can run individual tests by prefixing them with an
+exclamation mark. This is useful when putting debug statements into the subject
+under test:
+
+```js
+var test   = require('utest');
+var assert = require('assert');
+
+test('MyTest', {
+  '!will be executed': function() {
+    // ...
+  },
+
+  'will not be exectuted': function() {
+    // ...
+  },
+});
+```
+
+## Future Features
+
+I want to keep this library as minimal as possible, but I do consider the
+addition of the following features:
+
+* Nested test cases
+* TAP output (if TAP=1 in the environment, switch to TapReporter class)
+* Leak detection (automatically add a final test that fails if there are global
+  leaks).
+
+## License
+
+This module is licensed under the MIT license.
diff --git a/debian/tests/node_modules/utest/browser.js b/debian/tests/node_modules/utest/browser.js
new file mode 100644
index 0000000..32fd588
--- /dev/null
+++ b/debian/tests/node_modules/utest/browser.js
@@ -0,0 +1,20 @@
+if (!Function.prototype.bind) {
+  Function.prototype.bind = function (scope) {
+    var fn = this;
+    return function () {
+      return fn.apply(scope, arguments);
+    };
+  };
+}
+
+// Not shimed by Browserify:
+process.exit = function () {};
+
+var test = require('./index');
+test.Reporter = test.ConsoleReporter;
+
+module.exports = function (name, tests) {
+  process.nextTick(function () {
+    test(name, tests);
+  });
+};
diff --git a/debian/tests/node_modules/utest/index.js b/debian/tests/node_modules/utest/index.js
new file mode 100644
index 0000000..ac75255
--- /dev/null
+++ b/debian/tests/node_modules/utest/index.js
@@ -0,0 +1,23 @@
+module.exports        = utest;
+utest.Collection      = require('./lib/Collection');
+utest.TestCase        = require('./lib/TestCase');
+utest.BashReporter    = require('./lib/reporter/BashReporter');
+utest.ConsoleReporter = require('./lib/reporter/ConsoleReporter');
+utest.Reporter        = utest.BashReporter;
+
+var collection;
+var reporter;
+function utest(name, tests) {
+  if (!collection) {
+    collection = new utest.Collection();
+    reporter   = new utest.Reporter({collection: collection});
+
+    process.nextTick(collection.run.bind(collection));
+    collection.on('complete', function(stats) {
+      process.exit(stats.fail ? 1 : 0);
+    });
+  }
+
+  var testCase = new utest.TestCase({name: name, tests: tests});
+  collection.add(testCase);
+};
diff --git a/debian/tests/node_modules/utest/lib/Collection.js b/debian/tests/node_modules/utest/lib/Collection.js
new file mode 100644
index 0000000..385bc89
--- /dev/null
+++ b/debian/tests/node_modules/utest/lib/Collection.js
@@ -0,0 +1,54 @@
+var util         = require('util');
+var EventEmitter = require('events').EventEmitter;
+
+module.exports = Collection;
+util.inherits(Collection, EventEmitter);
+function Collection(options) {
+  this._pass                 = 0;
+  this._fail                 = 0;
+  this._skip                 = 0;
+  this._testCases            = [];
+  this._onlyRunSelectedTests = false;
+}
+
+Collection.prototype.add = function(testCase) {
+  this._testCases.push(testCase);
+  if (testCase.hasSelectedTests()) this._onlyRunSelectedTests = true;
+};
+
+Collection.prototype.run = function() {
+  this._start = this._start || Date.now();
+  for (var i = 0; i < this._testCases.length; i++) {
+    var testCase = this._testCases[i];
+    this._runTestCase(testCase);
+  }
+  this.emit('complete', this.stats());
+};
+
+Collection.prototype._runTestCase = function(testCase) {
+  this.emit('run', testCase);
+  var self = this;
+  testCase
+    .on('pass', function(name) {
+      self._pass++;
+      self.emit('pass', testCase, name);
+    })
+    .on('fail', function(name, err) {
+      self._fail++;
+      self.emit('fail', testCase, name, err);
+    })
+    .on('skip', function(name, err) {
+      self._skip++;
+      self.emit('skip', testCase, name);
+    })
+    .run(this._onlyRunSelectedTests);
+};
+
+Collection.prototype.stats = function() {
+  return {
+    pass     : this._pass,
+    fail     : this._fail,
+    skip     : this._skip,
+    duration : Date.now() - this._start,
+  };
+};
diff --git a/debian/tests/node_modules/utest/lib/TestCase.js b/debian/tests/node_modules/utest/lib/TestCase.js
new file mode 100644
index 0000000..1cbe1aa
--- /dev/null
+++ b/debian/tests/node_modules/utest/lib/TestCase.js
@@ -0,0 +1,61 @@
+var util         = require('util');
+var EventEmitter = require('events').EventEmitter;
+var doNothing    = function() {};
+
+module.exports = TestCase;
+util.inherits(TestCase, EventEmitter);
+function TestCase(properties) {
+  this.name   = properties.name;
+  this._tests = properties.tests;
+}
+
+TestCase.prototype.run = function(onlyRunSelectedTests) {
+  var before = this._tests.before || doNothing;
+  var after  = this._tests.after || doNothing;
+
+  for (var test in this._tests) {
+    if (test === 'before' || test === 'after') continue;
+
+    if (onlyRunSelectedTests && !this._isSelected(test)) {
+      this.emit('skip', test);
+      continue;
+    }
+
+    var fn      = this._tests[test];
+    var context = {};
+    var err     = null;
+
+    try {
+      before.call(context);
+      fn.call(context);
+    } catch (_err) {
+      err = _err;
+    } finally {
+      try {
+        after.call(context);
+      } catch (_err) {
+        if (!err) {
+          err = _err;
+        }
+      }
+    }
+
+    if (!err) {
+      this.emit('pass', test);
+    } else {
+      this.emit('fail', test, err);
+    }
+  }
+};
+
+TestCase.prototype.hasSelectedTests = function() {
+  for (var test in this._tests) {
+    if (this._isSelected(test)) return true;
+  }
+
+  return false;
+};
+
+TestCase.prototype._isSelected = function(test) {
+  return test.substr(0, 1) === '!';
+};
diff --git a/debian/tests/node_modules/utest/lib/reporter/BashReporter.js b/debian/tests/node_modules/utest/lib/reporter/BashReporter.js
new file mode 100644
index 0000000..b1a1237
--- /dev/null
+++ b/debian/tests/node_modules/utest/lib/reporter/BashReporter.js
@@ -0,0 +1,34 @@
+var Util = require('util');
+
+module.exports = BashReporter;
+function BashReporter(options) {
+  this._process    = options.process || process;
+  this._collection = options.collection;
+
+  this._collection.on('fail', this._handleFail.bind(this));
+  this._collection.on('complete', this._handleComplete.bind(this));
+}
+
+BashReporter.prototype._handleFail = function(testCase, test, error) {
+  this._process.stdout.write('Failed: ' + testCase.name + ' ' + test + '\n\n');
+  var stack = (error.stack)
+    ? error.stack
+    : 'Exception without stack: ' + Util.inspect(error);
+
+  stack = stack.replace(/^/gm, '  ');
+  this._process.stdout.write(stack + '\n\n');
+};
+
+BashReporter.prototype._handleComplete = function(stats) {
+  var output =
+    stats.fail + ' fail | ' +
+    stats.pass + ' pass | ' +
+    stats.duration + ' ms ' +
+    '\n';
+
+  if (stats.skip) {
+    output = stats.skip + ' SKIPPED | ' + output;
+  }
+
+  this._process.stdout.write(output);
+};
diff --git a/debian/tests/node_modules/utest/lib/reporter/ConsoleReporter.js b/debian/tests/node_modules/utest/lib/reporter/ConsoleReporter.js
new file mode 100644
index 0000000..a67e54c
--- /dev/null
+++ b/debian/tests/node_modules/utest/lib/reporter/ConsoleReporter.js
@@ -0,0 +1,34 @@
+var Util = require('util');
+
+module.exports = ConsoleReporter;
+function ConsoleReporter(options) {
+  this._collection = options.collection;
+
+  this._collection.on('run', this._handleRun.bind(this));
+  this._collection.on('fail', this._handleFail.bind(this));
+  this._collection.on('complete', this._handleComplete.bind(this));
+}
+
+ConsoleReporter.prototype._handleRun = function(testCase) {
+  console.log('Running: ' + testCase.name);
+};
+
+ConsoleReporter.prototype._handleFail = function(testCase, test, error) {
+  var msg   = 'Failed: ' + testCase.name + ' ' + test;
+  var stack = (error.stack)
+    ? error.stack
+    : 'Exception without stack: ' + Util.inspect(error);
+
+  stack = stack.replace(/^/gm, '  ');
+  console.error(msg + '\n\n' + stack + '\n');
+};
+
+ConsoleReporter.prototype._handleComplete = function(stats) {
+  if (stats.skip) {
+    console.warn(stats.skip + ' SKIPPED');
+  }
+  console.info(stats.fail + ' fail | ' +
+    stats.pass  + ' pass | ' +
+    stats.duration + ' ms');
+
+};
diff --git a/debian/tests/node_modules/utest/package.json b/debian/tests/node_modules/utest/package.json
new file mode 100644
index 0000000..e7fd6ab
--- /dev/null
+++ b/debian/tests/node_modules/utest/package.json
@@ -0,0 +1,50 @@
+{
+  "_from": "utest@^0.0.8",
+  "_id": "utest@0.0.8",
+  "_inBundle": false,
+  "_integrity": "sha1-/AlFH+aXuQCNDEMv4NtDnWzzeRQ=",
+  "_location": "/utest",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "utest@^0.0.8",
+    "name": "utest",
+    "escapedName": "utest",
+    "rawSpec": "^0.0.8",
+    "saveSpec": null,
+    "fetchSpec": "^0.0.8"
+  },
+  "_requiredBy": [
+    "#DEV:/"
+  ],
+  "_resolved": "https://registry.npmjs.org/utest/-/utest-0.0.8.tgz";,
+  "_shasum": "fc09451fe697b9008d0c432fe0db439d6cf37914",
+  "_spec": "utest@^0.0.8",
+  "_where": "/home/xavier/dev/debian/packages/node-formidable",
+  "author": {
+    "name": "Felix Geisendörfer",
+    "email": "felix@debuggable.com",
+    "url": "http://debuggable.com/";
+  },
+  "browser": "./browser.js",
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "The minimal unit testing library.",
+  "devDependencies": {},
+  "engines": {
+    "node": "*"
+  },
+  "homepage": "https://github.com/felixge/node-utest";,
+  "main": "./index",
+  "name": "utest",
+  "optionalDependencies": {},
+  "repository": {
+    "url": ""
+  },
+  "scripts": {
+    "test": "make test"
+  },
+  "version": "0.0.8"
+}
diff --git a/debian/tests/node_modules/utest/syntax.json b/debian/tests/node_modules/utest/syntax.json
new file mode 100644
index 0000000..b98ee1b
--- /dev/null
+++ b/debian/tests/node_modules/utest/syntax.json
@@ -0,0 +1,5 @@
+{
+  "addSemicolons": true,
+  "trimWhitespace": true,
+  "quotes": "'"
+}
diff --git a/debian/tests/pkg-js/files b/debian/tests/pkg-js/files
new file mode 100644
index 0000000..af03f72
--- /dev/null
+++ b/debian/tests/pkg-js/files
@@ -0,0 +1,2 @@
+debian/tests/node_modules
+test
diff --git a/debian/tests/pkg-js/test b/debian/tests/pkg-js/test
new file mode 100644
index 0000000..b104878
--- /dev/null
+++ b/debian/tests/pkg-js/test
@@ -0,0 +1 @@
+NODE_PATH=debian/tests/node_modules node test/run.js
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
new file mode 100644
index 0000000..28cff30
--- /dev/null
+++ b/debian/upstream/metadata
@@ -0,0 +1,7 @@
+---
+Archive: GitHub
+Bug-Database: https://github.com/felixge/node-formidable/issues
+Contact: https://github.com/felixge/node-formidable/issues
+Name: node-formidable
+Repository: https://github.com/felixge/node-formidable.git
+Repository-Browse: https://github.com/felixge/node-formidable
diff --git a/debian/watch b/debian/watch
index c125df3..fe59010 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,3 +1,5 @@
-version=3
-https://alioth.debian.org/~dapal/npmjs.php?id=formidable \
-	http://registry.npmjs.org/formidable/-/formidable-(\d+.*)\.tgz
+version=4
+opts=\
+dversionmangle=auto,\
+filenamemangle=s/.*\/v?([\d\.-]+)\.tar\.gz/node-formidable-$1.tar.gz/ \
+ https://github.com/felixge/node-formidable/releases .*/archive/v?([\d\.]+).tar.gz
diff --git a/example/json.js b/example/json.js
index eb8a724..0ef5a42 100644
--- a/example/json.js
+++ b/example/json.js
@@ -8,8 +8,8 @@ var common = require('../test/common'),
 
 server = http.createServer(function(req, res) {
   if (req.method !== 'POST') {
-    res.writeHead(200, {'content-type': 'text/plain'})
-    res.end('Please POST a JSON payload to http://localhost:'+port+'/')
+    res.writeHead(200, {'content-type': 'text/plain'});
+    res.end('Please POST a JSON payload to http://localhost:'+port+'/');
     return;
   }
 
@@ -50,18 +50,18 @@ var request = http.request({
   console.log('Status:', response.statusCode);
   response.pipe(process.stdout);
   response.on('end', function() {
-    console.log('\n')
+    console.log('\n');
     process.exit();
   });
   // response.on('data', function(chunk) {
   //   data += chunk.toString('utf8');
   // });
   // response.on('end', function() {
-  //   console.log('Response Data:')
+  //   console.log('Response Data:');
   //   console.log(data);
   //   process.exit();
   // });
-})
+});
 
 request.write('{"numbers":[1,2,3,4,5],"nested":{"key":"value"}}');
 request.end();
diff --git a/example/post.js b/example/post.js
index f6c15a6..8458fbd 100644
--- a/example/post.js
+++ b/example/post.js
@@ -1,7 +1,8 @@
-require('../test/common');
+var common = require('../test/common');
 var http = require('http'),
     util = require('util'),
-    formidable = require('formidable'),
+    formidable = common.formidable,
+    port = common.port,
     server;
 
 server = http.createServer(function(req, res) {
@@ -38,6 +39,6 @@ server = http.createServer(function(req, res) {
     res.end('404');
   }
 });
-server.listen(TEST_PORT);
+server.listen(port);
 
-console.log('listening on http://localhost:'+TEST_PORT+'/');
+console.log('listening on http://localhost:'+port+'/');
diff --git a/example/upload.js b/example/upload.js
index 050cdd9..0b498d6 100644
--- a/example/upload.js
+++ b/example/upload.js
@@ -1,7 +1,9 @@
-require('../test/common');
+var common = require('../test/common');
 var http = require('http'),
     util = require('util'),
-    formidable = require('formidable'),
+    os = require('os'),
+    formidable = common.formidable,
+    port = common.port,
     server;
 
 server = http.createServer(function(req, res) {
@@ -19,7 +21,7 @@ server = http.createServer(function(req, res) {
         files = [],
         fields = [];
 
-    form.uploadDir = TEST_TMP;
+    form.uploadDir = os.tmpdir();
 
     form
       .on('field', function(field, value) {
@@ -43,6 +45,6 @@ server = http.createServer(function(req, res) {
     res.end('404');
   }
 });
-server.listen(TEST_PORT);
+server.listen(port);
 
-console.log('listening on http://localhost:'+TEST_PORT+'/');
+console.log('listening on http://localhost:'+port+'/');
diff --git a/lib/file.js b/lib/file.js
index 1e7184d..50d34c0 100644
--- a/lib/file.js
+++ b/lib/file.js
@@ -1,7 +1,7 @@
 if (global.GENTLY) require = GENTLY.hijack(require);
 
 var util = require('util'),
-    WriteStream = require('fs').WriteStream,
+    fs = require('fs'),
     EventEmitter = require('events').EventEmitter,
     crypto = require('crypto');
 
@@ -23,17 +23,19 @@ function File(properties) {
 
   if(typeof this.hash === 'string') {
     this.hash = crypto.createHash(properties.hash);
+  } else {
+    this.hash = null;
   }
 }
 module.exports = File;
 util.inherits(File, EventEmitter);
 
 File.prototype.open = function() {
-  this._writeStream = new WriteStream(this.path);
+  this._writeStream = new fs.WriteStream(this.path);
 };
 
 File.prototype.toJSON = function() {
-  return {
+  var json = {
     size: this.size,
     path: this.path,
     name: this.name,
@@ -43,16 +45,23 @@ File.prototype.toJSON = function() {
     filename: this.filename,
     mime: this.mime
   };
+  if (this.hash && this.hash != "") {
+    json.hash = this.hash;
+  }
+  return json;
 };
 
 File.prototype.write = function(buffer, cb) {
   var self = this;
+  if (self.hash) {
+    self.hash.update(buffer);
+  }
+
+  if (this._writeStream.closed) {
+    return cb();
+  }
+
   this._writeStream.write(buffer, function() {
-    if (self.hash) {
-      if (self.hash.hasOwnProperty('update')) {
-        self.hash.update(buffer);
-      }
-    }
     self.lastModifiedDate = new Date();
     self.size += buffer.length;
     self.emit('progress', self.size);
@@ -62,10 +71,10 @@ File.prototype.write = function(buffer, cb) {
 
 File.prototype.end = function(cb) {
   var self = this;
+  if (self.hash) {
+    self.hash = self.hash.digest('hex');
+  }
   this._writeStream.end(function() {
-    if(self.hash) {
-      self.hash = self.hash.digest('hex');
-    }
     self.emit('end');
     cb();
   });
diff --git a/lib/incoming_form.js b/lib/incoming_form.js
index 291236d..dbd920b 100644
--- a/lib/incoming_form.js
+++ b/lib/incoming_form.js
@@ -1,5 +1,6 @@
 if (global.GENTLY) require = GENTLY.hijack(require);
 
+var crypto = require('crypto');
 var fs = require('fs');
 var util = require('util'),
     path = require('path'),
@@ -23,13 +24,15 @@ function IncomingForm(opts) {
   this.ended = false;
 
   this.maxFields = opts.maxFields || 1000;
-  this.maxFieldsSize = opts.maxFieldsSize || 2 * 1024 * 1024;
+  this.maxFieldsSize = opts.maxFieldsSize || 20 * 1024 * 1024;
+  this.maxFileSize = opts.maxFileSize || 200 * 1024 * 1024;
   this.keepExtensions = opts.keepExtensions || false;
-  this.uploadDir = opts.uploadDir || os.tmpDir();
+  this.uploadDir = opts.uploadDir || (os.tmpdir && os.tmpdir()) || os.tmpDir();
   this.encoding = opts.encoding || 'utf-8';
   this.headers = null;
   this.type = null;
-  this.hash = false;
+  this.hash = opts.hash || false;
+  this.multiples = opts.multiples || false;
 
   this.bytesReceived = null;
   this.bytesExpected = null;
@@ -37,10 +40,11 @@ function IncomingForm(opts) {
   this._parser = null;
   this._flushing = 0;
   this._fieldsSize = 0;
+  this._fileSize = 0;
   this.openedFiles = [];
 
   return this;
-};
+}
 util.inherits(IncomingForm, EventEmitter);
 exports.IncomingForm = IncomingForm;
 
@@ -74,6 +78,40 @@ IncomingForm.prototype.parse = function(req, cb) {
     return true;
   };
 
+  // Setup callback first, so we don't miss anything from data events emitted
+  // immediately.
+  if (cb) {
+    var fields = {}, files = {};
+    this
+      .on('field', function(name, value) {
+        fields[name] = value;
+      })
+      .on('file', function(name, file) {
+        if (this.multiples) {
+          if (files[name]) {
+            if (!Array.isArray(files[name])) {
+              files[name] = [files[name]];
+            }
+            files[name].push(file);
+          } else {
+            files[name] = file;
+          }
+        } else {
+          files[name] = file;
+        }
+      })
+      .on('error', function(err) {
+        cb(err, fields, files);
+      })
+      .on('end', function() {
+        cb(null, fields, files);
+      });
+  }
+
+  // Parse headers and setup the parser, ready to start listening for data.
+  this.writeHeaders(req.headers);
+
+  // Start listening for data.
   var self = this;
   req
     .on('error', function(err) {
@@ -97,25 +135,6 @@ IncomingForm.prototype.parse = function(req, cb) {
       }
     });
 
-  if (cb) {
-    var fields = {}, files = {};
-    this
-      .on('field', function(name, value) {
-        fields[name] = value;
-      })
-      .on('file', function(name, file) {
-        files[name] = file;
-      })
-      .on('error', function(err) {
-        cb(err, fields, files);
-      })
-      .on('end', function() {
-        cb(null, fields, files);
-      });
-  }
-
-  this.writeHeaders(req.headers);
-
   return this;
 };
 
@@ -126,8 +145,11 @@ IncomingForm.prototype.writeHeaders = function(headers) {
 };
 
 IncomingForm.prototype.write = function(buffer) {
+  if (this.error) {
+    return;
+  }
   if (!this._parser) {
-    this._error(new Error('unintialized parser'));
+    this._error(new Error('uninitialized parser'));
     return;
   }
 
@@ -160,6 +182,7 @@ IncomingForm.prototype.onPart = function(part) {
 IncomingForm.prototype.handlePart = function(part) {
   var self = this;
 
+  // This MUST check exactly for undefined. You can not change it to !part.filename.
   if (part.filename === undefined) {
     var value = ''
       , decoder = new StringDecoder(this.encoding);
@@ -194,6 +217,14 @@ IncomingForm.prototype.handlePart = function(part) {
   this.openedFiles.push(file);
 
   part.on('data', function(buffer) {
+    self._fileSize += buffer.length;
+    if (self._fileSize > self.maxFileSize) {
+      self._error(new Error('maxFileSize exceeded, received '+self._fileSize+' bytes of file data'));
+      return;
+    }
+    if (buffer.length == 0) {
+      return;
+    }
     self.pause();
     file.write(buffer, function() {
       self.resume();
@@ -241,8 +272,8 @@ IncomingForm.prototype._parseContentType = function() {
   }
 
   if (this.headers['content-type'].match(/multipart/i)) {
-    var m;
-    if (m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i)) {
+    var m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i);
+    if (m) {
       this._initMultipart(m[1] || m[2]);
     } else {
       this._error(new Error('bad content-type header, no multipart boundary'));
@@ -264,21 +295,25 @@ IncomingForm.prototype._error = function(err) {
   }
 
   this.error = err;
-  this.pause();
   this.emit('error', err);
 
   if (Array.isArray(this.openedFiles)) {
     this.openedFiles.forEach(function(file) {
       file._writeStream.destroy();
-      setTimeout(fs.unlink, 0, file.path);
+      setTimeout(fs.unlink, 0, file.path, function(error) { });
     });
   }
 };
 
 IncomingForm.prototype._parseContentLength = function() {
+  this.bytesReceived = 0;
   if (this.headers['content-length']) {
-    this.bytesReceived = 0;
     this.bytesExpected = parseInt(this.headers['content-length'], 10);
+  } else if (this.headers['transfer-encoding'] === undefined) {
+    this.bytesExpected = 0;
+  }
+
+  if (this.bytesExpected !== null) {
     this.emit('progress', this.bytesReceived, this.bytesExpected);
   }
 };
@@ -325,10 +360,11 @@ IncomingForm.prototype._initMultipart = function(boundary) {
     headerField = headerField.toLowerCase();
     part.headers[headerField] = headerValue;
 
-    var m;
+    // matches either a quoted-string or a token (RFC 2616 section 19.5.1)
+    var m = headerValue.match(/\bname=("([^"]*)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))/i);
     if (headerField == 'content-disposition') {
-      if (m = headerValue.match(/\bname="([^"]+)"/i)) {
-        part.name = m[1];
+      if (m) {
+        part.name = m[2] || m[3] || '';
       }
 
       part.filename = self._fileName(headerValue);
@@ -366,13 +402,13 @@ IncomingForm.prototype._initMultipart = function(boundary) {
         can be divided by 4, it will result in a number of buytes that
         can be divided vy 3.
         */
-        var offset = parseInt(part.transferBuffer.length / 4) * 4;
-        part.emit('data', new Buffer(part.transferBuffer.substring(0, offset), 'base64'))
+        var offset = parseInt(part.transferBuffer.length / 4, 10) * 4;
+        part.emit('data', new Buffer(part.transferBuffer.substring(0, offset), 'base64'));
         part.transferBuffer = part.transferBuffer.substring(offset);
       };
 
       parser.onPartEnd = function() {
-        part.emit('data', new Buffer(part.transferBuffer, 'base64'))
+        part.emit('data', new Buffer(part.transferBuffer, 'base64'));
         part.emit('end');
       };
       break;
@@ -394,10 +430,12 @@ IncomingForm.prototype._initMultipart = function(boundary) {
 };
 
 IncomingForm.prototype._fileName = function(headerValue) {
-  var m = headerValue.match(/\bfilename="(.*?)"($|; )/i);
+  // matches either a quoted-string or a token (RFC 2616 section 19.5.1)
+  var m = headerValue.match(/\bfilename=("(.*?)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))($|;\s)/i);
   if (!m) return;
 
-  var filename = m[1].substr(m[1].lastIndexOf('\\') + 1);
+  var match = m[2] || m[3] || '';
+  var filename = match.substr(match.lastIndexOf('\\') + 1);
   filename = filename.replace(/%22/g, '"');
   filename = filename.replace(/&#([\d]{4});/g, function(m, code) {
     return String.fromCharCode(code);
@@ -434,10 +472,9 @@ IncomingForm.prototype._initOctetStream = function() {
     type: mime
   });
 
-  file.open();
-
   this.emit('fileBegin', filename, file);
-
+  file.open();
+  this.openedFiles.push(file);
   this._flushing++;
 
   var self = this;
@@ -466,8 +503,10 @@ IncomingForm.prototype._initOctetStream = function() {
     self.ended = true;
 
     var done = function(){
-      self.emit('file', 'file', file);
-      self._maybeEnd();
+      file.end(function() {
+        self.emit('file', 'file', file);
+        self._maybeEnd();
+      });
     };
 
     if(outstandingWrites === 0){
@@ -481,16 +520,12 @@ IncomingForm.prototype._initOctetStream = function() {
 IncomingForm.prototype._initJSONencoded = function() {
   this.type = 'json';
 
-  var parser = new JSONParser()
+  var parser = new JSONParser(this)
     , self = this;
 
-  if (this.bytesExpected) {
-    parser.initWithLength(this.bytesExpected);
-  }
-
   parser.onField = function(key, val) {
     self.emit('field', key, val);
-  }
+  };
 
   parser.onEnd = function() {
     self.ended = true;
@@ -501,14 +536,12 @@ IncomingForm.prototype._initJSONencoded = function() {
 };
 
 IncomingForm.prototype._uploadPath = function(filename) {
-  var name = '';
-  for (var i = 0; i < 32; i++) {
-    name += Math.floor(Math.random() * 16).toString(16);
-  }
+  var buf = crypto.randomBytes(16);
+  var name = 'upload_' + buf.toString('hex');
 
   if (this.keepExtensions) {
     var ext = path.extname(filename);
-    ext     = ext.replace(/(\.[a-z0-9]+).*/, '$1');
+    ext     = ext.replace(/(\.[a-z0-9]+).*/i, '$1');
 
     name += ext;
   }
@@ -523,4 +556,3 @@ IncomingForm.prototype._maybeEnd = function() {
 
   this.emit('end');
 };
-
diff --git a/lib/json_parser.js b/lib/json_parser.js
index 6ce966b..28a23ba 100644
--- a/lib/json_parser.js
+++ b/lib/json_parser.js
@@ -1,35 +1,30 @@
 if (global.GENTLY) require = GENTLY.hijack(require);
 
-var Buffer = require('buffer').Buffer
+var Buffer = require('buffer').Buffer;
 
-function JSONParser() {
-  this.data = new Buffer('');
+function JSONParser(parent) {
+  this.parent = parent;
+  this.chunks = [];
   this.bytesWritten = 0;
-};
-exports.JSONParser = JSONParser;
-
-JSONParser.prototype.initWithLength = function(length) {
-  this.data = new Buffer(length);
 }
+exports.JSONParser = JSONParser;
 
 JSONParser.prototype.write = function(buffer) {
-  if (this.data.length >= this.bytesWritten + buffer.length) {
-    buffer.copy(this.data, this.bytesWritten);
-  } else {
-    this.data = Buffer.concat([this.data, buffer]);
-  }
   this.bytesWritten += buffer.length;
+  this.chunks.push(buffer);
   return buffer.length;
-}
+};
 
 JSONParser.prototype.end = function() {
   try {
-    var fields = JSON.parse(this.data.toString('utf8'))
+    var fields = JSON.parse(Buffer.concat(this.chunks));
     for (var field in fields) {
       this.onField(field, fields[field]);
     }
-  } catch (e) {}
+  } catch (e) {
+    this.parent.emit('error', e);
+  }
   this.data = null;
 
   this.onEnd();
-}
\ No newline at end of file
+};
diff --git a/lib/multipart_parser.js b/lib/multipart_parser.js
index 98a6856..36de2b0 100644
--- a/lib/multipart_parser.js
+++ b/lib/multipart_parser.js
@@ -46,7 +46,7 @@ function MultipartParser() {
 
   this.index = null;
   this.flags = 0;
-};
+}
 exports.MultipartParser = MultipartParser;
 
 MultipartParser.stateToString = function(stateNumber) {
@@ -58,8 +58,8 @@ MultipartParser.stateToString = function(stateNumber) {
 
 MultipartParser.prototype.initWithBoundary = function(str) {
   this.boundary = new Buffer(str.length+4);
-  this.boundary.write('\r\n--', 'ascii', 0);
-  this.boundary.write(str, 'ascii', 4);
+  this.boundary.write('\r\n--', 0);
+  this.boundary.write(str, 4);
   this.lookbehind = new Buffer(this.boundary.length+8);
   this.state = S.START;
 
@@ -127,18 +127,25 @@ MultipartParser.prototype.write = function(buffer) {
         state = S.START_BOUNDARY;
       case S.START_BOUNDARY:
         if (index == boundary.length - 2) {
-          if (c != CR) {
+          if (c == HYPHEN) {
+            flags |= F.LAST_BOUNDARY;
+          } else if (c != CR) {
             return i;
           }
           index++;
           break;
         } else if (index - 1 == boundary.length - 2) {
-          if (c != LF) {
+          if (flags & F.LAST_BOUNDARY && c == HYPHEN){
+            callback('end');
+            state = S.END;
+            flags = 0;
+          } else if (!(flags & F.LAST_BOUNDARY) && c == LF) {
+            index = 0;
+            callback('partBegin');
+            state = S.HEADER_FIELD_START;
+          } else {
             return i;
           }
-          index = 0;
-          callback('partBegin');
-          state = S.HEADER_FIELD_START;
           break;
         }
 
@@ -214,7 +221,7 @@ MultipartParser.prototype.write = function(buffer) {
       case S.PART_DATA:
         prevIndex = index;
 
-        if (index == 0) {
+        if (index === 0) {
           // boyer-moore derrived algorithm to safely skip non-boundary data
           i += boundaryEnd;
           while (i < bufferLength && !(buffer[i] in boundaryChars)) {
@@ -226,7 +233,7 @@ MultipartParser.prototype.write = function(buffer) {
 
         if (index < boundary.length) {
           if (boundary[index] == c) {
-            if (index == 0) {
+            if (index === 0) {
               dataCallback('partData', true);
             }
             index++;
@@ -260,6 +267,7 @@ MultipartParser.prototype.write = function(buffer) {
               callback('partEnd');
               callback('end');
               state = S.END;
+              flags = 0;
             } else {
               index = 0;
             }
@@ -310,7 +318,7 @@ MultipartParser.prototype.end = function() {
       self[callbackSymbol]();
     }
   };
-  if ((this.state == S.HEADER_FIELD_START && this.index == 0) ||
+  if ((this.state == S.HEADER_FIELD_START && this.index === 0) ||
       (this.state == S.PART_DATA && this.index == this.boundary.length)) {
     callback(this, 'partEnd');
     callback(this, 'end');
diff --git a/lib/querystring_parser.js b/lib/querystring_parser.js
index 320ce5a..fcaffe0 100644
--- a/lib/querystring_parser.js
+++ b/lib/querystring_parser.js
@@ -7,7 +7,7 @@ var querystring = require('querystring');
 function QuerystringParser(maxKeys) {
   this.maxKeys = maxKeys;
   this.buffer = '';
-};
+}
 exports.QuerystringParser = QuerystringParser;
 
 QuerystringParser.prototype.write = function(buffer) {
diff --git a/package.json b/package.json
index 4b42a1d..bf07c37 100644
--- a/package.json
+++ b/package.json
@@ -2,14 +2,15 @@
   "name": "formidable",
   "description": "A node.js module for parsing form data, especially file uploads.",
   "homepage": "https://github.com/felixge/node-formidable";,
-  "version": "1.0.13",
+  "license": "MIT",
+  "version": "1.2.1",
   "devDependencies": {
-    "gently": "0.8.0",
-    "findit": "0.1.1",
-    "hashish": "0.0.4",
-    "urun": "~0.0.6",
-    "utest": "0.0.3",
-    "request": "~2.11.4"
+    "gently": "^0.8.0",
+    "findit": "^0.1.2",
+    "hashish": "^0.0.4",
+    "urun": "^0.0.6",
+    "utest": "^0.0.8",
+    "request": "^2.11.4"
   },
   "directories": {
     "lib": "./lib"
@@ -19,9 +20,6 @@
     "test": "node test/run.js",
     "clean": "rm test/tmp/*"
   },
-  "engines": {
-    "node": "<0.9.0"
-  },
   "repository": {
     "type": "git",
     "url": "git://github.com/felixge/node-formidable.git"
diff --git a/test/fixture/http/encoding/beta-sticker-1.png.http b/test/fixture/http/encoding/beta-sticker-1.png.http
new file mode 100644
index 0000000..833b83c
--- /dev/null
+++ b/test/fixture/http/encoding/beta-sticker-1.png.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Length: 2483
+
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Disposition: form-data; name="sticker"; filename="beta-sticker-1.png"
+Content-Type: image/png
+Content-Transfer-Encoding: base64
+
+iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABh5JREFUeNrMmHtIHEcYwGfv5SNwaovxEanEiJKqlYCCTRo1f0SvDeof1legEcE/YttQaNOiaQjYFFtpKaJILZU8SCRUWqlJGpoWepGLTXqUEnzFxCrnK9DEelbvvPOe/WacuY7r7HmGFjrwsbNzt7u//V7zfYvQ/2xI/9K1/NyvMP9PgCTuGmmL6/0ckD9UOGmbIExUsqMkAPHJjv5QwKRtgKioqDlh5+w/7IFeCuLlxCeA2zQ0IcCwh2qoaLH09fUdTElJ2e/1elU+n0/y+9fvPz4+fvfYsWN3YOoBcXPiocLghD4mBYHhQTCErqWlZU9FRcXJqKiowyqVSk/uSEH4o8fjWVlYWDB2d3e3d3R0WGB5jYqLg/NyGgsKxMNgkDB4451NTU3vxcXF1SlBKB0tFsuVxsbGjlu3bj2GJQeIk8K5RVBqBTMxrYRfuHAh9/jx4+ejo6MPS9I6f6hHPOC6rOLi4vyVlZXf7t27Z5c5/iZfkgMxxyUwFy9ezC0tLe3V6XRJ/MOCAYjWwsLCni0oKCh98uSJaWhoyMZFn0/uT2qBqYi/1NbWxjc0NJwPFUYExc/B53R5eXk5ZrN5YH5+3slFn5+D2uBDzG90IJETExOtzGdC9RelNf78wYMH3xQWFn4Ep0sgyyCr1NmJP6kEIa5tbW3dEx8fXxeKRoJpT76OR3p6enllZWUKTCOwNalFAglWDkTCvLq6+uR2YYKZSw4GQVKNfZQCafjkqhKYTBsTE3NY/uYi2Q4MP5KTkw9QGB3VEMv6G/YioqFLly5lazQavfytxobnUW+PWTGisIyNPEL3QYLB4PPIyMi4EydO7JUBbTIZ0RDYOFPkE8t/OdHczCK6Y/qdzP8BfUTW8Tj/uQndvT1F5vOzVvTLz1PwX4cQbt++fekURsNpSNLIw16v1z/HLsRRgecsSnovm8nxs5bvUe+NN1Bz47fkfBaAXj2aA2BWEsM/3hhFX1/5Fe3NTEAfvn8NXTO+tSH68IiNjU2Qw/AmCzg2XCQp+YyhJAu9c+pl9GJ+KmhiEt38bhjpoyJQRtYudA60k3dwD6o4mouKjmSiolcy0ArRqnXz3rT+knwFEShhNKLNlmmFP7Kf8XxuehHpj0QQmLdPGch/ioYyCSAe57pMaHnJgcprctDdwUkRjKi8CUTWhipvbm7uvlJo3zFNoHJDOznPeGEXqn+9EBUf+AQZXvqU+BEG/KCpHz2flYh+ALO9++ZX5L/Mj3gfevjw4ZRoP+PzD/b4HadPn844c+aMkb0F1DqIz9byzBvquXytvr6+7vr16+Ow9CfN2njjdfFAWpo9o2FnNmm12kQMw24gcvSnhbHb7Y+huHsNlhapLNHSxK3idlq287qhhrkKlSByOBzIZrPhGyCn04ncbjfRGAMV5ZlQxvDw8E+yYi1Q3qpleYjUQlNTU5aysrJqgNBhIAwGVSDCkFj48BVFULA1eCl7XV3dx1CKYK3YqKnY7u9Ti2royclJ76FDh1YhxefgsoFpCIOtra0RuGBQwYbRaLzc1dVlpjA2ZiqmKbWsDAmEYU9Pz8Tg4OCNoqKixNTU1BQostDq6iqBcrlcRBiYfEff1KBR+OnpabPBYOikWlnhtOOWm0zUffpnZ2ednZ2dJtCYMTs7+xkA2x0eHk6gsMYwFPYr/EC1Wo2LMEWzWa1WC1QRZ8FUVgpj42ohD3umWqHjRFxf5RkZGVkCNQ9CcTWQn5+flpSUtBOiMKAt7Fek/FSAmpmZMVdVVZ0dGxv7g4PhteMVlbBIofv0sh4Lbmhtb2+/Cbv1eFpaWmJCQsJODMO0hGGgUghAAay9v7//i5KSki9lmmG+4+Jg/MHaIH6f0dCkqaNFFc5VkViam5v319TUNEDdvRubEGsNYHGqsAwMDFxta2u7DdpdpA+3c+LgWiHfVkCiFnpDw0iLqwgqO6BVKoPo00K6WIDsOzE6OrpE395FzeLgxMn5jVe0dYTa26s5jfFg4VR0nAuwNtrFda1rgmToD6VzVWq3eTPyYAxOwwH5gvT2PiWY7X4fUgJTywp1fivyyL6E+Lb6XvQ0X9AkBeeXZED+p/k+9LcAAwAXm3hBLzoZPAAAAABJRU5ErkJggg==
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/--
diff --git a/test/fixture/http/encoding/binaryfile.tar.gz.http b/test/fixture/http/encoding/binaryfile.tar.gz.http
new file mode 100644
index 0000000..4f4fadb
--- /dev/null
+++ b/test/fixture/http/encoding/binaryfile.tar.gz.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Length: 676
+
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Disposition: form-data; name="file"; filename="binaryfile.tar.gz"
+Content-Type: application/x-gzip
+Content-Transfer-Encoding: base64
+
+H4sIAGiNIU8AA+3R0W6CMBQGYK59iobLZantRDG73osUOGqnFNJWM2N897UghG1ZdmWWLf93U/jP4bRAq8q92hJ/dY1J7kQEqyyLq8yXYrp2ltkqkTKXYiEykYc++ZTLVcLEvQ40dXReWcYSV1pdnL/v+6n+R11mjKVG1ZQ+s3TT2FpXqjhQ+hjzE1mnGxNLkgu+7tOKWjIVmVKTC6XL9ZaeXj4VQhwKWzL+cI4zwgQuuhkh3mhTad/Hkssh3im3027X54JnQ360R/M19OT8kC7SEN7Ooi2VvrEfznHQRWzl83gxttZKmzGehzPRW/+W8X+3fvL8sFet9sS6m3EIma02071MU3Uf9KHrmV1/+y8DAAAAAAAAAAAAAAAAAAAAAMB/9A6txIuJACgAAA==
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/--
diff --git a/test/fixture/http/encoding/blank.gif.http b/test/fixture/http/encoding/blank.gif.http
new file mode 100644
index 0000000..7426f5b
--- /dev/null
+++ b/test/fixture/http/encoding/blank.gif.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Length: 323
+
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Disposition: form-data; name="file"; filename="blank.gif"
+Content-Type: image/gif
+Content-Transfer-Encoding: base64
+
+R0lGODlhAQABAJH/AP///wAAAMDAwAAAACH5BAEAAAIALAAAAAABAAEAAAICVAEAOw==
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/--
diff --git a/test/fixture/http/encoding/menu_seperator.png.http b/test/fixture/http/encoding/menu_seperator.png.http
new file mode 100644
index 0000000..d08fd37
--- /dev/null
+++ b/test/fixture/http/encoding/menu_seperator.png.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Length: 1509
+
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Disposition: form-data; name="image"; filename="menu_separator.png"
+Content-Type: image/png
+Content-Transfer-Encoding: base64
+
+iVBORw0KGgoAAAANSUhEUgAAAAIAAAAYCAIAAABfmbuOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDcxODNBNzJERDcyMTFFMUFBOEVFNDQzOTA0MDJDMjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDcxODNBNzNERDcyMTFFMUFBOEVFNDQzOTA0MDJDMjQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowNzE4M0E3MERENzIxMUUxQUE4RUU0NDM5MDQwMkMyNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowNzE4M0E3MURENzIxMUUxQUE4RUU0NDM5MDQwMkMyNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pmvhbb8AAAAXSURBVHjaYnHk9PON8WJiAIPBSwEEGAAPrgG+VozFWgAAAABJRU5ErkJggg==
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/--
diff --git a/test/fixture/http/encoding/plain.txt.http b/test/fixture/http/encoding/plain.txt.http
new file mode 100644
index 0000000..5e85ad6
--- /dev/null
+++ b/test/fixture/http/encoding/plain.txt.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 221
+
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="file"; filename="plain.txt"
+Content-Type: text/plain
+Content-Transfer-Encoding: 7bit
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ--
diff --git a/test/fixture/http/misc/empty-multipart.http b/test/fixture/http/misc/empty-multipart.http
new file mode 100644
index 0000000..81c6125
--- /dev/null
+++ b/test/fixture/http/misc/empty-multipart.http
@@ -0,0 +1,5 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 0
+
diff --git a/test/fixture/http/misc/empty-multipart2.http b/test/fixture/http/misc/empty-multipart2.http
new file mode 100644
index 0000000..eda6528
--- /dev/null
+++ b/test/fixture/http/misc/empty-multipart2.http
@@ -0,0 +1,6 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 31
+
+------TLV0SrKD4z1TRxRhAPUvZ--
diff --git a/test/fixture/http/misc/empty-urlencoded.http b/test/fixture/http/misc/empty-urlencoded.http
new file mode 100644
index 0000000..bb197d3
--- /dev/null
+++ b/test/fixture/http/misc/empty-urlencoded.http
@@ -0,0 +1,5 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Length: 0
+Content-Type: application/x-www-form-urlencoded
+
diff --git a/test/fixture/http/misc/empty.http b/test/fixture/http/misc/empty.http
new file mode 100644
index 0000000..4c4cee5
--- /dev/null
+++ b/test/fixture/http/misc/empty.http
@@ -0,0 +1,4 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Length: 0
+
diff --git a/test/fixture/http/misc/minimal.http b/test/fixture/http/misc/minimal.http
new file mode 100644
index 0000000..594cdd3
--- /dev/null
+++ b/test/fixture/http/misc/minimal.http
@@ -0,0 +1,3 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+
diff --git a/test/fixture/http/no-filename/filename-name.http b/test/fixture/http/no-filename/filename-name.http
new file mode 100644
index 0000000..43672a3
--- /dev/null
+++ b/test/fixture/http/no-filename/filename-name.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Length: 1000
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Disposition: form-data; filename="plain.txt"; name="upload"
+Content-Type: text/plain
+
+I am a plain text file
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG--
+
diff --git a/test/fixture/http/no-filename/generic.http b/test/fixture/http/no-filename/generic.http
new file mode 100644
index 0000000..e0dee27
--- /dev/null
+++ b/test/fixture/http/no-filename/generic.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Length: 1000
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Disposition: form-data; name="upload"; filename=""
+Content-Type: text/plain
+
+I am a plain text file
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG--
+
diff --git a/test/fixture/http/preamble/crlf.http b/test/fixture/http/preamble/crlf.http
new file mode 100644
index 0000000..1d5f709
--- /dev/null
+++ b/test/fixture/http/preamble/crlf.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 184
+
+
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="upload"; filename="plain.txt"
+Content-Type: text/plain
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ--
diff --git a/test/fixture/http/preamble/preamble.http b/test/fixture/http/preamble/preamble.http
new file mode 100644
index 0000000..d14d433
--- /dev/null
+++ b/test/fixture/http/preamble/preamble.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 226
+
+This is a preamble which should be ignored
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="upload"; filename="plain.txt"
+Content-Type: text/plain
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ--
diff --git a/test/fixture/http/special-chars-in-filename/osx-chrome-13.http b/test/fixture/http/special-chars-in-filename/osx-chrome-13.http
new file mode 100644
index 0000000..4ef3917
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/osx-chrome-13.http
@@ -0,0 +1,26 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Connection: keep-alive
+Referer: http://localhost:8080/
+Content-Length: 383
+Cache-Control: max-age=0
+Origin: http://localhost:8080
+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Encoding: gzip,deflate,sdch
+Accept-Language: en-US,en;q=0.8
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
+Cookie: jqCookieJar_tablesorter=%7B%22showListTable%22%3A%5B%5B5%2C1%5D%2C%5B1%2C0%5D%5D%7D
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Disposition: form-data; name="title"
+
+Weird filename
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Disposition: form-data; name="upload"; filename=": \ ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+I am a text file with a funky name!
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG--
diff --git a/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http b/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http
new file mode 100644
index 0000000..bf49f85
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http
@@ -0,0 +1,24 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.22) Gecko/20110902 Firefox/3.6.22
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Language: en-us,en;q=0.5
+Accept-Encoding: gzip,deflate
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
+Keep-Alive: 115
+Connection: keep-alive
+Referer: http://localhost:8080/
+Content-Type: multipart/form-data; boundary=---------------------------9849436581144108930470211272
+Content-Length: 438
+
+-----------------------------9849436581144108930470211272
+Content-Disposition: form-data; name="title"
+
+Weird filename
+-----------------------------9849436581144108930470211272
+Content-Disposition: form-data; name="upload"; filename=": \ ? % * | " < > . &#9731; ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+I am a text file with a funky name!
+
+-----------------------------9849436581144108930470211272--
diff --git a/test/fixture/http/special-chars-in-filename/osx-safari-5.http b/test/fixture/http/special-chars-in-filename/osx-safari-5.http
new file mode 100644
index 0000000..ff158a4
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/osx-safari-5.http
@@ -0,0 +1,23 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Origin: http://localhost:8080
+Content-Length: 383
+User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryQJZ1gvhvdgfisJPJ
+Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
+Referer: http://localhost:8080/
+Accept-Language: en-us
+Accept-Encoding: gzip, deflate
+Connection: keep-alive
+
+------WebKitFormBoundaryQJZ1gvhvdgfisJPJ
+Content-Disposition: form-data; name="title"
+
+Weird filename
+------WebKitFormBoundaryQJZ1gvhvdgfisJPJ
+Content-Disposition: form-data; name="upload"; filename=": \ ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+I am a text file with a funky name!
+
+------WebKitFormBoundaryQJZ1gvhvdgfisJPJ--
diff --git a/test/fixture/http/special-chars-in-filename/xp-chrome-12.http b/test/fixture/http/special-chars-in-filename/xp-chrome-12.http
new file mode 100644
index 0000000..f0fc533
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/xp-chrome-12.http
@@ -0,0 +1,24 @@
+POST /upload HTTP/1.1
+Host: 192.168.56.1:8080
+Connection: keep-alive
+Referer: http://192.168.56.1:8080/
+Content-Length: 344
+Cache-Control: max-age=0
+Origin: http://192.168.56.1:8080
+User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryEvqBNplR3ByrwQPa
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Encoding: gzip,deflate,sdch
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
+
+------WebKitFormBoundaryEvqBNplR3ByrwQPa
+Content-Disposition: form-data; name="title"
+
+Weird filename
+------WebKitFormBoundaryEvqBNplR3ByrwQPa
+Content-Disposition: form-data; name="upload"; filename=" ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+
+------WebKitFormBoundaryEvqBNplR3ByrwQPa--
diff --git a/test/fixture/http/special-chars-in-filename/xp-ie-7.http b/test/fixture/http/special-chars-in-filename/xp-ie-7.http
new file mode 100644
index 0000000..2e2c61c
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/xp-ie-7.http
@@ -0,0 +1,22 @@
+POST /upload HTTP/1.1
+Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */*
+Referer: http://192.168.56.1:8080/
+Accept-Language: de
+User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
+Content-Type: multipart/form-data; boundary=---------------------------7db1fe232017c
+Accept-Encoding: gzip, deflate
+Host: 192.168.56.1:8080
+Content-Length: 368
+Connection: Keep-Alive
+Cache-Control: no-cache
+
+-----------------------------7db1fe232017c
+Content-Disposition: form-data; name="title"
+
+Weird filename
+-----------------------------7db1fe232017c
+Content-Disposition: form-data; name="upload"; filename=" ? % * | " < > . &#9731; ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: application/octet-stream
+
+
+-----------------------------7db1fe232017c--
diff --git a/test/fixture/http/special-chars-in-filename/xp-ie-8.http b/test/fixture/http/special-chars-in-filename/xp-ie-8.http
new file mode 100644
index 0000000..e2b94fa
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/xp-ie-8.http
@@ -0,0 +1,22 @@
+POST /upload HTTP/1.1
+Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */*
+Referer: http://192.168.56.1:8080/
+Accept-Language: de
+User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
+Content-Type: multipart/form-data; boundary=---------------------------7db3a8372017c
+Accept-Encoding: gzip, deflate
+Host: 192.168.56.1:8080
+Content-Length: 368
+Connection: Keep-Alive
+Cache-Control: no-cache
+
+-----------------------------7db3a8372017c
+Content-Disposition: form-data; name="title"
+
+Weird filename
+-----------------------------7db3a8372017c
+Content-Disposition: form-data; name="upload"; filename=" ? % * | " < > . &#9731; ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: application/octet-stream
+
+
+-----------------------------7db3a8372017c--
diff --git a/test/fixture/http/special-chars-in-filename/xp-safari-5.http b/test/fixture/http/special-chars-in-filename/xp-safari-5.http
new file mode 100644
index 0000000..6379ac0
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/xp-safari-5.http
@@ -0,0 +1,22 @@
+POST /upload HTTP/1.1
+Host: 192.168.56.1:8080
+Referer: http://192.168.56.1:8080/
+Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
+Accept-Language: en-US
+Origin: http://192.168.56.1:8080
+User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4
+Accept-Encoding: gzip, deflate
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykmaWSUbu697WN9TM
+Content-Length: 344
+Connection: keep-alive
+
+------WebKitFormBoundarykmaWSUbu697WN9TM
+Content-Disposition: form-data; name="title"
+
+Weird filename
+------WebKitFormBoundarykmaWSUbu697WN9TM
+Content-Disposition: form-data; name="upload"; filename=" ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+
+------WebKitFormBoundarykmaWSUbu697WN9TM--
diff --git a/test/fixture/http/workarounds/missing-hyphens1.http b/test/fixture/http/workarounds/missing-hyphens1.http
new file mode 100644
index 0000000..2826890
--- /dev/null
+++ b/test/fixture/http/workarounds/missing-hyphens1.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 178
+
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="upload"; filename="plain.txt"
+Content-Type: text/plain
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ
diff --git a/test/fixture/http/workarounds/missing-hyphens2.http b/test/fixture/http/workarounds/missing-hyphens2.http
new file mode 100644
index 0000000..8e18194
--- /dev/null
+++ b/test/fixture/http/workarounds/missing-hyphens2.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 180
+
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="upload"; filename="plain.txt"
+Content-Type: text/plain
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ
diff --git a/test/fixture/js/encoding.js b/test/fixture/js/encoding.js
index 83dfb15..fc22026 100644
--- a/test/fixture/js/encoding.js
+++ b/test/fixture/js/encoding.js
@@ -1,19 +1,24 @@
 module.exports['menu_seperator.png.http'] = [
-  {type: 'file', name: 'image', filename: 'menu_separator.png', fixture: 'menu_separator.png'}
+  {type: 'file', name: 'image', filename: 'menu_separator.png', fixture: 'menu_separator.png',
+  sha1: 'c845ca3ea794be298f2a1b79769b71939eaf4e54'}
 ];
 
 module.exports['beta-sticker-1.png.http'] = [
-  {type: 'file', name: 'sticker', filename: 'beta-sticker-1.png', fixture: 'beta-sticker-1.png'}
+  {type: 'file', name: 'sticker', filename: 'beta-sticker-1.png', fixture: 'beta-sticker-1.png',
+  sha1: '6abbcffd12b4ada5a6a084fe9e4584f846331bc4'}
 ];
 
 module.exports['blank.gif.http'] = [
-  {type: 'file', name: 'file', filename: 'blank.gif', fixture: 'blank.gif'}
+  {type: 'file', name: 'file', filename: 'blank.gif', fixture: 'blank.gif',
+  sha1: 'a1fdee122b95748d81cee426d717c05b5174fe96'}
 ];
 
 module.exports['binaryfile.tar.gz.http'] = [
-  {type: 'file', name: 'file', filename: 'binaryfile.tar.gz', fixture: 'binaryfile.tar.gz'}
+  {type: 'file', name: 'file', filename: 'binaryfile.tar.gz', fixture: 'binaryfile.tar.gz',
+  sha1: 'cfabe13b348e5e69287d677860880c52a69d2155'}
 ];
 
 module.exports['plain.txt.http'] = [
-  {type: 'file', name: 'file', filename: 'plain.txt', fixture: 'plain.txt'}
+  {type: 'file', name: 'file', filename: 'plain.txt', fixture: 'plain.txt',
+  sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}
 ];
diff --git a/test/fixture/js/misc.js b/test/fixture/js/misc.js
index 3e27472..1ae9fb9 100644
--- a/test/fixture/js/misc.js
+++ b/test/fixture/js/misc.js
@@ -2,4 +2,6 @@ module.exports = {
   'empty.http': [],
   'empty-urlencoded.http': [],
   'empty-multipart.http': [],
+  'empty-multipart2.http': [],
+  'minimal.http': [],
 };
diff --git a/test/fixture/js/no-filename.js b/test/fixture/js/no-filename.js
index c36e792..f03b4f0 100644
--- a/test/fixture/js/no-filename.js
+++ b/test/fixture/js/no-filename.js
@@ -1,7 +1,9 @@
 module.exports['generic.http'] = [
-  {type: 'file', name: 'upload', filename: '', fixture: 'plain.txt'},
+  {type: 'file', name: 'upload', filename: '', fixture: 'plain.txt',
+  sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
 ];
 
 module.exports['filename-name.http'] = [
-  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+  sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
 ];
diff --git a/test/fixture/js/preamble.js b/test/fixture/js/preamble.js
index da569b2..d2e4cfd 100644
--- a/test/fixture/js/preamble.js
+++ b/test/fixture/js/preamble.js
@@ -1,7 +1,9 @@
 module.exports['crlf.http'] = [
-  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+  sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
 ];
 
 module.exports['preamble.http'] = [
-  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+  sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
 ];
diff --git a/test/fixture/js/special-chars-in-filename.js b/test/fixture/js/special-chars-in-filename.js
index eb76fdc..f5eccda 100644
--- a/test/fixture/js/special-chars-in-filename.js
+++ b/test/fixture/js/special-chars-in-filename.js
@@ -5,7 +5,7 @@ function expect(filename) {
     {type: 'field', name: 'title', value: 'Weird filename'},
     {type: 'file', name: 'upload', filename: filename, fixture: properFilename},
   ];
-};
+}
 
 var webkit = " ? % * | \" < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
 var ffOrIe = " ? % * | \" < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
diff --git a/test/fixture/js/workarounds.js b/test/fixture/js/workarounds.js
index d336505..e59c5b2 100644
--- a/test/fixture/js/workarounds.js
+++ b/test/fixture/js/workarounds.js
@@ -1,6 +1,8 @@
 module.exports['missing-hyphens1.http'] = [
-  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+  sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
 ];
 module.exports['missing-hyphens2.http'] = [
-  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+  {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+  sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
 ];
diff --git a/test/fixture/multi_video.upload b/test/fixture/multi_video.upload
new file mode 100644
index 0000000..9c82ba3
Binary files /dev/null and b/test/fixture/multi_video.upload differ
diff --git a/test/fixture/multipart.js b/test/fixture/multipart.js
index a476169..aa354e7 100644
--- a/test/fixture/multipart.js
+++ b/test/fixture/multipart.js
@@ -1,4 +1,4 @@
-exports['rfc1867'] =
+exports.rfc1867 =
   { boundary: 'AaB03x',
     raw:
       '--AaB03x\r\n'+
@@ -54,7 +54,7 @@ exports['noTrailing\r\n'] =
     ]
   };
 
-exports['emptyHeader'] =
+exports.emptyHeader =
   { boundary: 'AaB03x',
     raw:
       '--AaB03x\r\n'+
diff --git a/test/integration/test-fixtures.js b/test/integration/test-fixtures.js
index eb32fd8..6c03194 100644
--- a/test/integration/test-fixtures.js
+++ b/test/integration/test-fixtures.js
@@ -36,7 +36,7 @@ function testNext(fixtures) {
   if (!fixture) return server.close();
 
   var name    = fixture.name;
-  var fixture = fixture.fixture;
+  fixture = fixture.fixture;
 
   uploadFixture(name, function(err, parts) {
     if (err) throw err;
@@ -47,19 +47,21 @@ function testNext(fixtures) {
       assert.equal(parsedPart.name, expectedPart.name);
 
       if (parsedPart.type === 'file') {
-        var filename = parsedPart.value.name;
-        assert.equal(filename, expectedPart.filename);
+        var file = parsedPart.value;
+        assert.equal(file.name, expectedPart.filename);
+        if(expectedPart.sha1) assert.equal(file.hash, expectedPart.sha1);
       }
     });
 
     testNext(fixtures);
   });
-};
+}
 
 function uploadFixture(name, cb) {
   server.once('request', function(req, res) {
     var form = new formidable.IncomingForm();
     form.uploadDir = common.dir.tmp;
+    form.hash = "sha1";
     form.parse(req);
 
     function callback() {
diff --git a/test/legacy/integration/test-multipart-parser.js b/test/legacy/integration/test-multipart-parser.js
index 75232aa..45047fe 100644
--- a/test/legacy/integration/test-multipart-parser.js
+++ b/test/legacy/integration/test-multipart-parser.js
@@ -33,7 +33,7 @@ Object.keys(fixtures).forEach(function(name) {
 
   parser.onHeaderValue = function(b, start, end) {
     headerValue += b.toString('ascii', start, end);
-  }
+  };
 
   parser.onHeaderEnd = function() {
     part.headers[headerField] = headerValue;
@@ -44,13 +44,13 @@ Object.keys(fixtures).forEach(function(name) {
   parser.onPartData = function(b, start, end) {
     var str = b.toString('ascii', start, end);
     part.data += b.slice(start, end);
-  }
+  };
 
   parser.onEnd = function() {
     endCalled = true;
-  }
+  };
 
-  buffer.write(fixture.raw, 'binary', 0);
+  buffer.write(fixture.raw, 0, undefined, 'binary');
 
   while (offset < buffer.length) {
     if (offset + CHUNK_LENGTH < buffer.length) {
diff --git a/test/legacy/simple/test-incoming-form.js b/test/legacy/simple/test-incoming-form.js
index d79a8e2..ddb1325 100644
--- a/test/legacy/simple/test-incoming-form.js
+++ b/test/legacy/simple/test-incoming-form.js
@@ -38,7 +38,7 @@ test(function constructor() {
   assert.strictEqual(form.encoding, 'utf-8');
   assert.strictEqual(form.bytesReceived, null);
   assert.strictEqual(form.bytesExpected, null);
-  assert.strictEqual(form.maxFieldsSize, 2 * 1024 * 1024);
+  assert.strictEqual(form.maxFieldsSize, 20 * 1024 * 1024);
   assert.strictEqual(form._parser, null);
   assert.strictEqual(form._flushing, 0);
   assert.strictEqual(form._fieldsSize, 0);
@@ -62,17 +62,17 @@ test(function parse() {
   var REQ = {headers: {}}
     , emit = {};
 
-  var events = ['error', 'aborted', 'data', 'end'];
-  gently.expect(REQ, 'on', events.length, function(event, fn) {
-    assert.equal(event, events.shift());
-    emit[event] = fn;
-    return this;
-  });
-
   gently.expect(form, 'writeHeaders', function(headers) {
     assert.strictEqual(headers, REQ.headers);
   });
 
+  var EVENTS = ['error', 'aborted', 'data', 'end'];
+  gently.expect(REQ, 'on', EVENTS.length, function(event, fn) {
+    assert.equal(event, EVENTS.shift());
+    emit[event] = fn;
+    return this;
+  });
+
   form.parse(REQ);
 
   (function testPause() {
@@ -196,10 +196,6 @@ test(function parse() {
         REQ = {headers: {}},
         parseCalled = 0;
 
-    gently.expect(REQ, 'on', 4, function() {
-      return this;
-    });
-
     gently.expect(form, 'on', 4, function(event, fn) {
       if (event == 'field') {
         fn('field1', 'foo');
@@ -219,15 +215,17 @@ test(function parse() {
       return this;
     });
 
+    gently.expect(form, 'writeHeaders');
+
+    gently.expect(REQ, 'on', 4, function() {
+      return this;
+    });
+
     var parseCbOk = function (err, fields, files) {
       assert.deepEqual(fields, {field1: 'bar', field2: 'nice'});
       assert.deepEqual(files, {file1: '2', file2: '3'});
     };
-    gently.expect(form, 'writeHeaders');
     form.parse(REQ, parseCbOk);
-    gently.expect(REQ, 'on', 4, function() {
-      return this;
-    });
 
     var ERR = new Error('test');
     gently.expect(form, 'on', 3, function(event, fn) {
@@ -239,6 +237,9 @@ test(function parse() {
         fn(ERR);
         gently.expect(form, 'on');
         gently.expect(form, 'writeHeaders');
+        gently.expect(REQ, 'on', 4, function() {
+          return this;
+        });
       }
       return this;
     });
@@ -248,6 +249,25 @@ test(function parse() {
       assert.deepEqual(fields, {foo: 'bar'});
     });
   })();
+
+  (function testWriteOrder() {
+    gently.expect(EventEmitterStub, 'call');
+    var form    = new IncomingForm();
+    var REQ     = new events.EventEmitter();
+    var BUF     = {};
+    var DATACB  = null;
+
+    REQ.on('newListener', function(event, fn) {
+      if ('data' === event) fn(BUF);
+    });
+
+    gently.expect(form, 'writeHeaders');
+    gently.expect(form, 'write', function(buf) {
+      assert.strictEqual(buf, BUF);
+    });
+
+    form.parse(REQ);
+  })();
 });
 
 test(function pause() {
@@ -311,7 +331,7 @@ test(function write() {
     delete form._parser;
 
     gently.expect(form, '_error', function(err) {
-      assert.ok(err.message.match(/unintialized parser/i));
+      assert.ok(err.message.match(/uninitialized parser/i));
     });
     form.write(BUFFER);
   })();
@@ -378,9 +398,12 @@ test(function parseContentLength() {
   var HEADERS = {};
 
   form.headers = {};
+  gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
+    assert.equal(event, 'progress');
+    assert.equal(bytesReceived, 0);
+    assert.equal(bytesExpected, 0);
+  });
   form._parseContentLength();
-  assert.strictEqual(form.bytesReceived, null);
-  assert.strictEqual(form.bytesExpected, null);
 
   form.headers['content-length'] = '8';
   gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
@@ -545,7 +568,6 @@ test(function _initUrlencoded() {
 test(function _error() {
   var ERR = new Error('bla');
 
-  gently.expect(form, 'pause');
   gently.expect(form, 'emit', function(event, err) {
     assert.equal(event, 'error');
     assert.strictEqual(err, ERR);
diff --git a/test/legacy/simple/test-multipart-parser.js b/test/legacy/simple/test-multipart-parser.js
index bf2cd5e..c732d32 100644
--- a/test/legacy/simple/test-multipart-parser.js
+++ b/test/legacy/simple/test-multipart-parser.js
@@ -34,7 +34,7 @@ test(function parserError() {
       buffer = new Buffer(5);
 
   parser.initWithBoundary(boundary);
-  buffer.write('--ad', 'ascii', 0);
+  buffer.write('--ad', 0);
   assert.equal(parser.write(buffer), 5);
 });
 
diff --git a/test/legacy/system/test-multi-video-upload.js b/test/legacy/system/test-multi-video-upload.js
index a52db6a..b35ffd6 100644
--- a/test/legacy/system/test-multi-video-upload.js
+++ b/test/legacy/system/test-multi-video-upload.js
@@ -41,12 +41,12 @@ server.on('request', function(req, res) {
       assert.ok(uploads['shortest_video.flv']);
       assert.ok(uploads['shortest_video.flv'].ended);
       assert.ok(uploads['shortest_video.flv'].progress.length > 3);
-      assert.equal(uploads['shortest_video.flv'].file.hash, 'da39a3ee5e6b4b0d3255bfef95601890afd80709');
+      assert.equal(uploads['shortest_video.flv'].file.hash, 'd6a17616c7143d1b1438ceeef6836d1a09186b3a');
       assert.equal(uploads['shortest_video.flv'].progress.slice(-1), uploads['shortest_video.flv'].file.size);
       assert.ok(uploads['shortest_video.mp4']);
       assert.ok(uploads['shortest_video.mp4'].ended);
       assert.ok(uploads['shortest_video.mp4'].progress.length > 3);
-      assert.equal(uploads['shortest_video.mp4'].file.hash, 'da39a3ee5e6b4b0d3255bfef95601890afd80709');
+      assert.equal(uploads['shortest_video.mp4'].file.hash, '937dfd4db263f4887ceae19341dcc8d63bcd557f');
 
       server.close();
       res.writeHead(200);
diff --git a/test/run.js b/test/run.js
index 02d6d5c..887fab3 100755
--- a/test/run.js
+++ b/test/run.js
@@ -1 +1 @@
-require('urun')(__dirname)
+require('urun')(__dirname);
diff --git a/test/standalone/test-issue-46.js b/test/standalone/test-issue-46.js
index 1939328..519bf35 100644
--- a/test/standalone/test-issue-46.js
+++ b/test/standalone/test-issue-46.js
@@ -38,7 +38,7 @@ var server = http.createServer(function(req, res) {
 
   var parts  = [
     {'Content-Disposition': 'form-data; name="foo"', 'body': 'bar'}
-  ]
+  ];
 
   var req = request({method: 'POST', url: url, multipart: parts}, function(e, res, body) {
     var obj = JSON.parse(body);
diff --git a/test/standalone/test-keep-alive-error.js b/test/standalone/test-keep-alive-error.js
new file mode 100644
index 0000000..e0513cc
--- /dev/null
+++ b/test/standalone/test-keep-alive-error.js
@@ -0,0 +1,53 @@
+var assert = require('assert');
+var http = require('http');
+var net = require('net');
+var formidable = require('../../lib/index');
+
+var ok = 0;
+var errors = 0;
+
+var server = http.createServer(function (req, res) {
+  var form = new formidable.IncomingForm();
+  form.on('error', function (e) {
+    errors += 1;
+    res.writeHead(500);
+    res.end();
+  });
+  form.on('end', function () {
+    ok += 1;
+    res.writeHead(200);
+    res.end();
+  });
+  form.parse(req);
+}).listen(0, 'localhost', function () {
+  var client = net.createConnection(server.address().port);
+
+  // first send malformed post upload
+  client.write('POST /upload-test HTTP/1.1\r\n' +
+        'Host: localhost\r\n' +
+        'Connection: keep-alive\r\n' +
+        'Content-Type: multipart/form-data; boundary=----aaa\r\n' +
+        'Content-Length: 10011\r\n\r\n' +
+        '------aaa\n\r'); // expected \r\n
+
+  setTimeout(function () {
+    var buf = new Buffer(10000);
+    buf.fill('a');
+    client.write(buf);
+
+    // correct post upload
+    client.write('POST /upload-test HTTP/1.1\r\n' +
+        'Host: localhost\r\n' +
+        'Connection: keep-alive\r\n' +
+        'Content-Type: multipart/form-data; boundary=----aaa\r\n' +
+        'Content-Length: 13\r\n\r\n' +
+        '------aaa--\r\n');
+
+    setTimeout(function () {
+      assert(ok == 1);
+      assert(errors == 1);
+      client.end();
+      server.close();
+    }, 100);
+  }, 100);
+});
diff --git a/test/tmp/.empty b/test/tmp/.empty
new file mode 100644
index 0000000..e69de29
diff --git a/test/unit/test-file.js b/test/unit/test-file.js
index fc8f36e..1a5f044 100644
--- a/test/unit/test-file.js
+++ b/test/unit/test-file.js
@@ -4,7 +4,7 @@ var assert       = common.assert;
 var File = common.require('file');
 
 var file;
-var now = new Date;
+var now = new Date();
 test('IncomingForm', {
   before: function() {
     file = new File({
@@ -15,7 +15,7 @@ test('IncomingForm', {
       lastModifiedDate: now,
       filename: 'cat.png',
       mime: 'image/png'
-    })
+    });
   },
 
   '#toJSON()': function() {
@@ -30,4 +30,4 @@ test('IncomingForm', {
     assert.equal(now, obj.mtime);
     assert.equal(len, 8);
   }
-});
\ No newline at end of file
+});
diff --git a/test/unit/test-incoming-form.js b/test/unit/test-incoming-form.js
index fe2ac1c..e1b516d 100644
--- a/test/unit/test-incoming-form.js
+++ b/test/unit/test-incoming-form.js
@@ -47,14 +47,17 @@ test('IncomingForm', {
     var ext = path.extname(form._uploadPath('fine.jpg?foo=bar'));
     assert.equal(ext, '.jpg');
 
-    var ext = path.extname(form._uploadPath('fine?foo=bar'));
+    ext = path.extname(form._uploadPath('fine?foo=bar'));
     assert.equal(ext, '');
 
-    var ext = path.extname(form._uploadPath('super.cr2+dsad'));
+    ext = path.extname(form._uploadPath('super.cr2+dsad'));
     assert.equal(ext, '.cr2');
 
-    var ext = path.extname(form._uploadPath('super.bar'));
+    ext = path.extname(form._uploadPath('super.bar'));
     assert.equal(ext, '.bar');
+
+    ext = path.extname(form._uploadPath('file.aAa'));
+    assert.equal(ext, '.aAa');
   },
 });
 

Reply to: