public boolean equals(Object o) {
      if (!(o instanceof FilteredSubContext)) {
        return false;
      }

      FilteredSubContext that = (FilteredSubContext) o;

      return context.equals(that.context)
          && filter.equals(that.filter)
          && secondaryFilter.equals(that.secondaryFilter)
          && (recurse == that.recurse);
    }
  /**
   * <code>getSubContext</code> creates a new context which has <code>FeatureHolder</code>s filtered
   * using the current filter.
   *
   * @param context a <code>PairwiseRenderContext</code>.
   * @return a <code>PairwiseRenderContext</code>.
   */
  protected PairwiseRenderContext getSubContext(PairwiseRenderContext context) {
    // Filter the sequence features
    FeatureFilter ff =
        new FeatureFilter.And(filter, new FeatureFilter.OverlapsLocation(context.getRange()));

    // Filter the secondary sequence features
    FeatureFilter ffSec =
        new FeatureFilter.And(
            filter, new FeatureFilter.OverlapsLocation(context.getSecondaryRange()));

    // Create a cache key
    FilteredSubContext cacheKey = new FilteredSubContext(context, ff, ffSec, recurse);
    // Try the cache for a context first
    PairwiseRenderContext filtered = (PairwiseRenderContext) subContextCache.get(cacheKey);

    if (filtered == null) {
      // None in cache, so make a new one
      filtered =
          new SubPairwiseRenderContext(
              context, // context delegate
              null, // symbols
              null, // secondary symbols
              context.getFeatures().filter(ff, recurse),
              context.getFeatures().filter(ffSec, recurse),
              null, // range
              null); // secondary range

      // Add to cache
      subContextCache.put(cacheKey, filtered);
      // Create a listener for changes in the feature holder
      CacheFlusher cf = new CacheFlusher(cacheKey);
      // Add the listener for changes in features
      ((Changeable) context.getSymbols()).addChangeListener(cf, FeatureHolder.FEATURES);
      cacheFlushers.add(cf);
    }

    return filtered;
  }
 public int hashCode() {
   return context.hashCode() ^ filter.hashCode();
 }