@Override
 public boolean equals(Object obj) {
   if (this == obj) {
     return true;
   }
   // DO NOT call super.equals(); because ID could be null.
   // if (!super.equals(obj)) {
   // return false;
   // }
   if (getClass() != obj.getClass()) {
     return false;
   }
   RestaurantPrefixTable other = (RestaurantPrefixTable) obj;
   if (restaurant == null) {
     if (other.restaurant != null) {
       return false;
     }
   } else if (restaurant.getId() == null) {
     if (other.restaurant.getId() != null) {
       return false;
     }
   } else if (other.restaurant == null || !restaurant.getId().equals(other.restaurant.getId())) {
     return false;
   }
   if (prefix == null) {
     if (other.prefix != null) {
       return false;
     }
   } else if (prefix.getId() == null) {
     if (other.prefix.getId() != null) {
       return false;
     }
   } else if (other.prefix == null || !prefix.getId().equals(other.prefix.getId())) {
     return false;
   }
   if (type == null) {
     if (other.type != null) {
       return false;
     }
   } else if (type.getId() == null) {
     if (other.type.getId() != null) {
       return false;
     }
   } else if (other.type == null || !type.getId().equals(other.type.getId())) {
     return false;
   }
   return true;
 }
 @Override
 public int hashCode() {
   final int prime = 31;
   int result = 1; // DO NOT call super.hashCode(); because ID could be
   // null.
   result =
       prime * result
           + ((restaurant == null || restaurant.getId() == null)
               ? 0
               : restaurant.getId().hashCode());
   result =
       prime * result
           + ((prefix == null || prefix.getId() == null) ? 0 : prefix.getId().hashCode());
   result =
       prime * result + ((type == null || type.getId() == null) ? 0 : type.getId().hashCode());
   return result;
 }
  /**
   * Output the finalized report
   *
   * @param result an integer that doesn't get used for anything
   */
  public void onTraversalDone(Integer result) {
    logger.info("Finalizing variant report");

    for (StateKey stateKey : evaluationContexts.keySet()) {
      NewEvaluationContext nec = evaluationContexts.get(stateKey);

      for (VariantEvaluator ve : nec.getEvaluationClassList().values()) {
        ve.finalizeEvaluation();

        AnalysisModuleScanner scanner = new AnalysisModuleScanner(ve);
        Map<Field, DataPoint> datamap = scanner.getData();

        for (Field field : datamap.keySet()) {
          try {
            field.setAccessible(true);

            if (field.get(ve) instanceof TableType) {
              TableType t = (TableType) field.get(ve);

              String subTableName = ve.getClass().getSimpleName() + "." + field.getName();
              final DataPoint dataPointAnn = datamap.get(field);

              GATKReportTable table;
              if (!report.hasTable(subTableName)) {
                report.addTable(subTableName, dataPointAnn.description());
                table = report.getTable(subTableName);

                table.addPrimaryKey("entry", false);
                table.addColumn(subTableName, subTableName);

                for (VariantStratifier vs : stratificationObjects) {
                  table.addColumn(vs.getName(), "unknown");
                }

                table.addColumn("row", "unknown");

                for (Object o : t.getColumnKeys()) {
                  String c;

                  if (o instanceof String) {
                    c = (String) o;
                  } else {
                    c = o.toString();
                  }

                  table.addColumn(c, 0.0);
                }
              } else {
                table = report.getTable(subTableName);
              }

              for (int row = 0; row < t.getRowKeys().length; row++) {
                String r = (String) t.getRowKeys()[row];

                for (VariantStratifier vs : stratificationObjects) {
                  final String columnName = vs.getName();
                  table.set(stateKey.toString() + r, columnName, stateKey.get(columnName));
                }

                for (int col = 0; col < t.getColumnKeys().length; col++) {
                  String c;
                  if (t.getColumnKeys()[col] instanceof String) {
                    c = (String) t.getColumnKeys()[col];
                  } else {
                    c = t.getColumnKeys()[col].toString();
                  }

                  String newStateKey = stateKey.toString() + r;
                  table.set(newStateKey, c, t.getCell(row, col));

                  table.set(newStateKey, "row", r);
                }
              }
            } else {
              GATKReportTable table = report.getTable(ve.getClass().getSimpleName());

              for (VariantStratifier vs : stratificationObjects) {
                String columnName = vs.getName();

                table.set(stateKey.toString(), columnName, stateKey.get(vs.getName()));
              }

              table.set(stateKey.toString(), field.getName(), field.get(ve));
            }
          } catch (IllegalAccessException e) {
            throw new StingException("IllegalAccessException: " + e);
          }
        }
      }
    }

    report.print(out);
  }