// Path: measures/src/main/java/org/xbill/DNS/DNSClient.java
// public interface DNSClient {
//   void bind(SocketAddress addr) throws IOException;
// 
//   void connect(SocketAddress addr) throws IOException;
// 
//   void send(byte[] data) throws IOException;
// 
//   byte[] recv(int max) throws IOException;
// 
//   void cleanup() throws IOException;
// }
// 
// Path: measures/src/main/java/org/xbill/DNS/PublicTCPClient.java
// public final class PublicTCPClient implements DNSClient {
//   private final TCPClient client;
// 
//   public PublicTCPClient(long endTime) throws IOException {
//     client = new TCPClient(endTime);
//   }
// 
//   @Override
//   public void bind(SocketAddress addr) throws IOException {
//     client.bind(addr);
//   }
// 
//   @Override
//   public void connect(SocketAddress addr) throws IOException {
//     client.connect(addr);
//   }
// 
//   @Override
//   public void send(byte[] data) throws IOException {
//     client.send(data);
//   }
// 
//   /**
//    * Receive DNS data.
//    *
//    * @param max Not used in tcp implementation
//    * @return The received content.
//    * @throws IOException {@inheritDoc}
//    */
//   @Override
//   public byte[] recv(int max) throws IOException {
//     return client.recv();
//   }
// 
//   @Override
//   public void cleanup() throws IOException {
//     client.cleanup();
//   }
// }
// 
// Path: measures/src/main/java/org/xbill/DNS/PublicUDPClient.java
// public final class PublicUDPClient implements DNSClient {
//   private final UDPClient client;
// 
//   public PublicUDPClient(long endTime) throws IOException {
//     client = new UDPClient(endTime);
//   }
// 
//   @Override
//   public void bind(SocketAddress addr) throws IOException {
//     client.bind(addr);
//   }
// 
//   @Override
//   public void connect(SocketAddress addr) throws IOException {
//     client.connect(addr);
//   }
// 
//   @Override
//   public void send(byte[] data) throws IOException {
//     client.send(data);
//   }
// 
//   @Override
//   public byte[] recv(int max) throws IOException {
//     return client.recv(max);
//   }
// 
//   @Override
//   public void cleanup() throws IOException {
//     client.cleanup();
//   }
// }
// 
// Path: measures/src/main/java/io/apisense/network/Measurement.java
// public abstract class Measurement {
//   public final String taskName;
// 
//   protected Measurement(String taskName) {
//     this.taskName = taskName;
//   }
// 
//   /**
//    * Ensure that the measurement is asynchronously called in an {@link ExecutorService}.
//    *
//    * @param callback The {@link MeasurementCallback} used
//    *                 for reporting success or failure of this measurement.
//    */
//   public final void call(MeasurementCallback callback) {
//     AsyncTask.execute(new MeasurementExecutor(this, callback));
//   }
// 
//   /**
//    * Actual, synchronous, process of a measurement.
//    * This method has to be called from another thread than the UI one.
//    *
//    * @return The results of this measurement.
//    * @throws MeasurementError If anything goes wrong during measurement.
//    */
//   public abstract MeasurementResult execute() throws MeasurementError;
// }
// 
// Path: measures/src/main/java/io/apisense/network/MeasurementError.java
// public class MeasurementError extends Exception {
//   public final String taskName;
// 
//   public MeasurementError(String taskName, String reason) {
//     super(reason);
//     this.taskName = taskName;
//   }
// 
//   public MeasurementError(String taskName, String reason, Throwable e) {
//     super(reason, e);
//     this.taskName = taskName;
//   }
// 
//   public MeasurementError(String taskName, Exception e) {
//     this(taskName, e.getMessage(), e);
//   }
// }


