public static <X, Y> List<LocalProperty<Y>> translate(List<? extends LocalProperty<X>> properties, Function<X, Optional<Y>> translator)
    {
        properties = normalizeAndPrune(properties);

        ImmutableList.Builder<LocalProperty<Y>> builder = ImmutableList.builder();
        for (LocalProperty<X> property : properties) {
            Optional<LocalProperty<Y>> translated = property.translate(translator);
            if (translated.isPresent()) {
                builder.add(translated.get());
            }
            else if (!(property instanceof ConstantProperty)) {
                break; // Only break if we fail to translate non-constants
            }
        }

        return builder.build();
    }
@Test
    public void testTranslate()
    {
        Map<String, String> map = ImmutableMap.of();
        List<LocalProperty<String>> input = ImmutableList.of();
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of());

        map = ImmutableMap.of();
        input = ImmutableList.of(grouped("a"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of());

        map = ImmutableMap.of("a", "a1");
        input = ImmutableList.of(grouped("a"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of(grouped("a1")));

        map = ImmutableMap.of();
        input = ImmutableList.of(constant("a"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of());

        map = ImmutableMap.of();
        input = ImmutableList.of(constant("a"), grouped("b"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of());

        map = ImmutableMap.of("b", "b1");
        input = ImmutableList.of(constant("a"), grouped("b"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of(grouped("b1")));

        map = ImmutableMap.of("a", "a1", "b", "b1");
        input = ImmutableList.of(constant("a"), grouped("b"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of(constant("a1"), grouped("b1")));

        map = ImmutableMap.of("a", "a1", "b", "b1");
        input = ImmutableList.of(grouped("a", "b"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of(grouped("a1", "b1")));

        map = ImmutableMap.of("a", "a1", "c", "c1");
        input = ImmutableList.of(constant("a"), grouped("b"), grouped("c"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of(constant("a1")));

        map = ImmutableMap.of("a", "a1", "c", "c1");
        input = ImmutableList.of(grouped("a", "b"), grouped("c"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of());

        map = ImmutableMap.of("a", "a1", "c", "c1");
        input = ImmutableList.of(grouped("a"), grouped("b"), grouped("c"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of(grouped("a1")));

        map = ImmutableMap.of("a", "a1", "c", "c1");
        input = ImmutableList.of(constant("b"), grouped("a", "b"), grouped("c")); // Because b is constant, we can rewrite (a, b)
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of(grouped("a1"), grouped("c1")));

        map = ImmutableMap.of("a", "a1", "c", "c1");
        input = ImmutableList.of(grouped("a"), constant("b"), grouped("c")); // Don't fail c translation due to a failed constant translation
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of(grouped("a1"), grouped("c1")));

        map = ImmutableMap.of("a", "a1", "b", "b1", "c", "c1");
        input = ImmutableList.of(grouped("a"), constant("b"), grouped("c"));
        assertEquals(LocalProperties.translate(input, translateWithMap(map)), ImmutableList.of(grouped("a1"), constant("b1"), grouped("c1")));
    }