// Path: src/main/java/com/wizzardo/epoll/readable/ReadableByteArray.java
// public class ReadableByteArray extends ReadableData {
//     protected byte[] bytes;
//     protected int offset, length, position;
// 
//     public ReadableByteArray(byte[] bytes) {
//         this(bytes, 0, bytes.length);
//     }
// 
//     public ReadableByteArray(byte[] bytes, int offset, int length) {
//         this.bytes = bytes;
//         this.offset = offset;
//         this.length = length;
//         position = offset;
//     }
// 
//     @Override
//     public int read(ByteBuffer byteBuffer) {
//         int r = Math.min(byteBuffer.remaining(), length + offset - position);
//         byteBuffer.put(bytes, position, r);
//         position += r;
//         return r;
//     }
// 
//     @Override
//     public void unread(int i) {
//         if (i < 0)
//             throw new IllegalArgumentException("can't unread negative value: " + i);
//         if (position - i < offset)
//             throw new IllegalArgumentException("can't unread value bigger than offset (" + offset + "): " + i);
//         position -= i;
//     }
// 
//     @Override
//     public boolean isComplete() {
//         return length == position - offset;
//     }
// 
//     @Override
//     public long complete() {
//         return position - offset;
//     }
// 
//     @Override
//     public long length() {
//         return length;
//     }
// 
//     public long remains() {
//         return length + offset - position;
//     }
// 
//     @Override
//     public String toString() {
//         return new String(bytes, offset, length);
//     }
// }
// 
// Path: src/main/java/com/wizzardo/epoll/readable/ReadableData.java
// public abstract class ReadableData implements Closeable {
// 
//     public ByteBufferWrapper getByteBuffer(ByteBufferProvider bufferProvider) {
//         return bufferProvider.getBuffer();
//     }
// 
//     public void close() throws IOException {
//     }
// 
//     public abstract int read(ByteBuffer byteBuffer);
// 
//     public int read(ByteBufferWrapper wrapper) {
//         return read(wrapper.buffer());
//     }
// 
//     public abstract void unread(int i);
// 
//     public abstract boolean isComplete();
// 
//     public abstract long complete();
// 
//     public abstract long length();
// 
//     public abstract long remains();
// 
//     public boolean hasOwnBuffer() {
//         return false;
//     }
// 
//     public void onComplete() {
//     }
// }


import com.wizzardo.epoll.readable.ReadableByteArray;
import com.wizzardo.epoll.readable.ReadableData;
import com.wizzardo.tools.io.IOTools;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.Deque;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicReference;
                ReadableData readable;
                while ((readable = queue.peek()) != null) {
                    while (!readable.isComplete() && actualWrite(readable, bufferProvider)) {
                    }
                    if (!readable.isComplete())
                        return false;

                    queue.poll();
                    readable.close();
                    readable.onComplete();
                    onWriteData(readable, !queue.isEmpty());
                }
            } catch (Exception e) {
                e.printStackTrace();
                close();
                return false;
            } finally {
                writer.set(null);
            }
        }
        return true;
    }

    protected int write(ByteBufferWrapper wrapper, int off, int len) throws IOException {
        return epoll.write(this, wrapper.address, off, len);
    }

    /*
     * @return true if connection is ready to write data
     */
// Path: src/main/java/com/wizzardo/epoll/readable/ReadableByteArray.java
// public class ReadableByteArray extends ReadableData {
//     protected byte[] bytes;
//     protected int offset, length, position;
// 
//     public ReadableByteArray(byte[] bytes) {
//         this(bytes, 0, bytes.length);
//     }
// 
//     public ReadableByteArray(byte[] bytes, int offset, int length) {
//         this.bytes = bytes;
//         this.offset = offset;
//         this.length = length;
//         position = offset;
//     }
// 
//     @Override
//     public int read(ByteBuffer byteBuffer) {
//         int r = Math.min(byteBuffer.remaining(), length + offset - position);
//         byteBuffer.put(bytes, position, r);
//         position += r;
//         return r;
//     }
// 
//     @Override
//     public void unread(int i) {
//         if (i < 0)
//             throw new IllegalArgumentException("can't unread negative value: " + i);
//         if (position - i < offset)
//             throw new IllegalArgumentException("can't unread value bigger than offset (" + offset + "): " + i);
//         position -= i;
//     }
// 
//     @Override
//     public boolean isComplete() {
//         return length == position - offset;
//     }
// 
//     @Override
//     public long complete() {
//         return position - offset;
//     }
// 
//     @Override
//     public long length() {
//         return length;
//     }
// 
//     public long remains() {
//         return length + offset - position;
//     }
// 
//     @Override
//     public String toString() {
//         return new String(bytes, offset, length);
//     }
// }
// 
// Path: src/main/java/com/wizzardo/epoll/readable/ReadableData.java
// public abstract class ReadableData implements Closeable {
// 
//     public ByteBufferWrapper getByteBuffer(ByteBufferProvider bufferProvider) {
//         return bufferProvider.getBuffer();
//     }
// 
//     public void close() throws IOException {
//     }
// 
//     public abstract int read(ByteBuffer byteBuffer);
// 
//     public int read(ByteBufferWrapper wrapper) {
//         return read(wrapper.buffer());
//     }
// 
//     public abstract void unread(int i);
// 
//     public abstract boolean isComplete();
// 
//     public abstract long complete();
// 
//     public abstract long length();
// 
//     public abstract long remains();
// 
//     public boolean hasOwnBuffer() {
//         return false;
//     }
// 
//     public void onComplete() {
//     }
// }


// Path: src/main/java/com/wizzardo/epoll/Connection.java
import com.wizzardo.epoll.readable.ReadableByteArray;
import com.wizzardo.epoll.readable.ReadableData;
import com.wizzardo.tools.io.IOTools;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.Deque;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicReference;

                ReadableData readable;
                while ((readable = queue.peek()) != null) {
                    while (!readable.isComplete() && actualWrite(readable, bufferProvider)) {
                    }
                    if (!readable.isComplete())
                        return false;

                    queue.poll();
                    readable.close();
                    readable.onComplete();
                    onWriteData(readable, !queue.isEmpty());
                }
            } catch (Exception e) {
                e.printStackTrace();
                close();
                return false;
            } finally {
                writer.set(null);
            }
        }
        return true;
    }

    protected int write(ByteBufferWrapper wrapper, int off, int len) throws IOException {
        return epoll.write(this, wrapper.address, off, len);
    }

    /*
     * @return true if connection is ready to write data
     */
    protected boolean actualWrite(ReadableData readable, ByteBufferProvider bufferProvider) throws IOException {