import android.support.annotation.NonNull;
import android.util.Log;
import org.xbill.DNS.DClass;
import org.xbill.DNS.DNSClient;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Message;
import org.xbill.DNS.Name;
import org.xbill.DNS.OPTRecord;
import org.xbill.DNS.PublicTCPClient;
import org.xbill.DNS.PublicUDPClient;
import org.xbill.DNS.Record;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import io.apisense.network.Measurement;
import io.apisense.network.MeasurementError;
    try {
      response = new Message(respBytes);
      Log.d(TAG, "Successfully parsed response");
      // if the response was truncated, then re-query over TCP
      if (!useTCP && response.getHeader().getFlag(Flags.TC)) {
        throw new TruncatedException();
      }
    } catch (IOException e) {
      throw new MeasurementError(taskName, "Problem trying to parse dns packet", e);
    }
    return response;
  }

  /**
   * Initialize and connect the dns TCP or UDP client.
   *
   * @param server  The server to connect the client to.
   * @param useTCP  Tells if the client should be TCP or UDP.
   * @param endTime The request timeout.
   * @return The initialized client.
   * @throws MeasurementError If any error occurred during client creation or connection.
   */
  @NonNull
  private DNSClient connectClient(String server, boolean useTCP, long endTime)
      throws MeasurementError {
    DNSClient client;
    try {
      if (useTCP) {
        client = new PublicTCPClient(endTime);
      } else {
// Path: measures/src/main/java/org/xbill/DNS/DNSClient.java
// public interface DNSClient {
//   void bind(SocketAddress addr) throws IOException;
// 
//   void connect(SocketAddress addr) throws IOException;
// 
//   void send(byte[] data) throws IOException;
// 
//   byte[] recv(int max) throws IOException;
// 
//   void cleanup() throws IOException;
// }
// 
// Path: measures/src/main/java/org/xbill/DNS/PublicTCPClient.java
// public final class PublicTCPClient implements DNSClient {
//   private final TCPClient client;
// 
//   public PublicTCPClient(long endTime) throws IOException {
//     client = new TCPClient(endTime);
//   }
// 
//   @Override
//   public void bind(SocketAddress addr) throws IOException {
//     client.bind(addr);
//   }
// 
//   @Override
//   public void connect(SocketAddress addr) throws IOException {
//     client.connect(addr);
//   }
// 
//   @Override
//   public void send(byte[] data) throws IOException {
//     client.send(data);
//   }
// 
//   /**
//    * Receive DNS data.
//    *
//    * @param max Not used in tcp implementation
//    * @return The received content.
//    * @throws IOException {@inheritDoc}
//    */
//   @Override
//   public byte[] recv(int max) throws IOException {
//     return client.recv();
//   }
// 
//   @Override
//   public void cleanup() throws IOException {
//     client.cleanup();
//   }
// }
// 
// Path: measures/src/main/java/org/xbill/DNS/PublicUDPClient.java
// public final class PublicUDPClient implements DNSClient {
//   private final UDPClient client;
// 
//   public PublicUDPClient(long endTime) throws IOException {
//     client = new UDPClient(endTime);
//   }
// 
//   @Override
//   public void bind(SocketAddress addr) throws IOException {
//     client.bind(addr);
//   }
// 
//   @Override
//   public void connect(SocketAddress addr) throws IOException {
//     client.connect(addr);
//   }
// 
//   @Override
//   public void send(byte[] data) throws IOException {
//     client.send(data);
//   }
// 
//   @Override
//   public byte[] recv(int max) throws IOException {
//     return client.recv(max);
//   }
// 
//   @Override
//   public void cleanup() throws IOException {
//     client.cleanup();
//   }
// }
// 
// Path: measures/src/main/java/io/apisense/network/Measurement.java
// public abstract class Measurement {
//   public final String taskName;
// 
//   protected Measurement(String taskName) {
//     this.taskName = taskName;
//   }
// 
//   /**
//    * Ensure that the measurement is asynchronously called in an {@link ExecutorService}.
//    *
//    * @param callback The {@link MeasurementCallback} used
//    *                 for reporting success or failure of this measurement.
//    */
//   public final void call(MeasurementCallback callback) {
//     AsyncTask.execute(new MeasurementExecutor(this, callback));
//   }
// 
//   /**
//    * Actual, synchronous, process of a measurement.
//    * This method has to be called from another thread than the UI one.
//    *
//    * @return The results of this measurement.
//    * @throws MeasurementError If anything goes wrong during measurement.
//    */
//   public abstract MeasurementResult execute() throws MeasurementError;
// }
// 
// Path: measures/src/main/java/io/apisense/network/MeasurementError.java
// public class MeasurementError extends Exception {
//   public final String taskName;
// 
//   public MeasurementError(String taskName, String reason) {
//     super(reason);
//     this.taskName = taskName;
//   }
// 
//   public MeasurementError(String taskName, String reason, Throwable e) {
//     super(reason, e);
//     this.taskName = taskName;
//   }
// 
//   public MeasurementError(String taskName, Exception e) {
//     this(taskName, e.getMessage(), e);
//   }
// }


// Path: measures/src/main/java/io/apisense/network/dns/DNSLookupTask.java
import android.support.annotation.NonNull;
import android.util.Log;
import org.xbill.DNS.DClass;
import org.xbill.DNS.DNSClient;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Message;
import org.xbill.DNS.Name;
import org.xbill.DNS.OPTRecord;
import org.xbill.DNS.PublicTCPClient;
import org.xbill.DNS.PublicUDPClient;
import org.xbill.DNS.Record;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import io.apisense.network.Measurement;
import io.apisense.network.MeasurementError;

    try {
      response = new Message(respBytes);
      Log.d(TAG, "Successfully parsed response");
      // if the response was truncated, then re-query over TCP
      if (!useTCP && response.getHeader().getFlag(Flags.TC)) {
        throw new TruncatedException();
      }
    } catch (IOException e) {
      throw new MeasurementError(taskName, "Problem trying to parse dns packet", e);
    }
    return response;
  }

  /**
   * Initialize and connect the dns TCP or UDP client.
   *
   * @param server  The server to connect the client to.
   * @param useTCP  Tells if the client should be TCP or UDP.
   * @param endTime The request timeout.
   * @return The initialized client.
   * @throws MeasurementError If any error occurred during client creation or connection.
   */
  @NonNull
  private DNSClient connectClient(String server, boolean useTCP, long endTime)
      throws MeasurementError {
    DNSClient client;
    try {
      if (useTCP) {
        client = new PublicTCPClient(endTime);
      } else {
        client = new PublicUDPClient(endTime);