library Buffer {
  struct buffer {
    bytes buf;
    uint capacity;
  }

  function init(buffer memory buf, uint _capacity) internal pure {
    uint capacity = _capacity;
    if(capacity % 32 != 0) capacity += 32 - (capacity % 32);
    // Allocate space for the buffer data
    buf.capacity = capacity;
    assembly {
      let ptr := mload(0x40)
      mstore(buf, ptr)
      mstore(ptr, 0)
      mstore(0x40, add(ptr, capacity))
    }
  }

  function resize(buffer memory buf, uint capacity) private pure {
    bytes memory oldbuf = buf.buf;
    init(buf, capacity);
    append(buf, oldbuf);
  }

  function max(uint a, uint b) private pure returns(uint) {
    if(a > b) {
      return a;
    }
    return b;
  }

  /**
  * @dev Appends a byte array to the end of the buffer. Resizes if doing so
  *      would exceed the capacity of the buffer.
    * @param buf The buffer to append to.
      * @param data The data to append.
      * @return The original buffer.
      */
  function append(buffer memory buf, bytes data) internal pure returns(buffer memory) {
    if(data.length + buf.buf.length > buf.capacity) {
      resize(buf, max(buf.capacity, data.length) * 2);
    }

    uint dest;
    uint src;
    uint len = data.length;
    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Length of existing buffer data
      let buflen := mload(bufptr)
      // Start address = buffer address + buffer length + sizeof(buffer length)
      dest := add(add(bufptr, buflen), 32)
      // Update buffer length
      mstore(bufptr, add(buflen, mload(data)))
      src := add(data, 32)
    }

    // Copy word-length chunks while possible
    for(; len >= 32; len -= 32) {
      assembly {
        mstore(dest, mload(src))
      }
      dest += 32;
      src += 32;
    }

    // Copy remaining bytes
    uint mask = 256 ** (32 - len) - 1;
    assembly {
      let srcpart := and(mload(src), not(mask))
      let destpart := and(mload(dest), mask)
      mstore(dest, or(destpart, srcpart))
    }

    return buf;
  }

  /**
  * @dev Appends a byte to the end of the buffer. Resizes if doing so would
  * exceed the capacity of the buffer.
    * @param buf The buffer to append to.
      * @param data The data to append.
      * @return The original buffer.
      */
  function append(buffer memory buf, uint8 data) internal pure {
    if(buf.buf.length + 1 > buf.capacity) {
      resize(buf, buf.capacity * 2);
    }

    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Length of existing buffer data
      let buflen := mload(bufptr)
      // Address = buffer address + buffer length + sizeof(buffer length)
      let dest := add(add(bufptr, buflen), 32)
      mstore8(dest, data)
      // Update buffer length
      mstore(bufptr, add(buflen, 1))
    }
  }

  /**
  * @dev Appends a byte to the end of the buffer. Resizes if doing so would
  * exceed the capacity of the buffer.
    * @param buf The buffer to append to.
      * @param data The data to append.
      * @return The original buffer.
      */
  function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
    if(len + buf.buf.length > buf.capacity) {
      resize(buf, max(buf.capacity, len) * 2);
    }

    uint mask = 256 ** len - 1;
    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Length of existing buffer data
      let buflen := mload(bufptr)
      // Address = buffer address + buffer length + sizeof(buffer length) + len
      let dest := add(add(bufptr, buflen), len)
      mstore(dest, or(and(mload(dest), not(mask)), data))
      // Update buffer length
      mstore(bufptr, add(buflen, len))
    }
    return buf;
  }
}
function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
  if(len + buf.buf.length > buf.capacity) {
    resize(buf, max(buf.capacity, len) * 2);
  }

  uint mask = 256 ** len - 1;
  assembly {
    // Memory address of the buffer data
    let bufptr := mload(buf)
    // Length of existing buffer data
    let buflen := mload(bufptr)
    // Address = buffer address + buffer length + sizeof(buffer length) + len
    let dest := add(add(bufptr, buflen), len)
    mstore(dest, or(and(mload(dest), not(mask)), data))
    // Update buffer length
    mstore(bufptr, add(buflen, len))
  }
  return buf;
}

/**
 * @dev Appends a byte to the end of the buffer. Resizes if doing so would
 * exceed the capacity of the buffer.
 * @param buf The buffer to append to.
 * @param data The data to append.
 * @return The original buffer.
 */