// Path: src/main/java/com/cedarsoftware/util/Converter.java
// public static BigDecimal convert2BigDecimal(Object fromInstance)
// {
//     if (fromInstance == null)
//     {
//         return BIG_DECIMAL_ZERO;
//     }
//     return convertToBigDecimal(fromInstance);
// }
// 
// Path: src/main/java/com/cedarsoftware/util/Converter.java
// public static boolean convert2boolean(Object fromInstance)
// {
//     if (fromInstance == null)
//     {
//         return false;
//     }
//     return convertToBoolean(fromInstance);
// }
// 
// Path: src/main/java/com/cedarsoftware/util/ReflectionUtils.java
// protected static String getClassLoaderName(Class<?> c)
// {
//     ClassLoader loader = c.getClassLoader();
//     return loader == null ? "bootstrap" : loader.toString();
// }


import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static com.cedarsoftware.util.Converter.convert2BigDecimal;
import static com.cedarsoftware.util.Converter.convert2boolean;
import static com.cedarsoftware.util.ReflectionUtils.getClassLoaderName;
     * existence in a cache.  Relying on an objects identity will not locate an
     * object in cache, yet relying on it being equivalent will.<br><br>
     *
     * This method will handle cycles correctly, for example A-&gt;B-&gt;C-&gt;A.  Suppose a and
     * a' are two separate instances of the A with the same values for all fields on
     * A, B, and C.  Then a.deepEquals(a') will return true.  It uses cycle detection
     * storing visited objects in a Set to prevent endless loops.
     * @param a Object one to compare
     * @param b Object two to compare
     * @param options Map options for compare. With no option, if a custom equals()
     *                method is present, it will be used.  If IGNORE_CUSTOM_EQUALS is
     *                present, it will be expected to be a Set of classes to ignore.
     *                It is a black-list of classes that will not be compared
     *                using .equals() even if the classes have a custom .equals() method
     *                present.  If it is and empty set, then no custom .equals() methods
     *                will be called.
     *
     * @return true if a is equivalent to b, false otherwise.  Equivalent means that
     * all field values of both subgraphs are the same, either at the field level
     * or via the respectively encountered overridden .equals() methods during
     * traversal.
     */
    public static boolean deepEquals(Object a, Object b, Map<?, ?> options) {
        Set<ItemsToCompare> visited = new HashSet<>();
        return deepEquals(a, b, options,visited);
    }

    private static boolean deepEquals(Object a, Object b, Map<?, ?> options, Set<ItemsToCompare> visited) {
        Deque<ItemsToCompare> stack = new LinkedList<>();
        Set<String> ignoreCustomEquals = (Set<String>) options.get(IGNORE_CUSTOM_EQUALS);
// Path: src/main/java/com/cedarsoftware/util/Converter.java
// public static BigDecimal convert2BigDecimal(Object fromInstance)
// {
//     if (fromInstance == null)
//     {
//         return BIG_DECIMAL_ZERO;
//     }
//     return convertToBigDecimal(fromInstance);
// }
// 
// Path: src/main/java/com/cedarsoftware/util/Converter.java
// public static boolean convert2boolean(Object fromInstance)
// {
//     if (fromInstance == null)
//     {
//         return false;
//     }
//     return convertToBoolean(fromInstance);
// }
// 
// Path: src/main/java/com/cedarsoftware/util/ReflectionUtils.java
// protected static String getClassLoaderName(Class<?> c)
// {
//     ClassLoader loader = c.getClassLoader();
//     return loader == null ? "bootstrap" : loader.toString();
// }


// Path: src/main/java/com/cedarsoftware/util/DeepEquals.java
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static com.cedarsoftware.util.Converter.convert2BigDecimal;
import static com.cedarsoftware.util.Converter.convert2boolean;
import static com.cedarsoftware.util.ReflectionUtils.getClassLoaderName;

     * existence in a cache.  Relying on an objects identity will not locate an
     * object in cache, yet relying on it being equivalent will.<br><br>
     *
     * This method will handle cycles correctly, for example A-&gt;B-&gt;C-&gt;A.  Suppose a and
     * a' are two separate instances of the A with the same values for all fields on
     * A, B, and C.  Then a.deepEquals(a') will return true.  It uses cycle detection
     * storing visited objects in a Set to prevent endless loops.
     * @param a Object one to compare
     * @param b Object two to compare
     * @param options Map options for compare. With no option, if a custom equals()
     *                method is present, it will be used.  If IGNORE_CUSTOM_EQUALS is
     *                present, it will be expected to be a Set of classes to ignore.
     *                It is a black-list of classes that will not be compared
     *                using .equals() even if the classes have a custom .equals() method
     *                present.  If it is and empty set, then no custom .equals() methods
     *                will be called.
     *
     * @return true if a is equivalent to b, false otherwise.  Equivalent means that
     * all field values of both subgraphs are the same, either at the field level
     * or via the respectively encountered overridden .equals() methods during
     * traversal.
     */
    public static boolean deepEquals(Object a, Object b, Map<?, ?> options) {
        Set<ItemsToCompare> visited = new HashSet<>();
        return deepEquals(a, b, options,visited);
    }

    private static boolean deepEquals(Object a, Object b, Map<?, ?> options, Set<ItemsToCompare> visited) {
        Deque<ItemsToCompare> stack = new LinkedList<>();
        Set<String> ignoreCustomEquals = (Set<String>) options.get(IGNORE_CUSTOM_EQUALS);
        final boolean allowStringsToMatchNumbers = convert2boolean(options.get(ALLOW_STRINGS_TO_MATCH_NUMBERS));