var stream = require('stream'),
    fs     = require('fs');

var stk = {};


function createNullRead(length) {

    var readable = new stream.Readable();
    
    readable._read = function() {
      // nothing
    };

    readable.push(null);
    
    return readable;
}

function createNullWrite() {

    var writable = new stream.Writable();
    
    writable._write = function(chunk, encoding, callback) {
      callback();
    };

    /*
    writable.write = function() {
      return true;
    };
    */
    
    return writable;
}

function createZeroRead(length) {

    var readable = new stream.Readable();
    
    readable._read = function() {
      // nothing
    };
    
    readable.push(new Buffer(length).fill(0));
    readable.push(null);
    
    return readable;
}

var createZeroWrite = createNullWrite;

var createFullRead = createZeroRead;

function createFullWrite() {
    
    var writable = new stream.Writable();

    writable._write = function(chunk, encoding, callback) {
      callback();
    };

    writable.end('');
    
    return writable;
}

function createRandomRead(length) {
    
    var readable = new stream.Readable();

    readable._read = function() {
      // nothing
    };
    
    process.nextTick(function() {
      
      readable.push(null);
    });
    
    return readable;
}

function createRandomWrite() {
    
    var writable = new stream.Writable();
    
    return writable;
}

stk.createNull = function createNull(mode) {
  if(mode === "read") {
    try {
      return fs.createReadStream("/dev/null");
    } catch(e) {
      return createNullRead();
    }
  }
  if(mode === "write") {
    try {
      return fs.createWriteStream("/dev/null");
    } catch(e) {
      return createNullWrite();
    }
  }
  throw new Error("mode must be either 'read or 'write'");
};

stk.createZero = function createZero(mode, length) {
  if(mode === "read") {
    if(!Number(length)) {
      throw new Error("must provide length in bytes");
    }
    try {
      return fs.createReadStream("/dev/zero", {start: 0, end: length-1});
    } catch(e) {
      return createZeroRead(length);
    }
  }
  if(mode === "write") {
    try {
      return fs.createWriteStream("/dev/zero");
    } catch(e) {
      return createZeroWrite();
    }
  }
  throw new Error("mode must be either 'read or 'write'");
};

stk.createFull = function createFull(mode, length) {
  if(mode === "read") {
    if(!Number(length)) {
      throw new Error("must provide length in bytes");
    }
    try {
      return fs.createReadStream("/dev/full", {start: 0, end: length-1});
    } catch(e) {
      return createFullRead(length);
    }
  }
  if(mode === "write") {
    try {
      return fs.createWriteStream("/dev/full");
    } catch(e) {
      return createFullWrite();
    }
  }
  throw new Error("mode must be either 'read or 'write'");
};

stk.createRandom = function createRandom(mode, length) {
  if(mode === "read") {
    if(!Number(length)) {
      throw new Error("must provide length in bytes");
    }
    return fs.createReadStream("/dev/urandom", {start: 0, end: length-1});
  }
  if(mode === "write") {
    return fs.createWriteStream("/dev/urandom");
  }
  throw new Error("mode must be either 'read or 'write'");
};


module.exports = stk;

@@ -25,16 +25,48 @@
 ream'),%0A
+    crypto = require('crypto'),%0A
     fs  
@@ -1256,25 +1256,35 @@
     
-process.nextTick(
+crypto.randomBytes(length, 
 func
@@ -1280,32 +1280,40 @@
 ength, function(
+err, buf
 ) %7B%0A      %0A     
@@ -1302,24 +1302,69 @@
 uf) %7B%0A      
+if (err) throw err;%0A      readable.push(buf);
 %0A      reada
@@ -1491,32 +1491,167 @@
 ritable();%0A    %0A
+    writable._write = function(chunk, encoding, callback) %7B%0A      // for windows, N/A to mixin random data%0A      callback();%0A    %7D;%0A  %0A
     return writa
@@ -3245,24 +3245,36 @@
 es%22);%0A    %7D%0A
+    try %7B%0A  
     return f
@@ -3336,16 +3336,79 @@
 th-1%7D);%0A
+    %7D catch (e) %7B%0A      return createRandomRead(length);%0A    %7D%0A
   %7D%0A  if
@@ -3424,24 +3424,36 @@
  %22write%22) %7B%0A
+    try %7B%0A  
     return f
@@ -3489,16 +3489,73 @@
 ndom%22);%0A
+    %7D catch(e) %7B%0A      return createRandomWrite();%0A    %7D%0A
   %7D%0A  th

support pseudo devices for Windows