// Path: src/main/java/com/timgroup/karg/reference/Gettable.java
// public interface Gettable<T> extends Supplier<T> {
// }
// 
// Path: src/main/java/com/timgroup/karg/reference/Getter.java
// public interface Getter<O, T> {
//     T get(O object);
// }
// 
// Path: src/main/java/com/timgroup/karg/reference/Lens.java
// public interface Lens<O, T> extends Getter<O, T>, Setter<O, T> { }
// 
// Path: src/main/java/com/timgroup/karg/reference/Ref.java
// public interface Ref<T> extends Gettable<T>, Settable<T> { }
// 
// Path: src/main/java/com/timgroup/karg/reference/Settable.java
// public interface Settable<T> {
//     T set(T newValue);
// }
// 
// Path: src/main/java/com/timgroup/karg/reference/Setter.java
// public interface Setter<O, T> {
//     T set(O object, T newValue);
// }


import com.timgroup.karg.reference.Gettable;
import com.timgroup.karg.reference.Getter;
import com.timgroup.karg.reference.Lens;
import com.timgroup.karg.reference.Ref;
import com.timgroup.karg.reference.Settable;
import com.timgroup.karg.reference.Setter;
    
    public static <O, INNER, OUTER> Getter<O, OUTER> convert(final Getter<O, INNER> lens, final TypeConverter<INNER, OUTER> converter) {
        return new Getter<O, OUTER>() {
            @Override public OUTER get(O object) {
                return converter.pullOut(lens.get(object));
            }
        };
    }
    
    public static <O, INNER, OUTER> Setter<O, OUTER> convert(final Setter<O, INNER> lens, final TypeConverter<INNER, OUTER> converter) {
        return new Setter<O, OUTER>() {
            @Override public OUTER set(O object, OUTER newValue) {
                return converter.pullOut(lens.set(object, converter.pushIn(newValue)));
            }
        };
    }
    
    public static <INNER, OUTER> Ref<OUTER> convert(final Ref<INNER> ref, final TypeConverter<INNER, OUTER> converter) {
        return new Ref<OUTER>() {
            @Override public OUTER get() {
                return converter.pullOut(ref.get());
            }

            @Override public OUTER set(OUTER newValue) {
                return converter.pullOut(ref.set(converter.pushIn(newValue)));
            }
        };
    }
    
    public static <INNER, OUTER> Gettable<OUTER> convert(final Gettable<INNER> ref, final TypeConverter<INNER, OUTER> converter) {
// Path: src/main/java/com/timgroup/karg/reference/Gettable.java
// public interface Gettable<T> extends Supplier<T> {
// }
// 
// Path: src/main/java/com/timgroup/karg/reference/Getter.java
// public interface Getter<O, T> {
//     T get(O object);
// }
// 
// Path: src/main/java/com/timgroup/karg/reference/Lens.java
// public interface Lens<O, T> extends Getter<O, T>, Setter<O, T> { }
// 
// Path: src/main/java/com/timgroup/karg/reference/Ref.java
// public interface Ref<T> extends Gettable<T>, Settable<T> { }
// 
// Path: src/main/java/com/timgroup/karg/reference/Settable.java
// public interface Settable<T> {
//     T set(T newValue);
// }
// 
// Path: src/main/java/com/timgroup/karg/reference/Setter.java
// public interface Setter<O, T> {
//     T set(O object, T newValue);
// }


// Path: src/main/java/com/timgroup/karg/typeconversion/TypeConverters.java
import com.timgroup.karg.reference.Gettable;
import com.timgroup.karg.reference.Getter;
import com.timgroup.karg.reference.Lens;
import com.timgroup.karg.reference.Ref;
import com.timgroup.karg.reference.Settable;
import com.timgroup.karg.reference.Setter;

    
    public static <O, INNER, OUTER> Getter<O, OUTER> convert(final Getter<O, INNER> lens, final TypeConverter<INNER, OUTER> converter) {
        return new Getter<O, OUTER>() {
            @Override public OUTER get(O object) {
                return converter.pullOut(lens.get(object));
            }
        };
    }
    
    public static <O, INNER, OUTER> Setter<O, OUTER> convert(final Setter<O, INNER> lens, final TypeConverter<INNER, OUTER> converter) {
        return new Setter<O, OUTER>() {
            @Override public OUTER set(O object, OUTER newValue) {
                return converter.pullOut(lens.set(object, converter.pushIn(newValue)));
            }
        };
    }
    
    public static <INNER, OUTER> Ref<OUTER> convert(final Ref<INNER> ref, final TypeConverter<INNER, OUTER> converter) {
        return new Ref<OUTER>() {
            @Override public OUTER get() {
                return converter.pullOut(ref.get());
            }

            @Override public OUTER set(OUTER newValue) {
                return converter.pullOut(ref.set(converter.pushIn(newValue)));
            }
        };
    }
    
    public static <INNER, OUTER> Gettable<OUTER> convert(final Gettable<INNER> ref, final TypeConverter<INNER, OUTER> converter) {
        return new Gettable<OUTER>() {