var fs=require("fs"),util=require("util"),stream=require("stream"),Readable=stream.Readable,Writable=stream.Writable,PassThrough=stream.PassThrough,Pend=require("pend"),EventEmitter=require("events").EventEmitter;function FdSlicer(e,t){t=t||{},EventEmitter.call(this),this.fd=e,this.pend=new Pend,this.pend.max=1,this.refCount=0,this.autoClose=!!t.autoClose}function ReadStream(e,t){t=t||{},Readable.call(this,t),this.context=e,this.context.ref(),this.start=t.start||0,this.endOffset=t.end,this.pos=this.start,this.destroyed=!1}function WriteStream(e,t){t=t||{},Writable.call(this,t),this.context=e,this.context.ref(),this.start=t.start||0,this.endOffset=null==t.end?1/0:+t.end,this.bytesWritten=0,this.pos=this.start,this.destroyed=!1,this.on("finish",this.destroy.bind(this))}function BufferSlicer(e,t){EventEmitter.call(this),t=t||{},this.refCount=0,this.buffer=e,this.maxChunkSize=t.maxChunkSize||Number.MAX_SAFE_INTEGER}function createFromBuffer(e,t){return new BufferSlicer(e,t)}function createFromFd(e,t){return new FdSlicer(e,t)}exports.createFromBuffer=createFromBuffer,exports.createFromFd=createFromFd,exports.BufferSlicer=BufferSlicer,exports.FdSlicer=FdSlicer,util.inherits(FdSlicer,EventEmitter),FdSlicer.prototype.read=function(e,t,r,i,n){var o=this;o.pend.go(function(s){fs.read(o.fd,e,t,r,i,function(e,t,r){s(),n(e,t,r)})})},FdSlicer.prototype.write=function(e,t,r,i,n){var o=this;o.pend.go(function(s){fs.write(o.fd,e,t,r,i,function(e,t,r){s(),n(e,t,r)})})},FdSlicer.prototype.createReadStream=function(e){return new ReadStream(this,e)},FdSlicer.prototype.createWriteStream=function(e){return new WriteStream(this,e)},FdSlicer.prototype.ref=function(){this.refCount+=1},FdSlicer.prototype.unref=function(){var e=this;if(e.refCount-=1,!(e.refCount>0)){if(e.refCount<0)throw new Error("invalid unref");e.autoClose&&fs.close(e.fd,function(t){t?e.emit("error",t):e.emit("close")})}},util.inherits(ReadStream,Readable),ReadStream.prototype._read=function(e){var t=this;if(!t.destroyed){var r=Math.min(t._readableState.highWaterMark,e);if(null!=t.endOffset&&(r=Math.min(r,t.endOffset-t.pos)),r<=0)return t.destroyed=!0,t.push(null),void t.context.unref();t.context.pend.go(function(e){if(t.destroyed)return e();var i=new Buffer(r);fs.read(t.context.fd,i,0,r,t.pos,function(r,n){r?t.destroy(r):0===n?(t.destroyed=!0,t.push(null),t.context.unref()):(t.pos+=n,t.push(i.slice(0,n))),e()})})}},ReadStream.prototype.destroy=function(e){this.destroyed||(e=e||new Error("stream destroyed"),this.destroyed=!0,this.emit("error",e),this.context.unref())},util.inherits(WriteStream,Writable),WriteStream.prototype._write=function(e,t,r){var i=this;if(!i.destroyed){if(i.pos+e.length>i.endOffset){var n=new Error("maximum file length exceeded");return n.code="ETOOBIG",i.destroy(),void r(n)}i.context.pend.go(function(t){if(i.destroyed)return t();fs.write(i.context.fd,e,0,e.length,i.pos,function(e,n){e?(i.destroy(),t(),r(e)):(i.bytesWritten+=n,i.pos+=n,i.emit("progress"),t(),r())})})}},WriteStream.prototype.destroy=function(){this.destroyed||(this.destroyed=!0,this.context.unref())},util.inherits(BufferSlicer,EventEmitter),BufferSlicer.prototype.read=function(e,t,r,i,n){var o=i+r,s=o-this.buffer.length,f=s>0?s:r;this.buffer.copy(e,t,i,o),setImmediate(function(){n(null,f)})},BufferSlicer.prototype.write=function(e,t,r,i,n){e.copy(this.buffer,i,t,t+r),setImmediate(function(){n(null,r,e)})},BufferSlicer.prototype.createReadStream=function(e){var t=new PassThrough(e=e||{});t.destroyed=!1,t.start=e.start||0,t.endOffset=e.end,t.pos=t.endOffset||this.buffer.length;for(var r=this.buffer.slice(t.start,t.pos),i=0;;){var n=i+this.maxChunkSize;if(n>=r.length){i<r.length&&t.write(r.slice(i,r.length));break}t.write(r.slice(i,n)),i=n}return t.end(),t.destroy=function(){t.destroyed=!0},t},BufferSlicer.prototype.createWriteStream=function(e){var t=this,r=new Writable(e=e||{});return r.start=e.start||0,r.endOffset=null==e.end?this.buffer.length:+e.end,r.bytesWritten=0,r.pos=r.start,r.destroyed=!1,r._write=function(e,i,n){if(!r.destroyed){var o=r.pos+e.length;if(o>r.endOffset){var s=new Error("maximum file length exceeded");return s.code="ETOOBIG",r.destroyed=!0,void n(s)}e.copy(t.buffer,r.pos,0,e.length),r.bytesWritten+=e.length,r.pos=o,r.emit("progress"),n()}},r.destroy=function(){r.destroyed=!0},r},BufferSlicer.prototype.ref=function(){this.refCount+=1},BufferSlicer.prototype.unref=function(){if(this.refCount-=1,this.refCount<0)throw new Error("invalid unref")};