@@ -0,0 +1,2793 @@
+%0Apackage io.dmitryivanov.crdt.helpers;%0A%0Aimport java.util.*;%0A%0Apublic final class Operations %7B%0A    private Operations() %7B%0A        // No instances%0A    %7D%0A%0A    public static %3CE%3E Set%3CE%3E diff(Set%3CE%3E firstSet, final Set%3CE%3E secondSet) %7B%0A        return filtered(firstSet, new Predicate%3CE%3E() %7B%0A            @Override%0A            public boolean call(E element) %7B%0A                return !secondSet.contains(element);%0A            %7D%0A        %7D);%0A    %7D%0A%0A    public static %3CE%3E Set%3CE%3E union(Set%3CE%3E firstSet, final Set%3CE%3E secondSet) %7B%0A        return filtered(firstSet, new Predicate%3CE%3E() %7B%0A            @Override%0A            public boolean call(E element) %7B%0A                return secondSet.contains(element);%0A            %7D%0A        %7D);%0A    %7D%0A%0A    public static %3CE%3E Set%3CE%3E filtered(Set%3CE%3E set, Predicate%3CE%3E predicate) %7B%0A        final Set%3CE%3E newSet = new HashSet%3C%3E();%0A        for (E element : set) %7B%0A            if (predicate.call(element)) %7B%0A                newSet.add(element);%0A            %7D%0A        %7D%0A        return newSet;%0A    %7D%0A%0A    public static %3CE, R%3E Set%3CR%3E filteredAndMapped(Set%3CE%3E set, Predicate%3CE%3E predicate,%0A            Mapper%3CE, R%3E mapper) %7B%0A        final Set%3CR%3E newSet = new HashSet%3C%3E();%0A        for (E element : set) %7B%0A            if (predicate.call(element)) %7B%0A                newSet.add(mapper.call(element));%0A            %7D%0A        %7D%0A        return newSet;%0A    %7D%0A%0A    public static %3CE%3E E select(Set%3CE%3E set, Predicate2%3CE, E%3E predicate) %7B%0A        if (set.isEmpty()) %7B%0A            throw new IllegalArgumentException(%22Empty set for select operation%22);%0A        %7D%0A        E winner = set.iterator().next();%0A        for (E element : set) %7B%0A            if (predicate.call(winner, element)) %7B%0A                winner = element;%0A            %7D%0A        %7D%0A        return winner;%0A    %7D%0A%0A    public static %3CK, V%3E Map%3CK, Collection%3CV%3E%3E toListMap(Set%3CV%3E map, Mapper%3CV, K%3E mapper) %7B%0A        final Map%3CK, Collection%3CV%3E%3E newMap = new HashMap%3C%3E(map.size());%0A        for (V element : map) %7B%0A            K key = mapper.call(element);%0A            Collection%3CV%3E list = newMap.get(key);%0A            if (null == list) %7B%0A                list = new ArrayList%3C%3E();%0A            %7D%0A            list.add(element);%0A            newMap.put(key, list);%0A        %7D%0A        return newMap;%0A    %7D%0A%0A    public static %3CK, V, R%3E Map%3CK, R%3E mapValues(Map%3CK, V%3E map, Mapper%3CV, R%3E mapper) %7B%0A        final Map%3CK, R%3E newMap = new HashMap%3C%3E(map.size());%0A        for (Map.Entry%3CK, V%3E entry : map.entrySet()) %7B%0A            newMap.put(entry.getKey(), mapper.call(entry.getValue()));%0A        %7D%0A        return newMap;%0A    %7D%0A%0A    public interface Predicate%3CE%3E %7B%0A        boolean call(E element);%0A    %7D%0A%0A    public interface Predicate2%3CE, F%3E %7B%0A        boolean call(E first, F second);%0A    %7D%0A%0A    public interface Mapper%3CE, R%3E %7B%0A        R call(E element);%0A    %7D%0A%7D%0A

Add Operation helpers to replace Java 8 Streams, and Guava's utils