// Path: src/name/arbitrary/toytcp/WriteBuffer.java
// public class WriteBuffer {
//     private final ArrayList<Byte> buffer = new ArrayList<Byte>();
// 
//     public WriteBuffer() {
//     }
// 
//     public WriteBuffer(int... data) {
//         for (int i = 0 ; i < data.length; i++) {
//             append((byte)data[i]);
//         }
//     }
// 
//     public void append(byte b) {
//         buffer.add(b);
//     }
// 
//     public void append(byte... bs) {
//         for (byte b : bs) {
//             buffer.add(b);
//         }
//     }
// 
//     public void append(Buffer data) {
//         int n = data.length();
//         for (int i = 0; i < n; i++) {
//             append(data.get(i));
//         }
//     }
// 
//     public void appendU16(int value) {
//         buffer.add((byte)(value >> 8));
//         buffer.add((byte)(value & 0xFF));
//     }
// 
//     public void appendU32(int value) {
//         buffer.add((byte)(value >> 24));
//         buffer.add((byte)(value >> 16));
//         buffer.add((byte)(value >> 8));
//         buffer.add((byte)(value & 0xFF));
//     }
// 
//     public int getAppendOffset() {
//         return buffer.size();
//     }
// 
//     public void put(int i, byte value) {
//         buffer.set(i, value);
//     }
// 
//     public void putU8(int i, int value) {
//         put(i, (byte)value);
//     }
// 
//     public void putU16(int i, int value) {
//         put(i, (byte)(value >> 8));
//         put(i + 1, (byte)(value & 0xFF));
//     }
// 
//     public byte[] toByteArray() {
//         int n = buffer.size();
//         byte[] array = new byte[n];
//         for (int i = 0; i < n; i++) {
//             array[i] = buffer.get(i);
//         }
//         return array;
//     }
// 
//     @Override
//     public String toString() {
//         return "WriteBuffer{" +
//                 "buffer=" + buffer +
//                 '}';
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         WriteBuffer that = (WriteBuffer) o;
// 
//         if (!buffer.equals(that.buffer)) return false;
// 
//         return true;
//     }
// 
//     @Override
//     public int hashCode() {
//         return buffer.hashCode();
//     }
// 
//     public interface Listener {
//         void send(WriteBuffer buffer);
//     }
// }


import name.arbitrary.toytcp.WriteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package name.arbitrary.toytcp.ppp.link;


/**
 * Applies byte stuffing.
 */
public class Stuffer implements WriteBuffer.Listener {
    private final static Logger logger = LoggerFactory.getLogger(Stuffer.class);

    private final WriteBuffer.Listener listener;

    private int asyncControlCharacterMap = 0xFFFFFFFF;

    public Stuffer(WriteBuffer.Listener listener) {
        this.listener = listener;
    }

    @Override
    public void send(WriteBuffer buffer) {
        byte[] data = buffer.toByteArray();
        WriteBuffer newBuffer = new WriteBuffer();
        for (byte b : data) {
            if (b == Unstuffer.ESCAPE_CHAR || b == Unframer.FLAG_CHAR || isAsyncControl(b)) {
// Path: src/name/arbitrary/toytcp/WriteBuffer.java
// public class WriteBuffer {
//     private final ArrayList<Byte> buffer = new ArrayList<Byte>();
// 
//     public WriteBuffer() {
//     }
// 
//     public WriteBuffer(int... data) {
//         for (int i = 0 ; i < data.length; i++) {
//             append((byte)data[i]);
//         }
//     }
// 
//     public void append(byte b) {
//         buffer.add(b);
//     }
// 
//     public void append(byte... bs) {
//         for (byte b : bs) {
//             buffer.add(b);
//         }
//     }
// 
//     public void append(Buffer data) {
//         int n = data.length();
//         for (int i = 0; i < n; i++) {
//             append(data.get(i));
//         }
//     }
// 
//     public void appendU16(int value) {
//         buffer.add((byte)(value >> 8));
//         buffer.add((byte)(value & 0xFF));
//     }
// 
//     public void appendU32(int value) {
//         buffer.add((byte)(value >> 24));
//         buffer.add((byte)(value >> 16));
//         buffer.add((byte)(value >> 8));
//         buffer.add((byte)(value & 0xFF));
//     }
// 
//     public int getAppendOffset() {
//         return buffer.size();
//     }
// 
//     public void put(int i, byte value) {
//         buffer.set(i, value);
//     }
// 
//     public void putU8(int i, int value) {
//         put(i, (byte)value);
//     }
// 
//     public void putU16(int i, int value) {
//         put(i, (byte)(value >> 8));
//         put(i + 1, (byte)(value & 0xFF));
//     }
// 
//     public byte[] toByteArray() {
//         int n = buffer.size();
//         byte[] array = new byte[n];
//         for (int i = 0; i < n; i++) {
//             array[i] = buffer.get(i);
//         }
//         return array;
//     }
// 
//     @Override
//     public String toString() {
//         return "WriteBuffer{" +
//                 "buffer=" + buffer +
//                 '}';
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         WriteBuffer that = (WriteBuffer) o;
// 
//         if (!buffer.equals(that.buffer)) return false;
// 
//         return true;
//     }
// 
//     @Override
//     public int hashCode() {
//         return buffer.hashCode();
//     }
// 
//     public interface Listener {
//         void send(WriteBuffer buffer);
//     }
// }


// Path: src/name/arbitrary/toytcp/ppp/link/Stuffer.java
import name.arbitrary.toytcp.WriteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

package name.arbitrary.toytcp.ppp.link;


/**
 * Applies byte stuffing.
 */
public class Stuffer implements WriteBuffer.Listener {
    private final static Logger logger = LoggerFactory.getLogger(Stuffer.class);

    private final WriteBuffer.Listener listener;

    private int asyncControlCharacterMap = 0xFFFFFFFF;

    public Stuffer(WriteBuffer.Listener listener) {
        this.listener = listener;
    }

    @Override
    public void send(WriteBuffer buffer) {
        byte[] data = buffer.toByteArray();
        WriteBuffer newBuffer = new WriteBuffer();
        for (byte b : data) {
            if (b == Unstuffer.ESCAPE_CHAR || b == Unframer.FLAG_CHAR || isAsyncControl(b)) {
                newBuffer.append(Unstuffer.ESCAPE_CHAR);