// 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.util.Log;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import io.apisense.network.Measurement;
import io.apisense.network.MeasurementError;
package io.apisense.network.tcp;




/**
 * Abstract class containing common code used for UDP upload and download tests
 */
abstract class TCPThroughputTask extends Measurement {
  protected static final int BUFFER_SIZE = 5000;
  private static final String TAG = "TCPThroughputTask";
  private static final int SEC_TO_MS = 1000;
  protected final TCPThroughputConfig config;

  // helper variables
  protected int accumulativeSize = 0;
  //start time of each sampling period in milliseconds
  protected long startSampleTime = 0;
  protected long taskStartTime = 0;
  protected long taskEndTime = 0;
  /**
   * Data consummed (sent/received) after slow star period (in bits)
   */
  protected long dataConsumedAfterSlowStart = 0;
  List<Double> samplingResults = new ArrayList<>();

  TCPThroughputTask(String taskName, TCPThroughputConfig tcpThroughputConfig) {
    super(taskName);
    config = tcpThroughputConfig;
  }

// 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/tcp/TCPThroughputTask.java
import android.util.Log;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import io.apisense.network.Measurement;
import io.apisense.network.MeasurementError;

package io.apisense.network.tcp;




/**
 * Abstract class containing common code used for UDP upload and download tests
 */
abstract class TCPThroughputTask extends Measurement {
  protected static final int BUFFER_SIZE = 5000;
  private static final String TAG = "TCPThroughputTask";
  private static final int SEC_TO_MS = 1000;
  protected final TCPThroughputConfig config;

  // helper variables
  protected int accumulativeSize = 0;
  //start time of each sampling period in milliseconds
  protected long startSampleTime = 0;
  protected long taskStartTime = 0;
  protected long taskEndTime = 0;
  /**
   * Data consummed (sent/received) after slow star period (in bits)
   */
  protected long dataConsumedAfterSlowStart = 0;
  List<Double> samplingResults = new ArrayList<>();

  TCPThroughputTask(String taskName, TCPThroughputConfig tcpThroughputConfig) {
    super(taskName);
    config = tcpThroughputConfig;
  }

  protected Socket buildUpSocket(InetAddress hostname, int portNum) throws MeasurementError {