| var Stream = require("stream") | 
| var writeMethods = ["write", "end", "destroy"] | 
| var readMethods = ["resume", "pause"] | 
| var readEvents = ["data", "close"] | 
| var slice = Array.prototype.slice | 
|   | 
| module.exports = duplex | 
|   | 
| function forEach (arr, fn) { | 
|     if (arr.forEach) { | 
|         return arr.forEach(fn) | 
|     } | 
|   | 
|     for (var i = 0; i < arr.length; i++) { | 
|         fn(arr[i], i) | 
|     } | 
| } | 
|   | 
| function duplex(writer, reader) { | 
|     var stream = new Stream() | 
|     var ended = false | 
|   | 
|     forEach(writeMethods, proxyWriter) | 
|   | 
|     forEach(readMethods, proxyReader) | 
|   | 
|     forEach(readEvents, proxyStream) | 
|   | 
|     reader.on("end", handleEnd) | 
|   | 
|     writer.on("drain", function() { | 
|       stream.emit("drain") | 
|     }) | 
|   | 
|     writer.on("error", reemit) | 
|     reader.on("error", reemit) | 
|   | 
|     stream.writable = writer.writable | 
|     stream.readable = reader.readable | 
|   | 
|     return stream | 
|   | 
|     function proxyWriter(methodName) { | 
|         stream[methodName] = method | 
|   | 
|         function method() { | 
|             return writer[methodName].apply(writer, arguments) | 
|         } | 
|     } | 
|   | 
|     function proxyReader(methodName) { | 
|         stream[methodName] = method | 
|   | 
|         function method() { | 
|             stream.emit(methodName) | 
|             var func = reader[methodName] | 
|             if (func) { | 
|                 return func.apply(reader, arguments) | 
|             } | 
|             reader.emit(methodName) | 
|         } | 
|     } | 
|   | 
|     function proxyStream(methodName) { | 
|         reader.on(methodName, reemit) | 
|   | 
|         function reemit() { | 
|             var args = slice.call(arguments) | 
|             args.unshift(methodName) | 
|             stream.emit.apply(stream, args) | 
|         } | 
|     } | 
|   | 
|     function handleEnd() { | 
|         if (ended) { | 
|             return | 
|         } | 
|         ended = true | 
|         var args = slice.call(arguments) | 
|         args.unshift("end") | 
|         stream.emit.apply(stream, args) | 
|     } | 
|   | 
|     function reemit(err) { | 
|         stream.emit("error", err) | 
|     } | 
| } |