public static <T, D extends Difference> Specifier<T, D> make(final @Nullable Set<T> past, final @Nullable Set<T> now) {
    boolean pastEmpty = past == null || past.isEmpty();
    boolean nowEmpty = now == null || now.isEmpty();
    if (pastEmpty && nowEmpty) {
      return new Specifier<>() {
        @Override
        public Collection<T> added() {
          return Collections.emptySet();
        }

        @Override
        public Collection<T> removed() {
          return Collections.emptySet();
        }

        @Override
        public Collection<Pair<T, D>> changed() {
          return Collections.emptySet();
        }

        @Override
        public boolean unchanged() {
          return true;
        }
      };
    }

    if (pastEmpty) {
      final Collection<T> _now = Collections.unmodifiableSet(now);
      return new Specifier<>() {
        @Override
        public Collection<T> added() {
          return _now;
        }

        @Override
        public Collection<T> removed() {
          return Collections.emptySet();
        }

        @Override
        public Collection<Pair<T, D>> changed() {
          return Collections.emptySet();
        }

        @Override
        public boolean unchanged() {
          return false;
        }
      };
    }

    if (nowEmpty) {
      final Collection<T> _past = Collections.unmodifiableSet(past);
      return new Specifier<>() {
        @Override
        public Collection<T> added() {
          return Collections.emptySet();
        }

        @Override
        public Collection<T> removed() {
          return _past;
        }

        @Override
        public Collection<Pair<T, D>> changed() {
          return Collections.emptySet();
        }

        @Override
        public boolean unchanged() {
          return false;
        }
      };
    }

    final Set<T> added = new HashSet<>(now);
    added.removeAll(past);

    final Set<T> removed = new HashSet<>(past);
    removed.removeAll(now);

    final Set<Pair<T, D>> changed;
    if (canContainChangedElements(past, now)) {
      changed = new HashSet<>();
      final Set<T> intersect = new HashSet<>(past);
      final Map<T, T> nowMap = new HashMap<>();

      for (T s : now) {
        if (intersect.contains(s)) {
          nowMap.put(s, s);
        }
      }

      intersect.retainAll(now);

      for (T x : intersect) {
        final Proto px = (Proto)x;
        final Proto py = (Proto)nowMap.get(x);
        //noinspection unchecked
        final D diff = (D)py.difference(px);

        if (!diff.no()) {
          changed.add(Pair.create(x, diff));
        }
      }
    }
    else {
      changed = Collections.emptySet();
    }

    return new Specifier<>() {
      @Override
      public Collection<T> added() {
        return added;
      }

      @Override
      public Collection<T> removed() {
        return removed;
      }

      @Override
      public Collection<Pair<T, D>> changed() {
        return changed;
      }

      @Override
      public boolean unchanged() {
        return changed.isEmpty() && added.isEmpty() && removed.isEmpty();
      }
    };
  }
public static <T, D extends Difference> Specifier<T, D> make(final @Nullable Set<T> past, final @Nullable Set<T> now)