private void sendTuples() {
    assert (state == RUNNING || state == PAUSED || state == END || state == TERMINATED);

    if (state == TERMINATED) return;

    // Number seconds since start
    int curTs = getCurTs();

    if (state == RUNNING) {

      int n = getNumTuples();

      for (; n > 0; n--) {
        String line;

        try {
          line = in.readLine();
        } catch (IOException e) {
          System.out.println("Error reading from " + fileName);
          processEOF();
          break;
        }

        // End of file
        if (line == null) {
          processEOF();
          if (state == END) break;

          continue;
        }

        out.println(curTs + "," + line);

        numTuplesSent++;
        intervalNumTuplesSent++;
        lastOutputTs = curTs;
      }
    }

    // Send a heartbeat if we have not sent any tuple with curTs - we
    // send a heartbeat even in PAUSED or END state
    if (curTs > lastOutputTs) {
      out.println(curTs);
      lastOutputTs = curTs;
    }

    out.flush();
  }
  private void sendSchema() {
    StringBuffer strBuf = new StringBuffer();

    // timestamp column
    strBuf.append('i');

    // sign column
    if (!table.isStream()) {
      strBuf.append(",b");
    }

    for (int a = 0; a < table.getNumAttrs(); a++) {
      strBuf.append(',');

      switch (table.getAttrType(a)) {
        case Types.INTEGER:
          strBuf.append('i');
          break;

        case Types.FLOAT:
          strBuf.append('f');
          break;

        case Types.CHAR:
          strBuf.append('c');
          strBuf.append(table.getAttrLen(a));
          break;

        case Types.BYTE:
          strBuf.append('b');
          break;

        default:
          assert (false);
          break;
      }
    }

    String schema = strBuf.toString();
    out.println(schema);
  }