var expat = require("node-expat"),
    request = require("request");

function osm2geojson(bbox, outputStream, callback) {
    // Bail if the area is too big
    if ((bbox[2] - bbox[0]) * (bbox[3] - bbox[1]) > 0.25) {
        callback({
            error: "request_area_too_big",
            statusCode: 400,
            message: "The requested area is too large"
        });
        return;
    }
    
    // Setup an xml stream parser
    var parser = new expat.Parser("UTF-8"),
        // Build the API request to OSM
        url = "http://api.openstreetmap.org/api/0.6/map?bbox=" + bbox.join(","),
        // Setup some cruft
        firstFeature = true,
        currentFeature = null,
        nodes = {};
    
    // Listen to parser events -- When a new element starts...
    parser.on("startElement", function (name, attrs) {
        // ...react according to what type of element it is
        switch (name) {
        case "node":
            // Cache the node for later lookup
            nodes[attrs.id] = { uid: attrs.uid, coordinates: [attrs.lon, attrs.lat] };
            break;
        case "way":
            // Begin assembling a new feature
            currentFeature = {
                type: "Feature",
                id: attrs.id,
                properties: { uid: attrs.uid },
                geometry: { type: "", coordinates: [] }
            };
            break;
        case "nd":
            // Lookup the node, assign its coords to the currentFeature
            currentFeature.geometry.coordinates.push(nodes[attrs.ref].coordinates);
            break;
        case "tag":
            // Assign properties to the currentFeature, if it exists. Otherwise these are node tags.
            if (currentFeature) { currentFeature.properties[attrs.k] = attrs.v; }
            break;
        }
    });
    
    // When an element ends...
    parser.on("endElement", function (name) {
        // ...only do anything if its a way
        if (name === "way") {
            // If the last coord is identical to the first, then it is a Polygon...
            var last = currentFeature.geometry.coordinates.length - 1;
            if (currentFeature.geometry.coordinates[0] === currentFeature.geometry.coordinates[last]) {
                // ...and the line needs to be wrapped in another pair of brackets
                currentFeature.geometry.coordinates = [currentFeature.geometry.coordinates];
                currentFeature.geometry.type = "Polygon";
            } else {
            // Otherwise this is a LineString
                currentFeature.geometry.type = "LineString";
            }
            
            // Deal with commas between features -- don't prepend one if this is the first feature
            if (firstFeature) {
                // Start writing a FeatureCollection
                outputStream.write('{"type":"FeatureCollection","features":[');
                firstFeature = false;
            } else { outputStream.write(","); }
            
            // Write the feature to the stream
            outputStream.write(JSON.stringify(currentFeature));
        }
    });
    
    // When we're all finished with the incoming data
    parser.on("end", function () {
        if (!currentFeature) { callback("I didn't get any features from OSM\n"); return; }
        
        // Finish up the FeatureCollection
        outputStream.write("]}\n");
        
        // Callback
        callback();
    });
    
    // When an error is encountered
    parser.on("error", function (err) {
        // Callback with the error
        callback(err);
    });
    
    // Okay, actually make the request and pipe the response into the parser
    request(url).pipe(parser);
}

// Export the function for use elsewhere
module.exports = osm2geojson;
@@ -79,524 +79,129 @@
  osm
-2geojson(bbox, outputStream, callback) %7B%0A    // Bail if the area is too big%0A    if ((bbox%5B2%5D - bbox%5B0%5D) * (bbox%5B3%5D - bbox%5B1%5D) %3E 0.25) %7B%0A        callback(%7B%0A            error: %22request_area_too_big%22,%0A            statusCode: 400,%0A            message: %22The requested area is too large%22%0A        %7D);%0A        return;%0A    %7D%0A    %0A    // Setup an xml stream parser%0A    var parser = new expat.Parser(%22UTF-8%22),%0A        // Build the API request to OSM%0A        url = %22http://api.openstreetmap.org/api/0.6/map?bbox=%22 + bbox.join(%22,
+Stream2Stream(readable, writeable, callback) %7B%0A    // Setup an xml stream parser%0A    var parser = new expat.Parser(%22UTF-8
 %22),%0A
@@ -645,16 +645,23 @@
 nates: %5B
+Number(
 attrs.lo
@@ -661,18 +661,26 @@
 ttrs.lon
+)
 , 
+Number(
 attrs.la
@@ -680,16 +680,17 @@
 ttrs.lat
+)
 %5D %7D;%0A   
@@ -2437,36 +2437,33 @@
             
-outputStream
+writeable
 .write('%7B%22ty
@@ -2561,28 +2561,25 @@
  else %7B 
-outputStream
+writeable
 .write(%22
@@ -2653,36 +2653,33 @@
             
-outputStream
+writeable
 .write(JSON.
@@ -2973,20 +2973,17 @@
     
-outputStream
+writeable
 .wri
@@ -3199,24 +3199,509 @@
    %7D);%0A    %0A
+    readable.pipe(parser);%0A%7D%0A%0Afunction osm2geojson(bbox, outputStream, callback) %7B%0A    // Bail if the area is too big%0A    if ((bbox%5B2%5D - bbox%5B0%5D) * (bbox%5B3%5D - bbox%5B1%5D) %3E 0.25) %7B%0A        callback(%7B%0A            error: %22request_area_too_big%22,%0A            statusCode: 400,%0A            message: %22The requested area is too large%22%0A        %7D);%0A        return;%0A    %7D%0A    %0A    // Build the API request to OSM%0A    var url = %22http://api.openstreetmap.org/api/0.6/map?bbox=%22 + bbox.join(%22,%22);%0A    %0A
     // Okay,
@@ -3773,32 +3773,61 @@
     
-request(url).pipe(parser
+osmStream2Stream(request(url), outputStream, callback
 );%0A%7D

coords have to be numbers, duh