docs: public static Message read(DataInputStream is) throws IOException {
          final Field start = Field.read(is);
          if (!(start instanceof NumberField)) {
              throw new IOException("Did not find number field reading start of message; got: " + start);
          }
          if (start.getSize() != 4) {
              throw new IOException("Number field to start message must be of size 4, got: " + start);
          }
          if (((NumberField) start).getValue() != MESSAGE_START.getValue()) {
              throw new IOException("Number field had wrong value to start message. Expected: " + MESSAGE_START +
              ", got: " + start);
          }
  
          final Field transaction = Field.read(is);
          if (!(transaction instanceof NumberField)) {
              throw new IOException("Did not find number field reading transaction ID of message; got: " + transaction);
          }
          if (transaction.getSize() != 4) {
              throw new IOException("Transaction number field of message must be of size 4, got: " + transaction);
          }
  
          final Field type = Field.read(is);
          if (!(type instanceof NumberField)) {
              throw new IOException("Did not find number field reading type of message; got: " + type);
          }
          if (type.getSize() != 2) {
              throw new IOException("Type field of message must be of size 2, got: " + type);
          }
  
          final Field argCountField = Field.read(is);
          if (!(argCountField instanceof NumberField)) {
              throw new IOException("Did not find number field reading argument count of message; got: " + argCountField);
          }
          if (argCountField.getSize() != 1) {
              throw new IOException("Argument count field of message must be of size 1, got: " + argCountField);
          }
          final int argCount = (int)((NumberField)argCountField).getValue();
          if (argCount < 0 || argCount > 12) {
              throw new IOException("Illegal argument count while reading message; must be between 0 and 12, got: " +
              argCount);
          }
  
          final Field argTypes = Field.read(is);
          if (!(argTypes instanceof BinaryField)) {
              throw new IOException("Did not find binary field reading argument types of message, got: " + argTypes);
          }
          byte[] argTags = new byte[12];
          ((BinaryField)argTypes).getValue().get(argTags);
  
          Field[] arguments = new Field[argCount];
          Field lastArg = null;
          for (int i = 0; i < argCount; i++) {
              if (argTags[i] == 3 && (lastArg instanceof NumberField) &&
                      ((NumberField) lastArg).getValue() == 0) {
                  arguments [i] = new BinaryField(new byte[0]);  // Do not attempt to read a zero-length binary field
              } else {
                  arguments[i] = Field.read(is);
              }
              lastArg = arguments[i];
              if (lastArg.getArgumentTag() != argTags[i]) {
                  throw new IOException("Found argument of wrong type reading message. Expected tag: " + argTags[i] +
                  " and got: " + arguments[i].getArgumentTag());
              }
          }
          Message result = new Message((NumberField)transaction, (NumberField)type, arguments);
          logger.debug("Received> {}", result);
          return result;
      }