internal D.DifferenceNode _CompareObject(object left, object right)
        {
            Func <bool, D.DifferenceNode> state = (b) => {
                return(b ? null : new D.DifferenceNode(null, left, right));
            };

            if (left == null || right == null)
            {
                return(state(left == right));
            }
            if (!left.GetType().Equals(right.GetType()))
            {
                return(state(false));
            }

            if (left is byte)
            {
                return(state(((int)(byte)left - (int)(byte)right) == 0));
            }
            if (left is int)
            {
                return(state(((int)left - (int)right) == 0));
            }
            if (left is long)
            {
                return(state(((long)left - (long)right) == 0));
            }
            if (left is float)
            {
                return(state(((float)left - (float)right).IsNearZero(1e-5f)));
            }
            //if (left is double)
            //	return state(((double)left - (double)right).IsNearZero(1e-5));
            if (left is string)
            {
                return(state(((string)left).CompareTo((string)right) == 0));
            }

            if (left is F.str)
            {
                string left_str  = (left  as F.str).ToString();
                string right_str = (right as F.str).ToString();
                return(state(left_str.CompareTo(right_str) == 0));
            }

            if (left is P.Properties)
            {
                D.DifferenceNode node = new D.DifferenceNode(null, left, right);
                D.DifferenceNode sub;

                Func <P.Properties, P.Properties> clone = (src) => {
                    P.Properties dst = new P.Properties();
                    foreach (P.Property prop in src)
                    {
                        dst.Add(prop);
                    }
                    return(dst);
                };
                P.Properties left_coll  = clone(left as P.Properties);
                P.Properties right_coll = clone(right as P.Properties);

                for (int index = 0; index < left_coll.Count; ++index)
                {
                    P.Property left_sub  = left_coll[index];
                    P.Property right_sub = _FindMatch(left_sub, right_coll);
                    if (right_sub != null)
                    {
                        right_coll.Remove(right_sub);
                    }

                    sub = _Compare(left_sub, right_sub);
                    if (sub != null)
                    {
                        string title = left_sub.PrettyName();
                        if (string.IsNullOrEmpty(title))
                        {
                            title = index.ToString();
                        }
                        sub.Title = title;
                        node.Add(sub);
                    }
                }
                for (int index = 0; index < right_coll.Count; ++index)
                {
                    P.Property right_sub = right_coll[index];
                    if (right_sub != null)
                    {
                        string name = right_sub.GetName();
                        if (_blacklisted.Contains(name))
                        {
                            continue;
                        }

                        string title = right_sub.PrettyName();
                        if (string.IsNullOrEmpty(title))
                        {
                            title = index.ToString();
                        }
                        node.Add(title, null, right_sub);
                    }
                }

                return(node.ChildCount > 0 ? node : null);
            }

            if (left is IDictionary)
            {
                D.DifferenceNode node = new D.DifferenceNode(null, left, right);
                D.DifferenceNode sub;

                Func <IDictionary, IDictionary> clone = (src) => {
                    Dictionary <object, object> dst = new Dictionary <object, object>();
                    foreach (object key in src.Keys)
                    {
                        dst.Add(key, src[key]);
                    }
                    return(dst);
                };
                IDictionary left_coll  = clone(left as IDictionary);
                IDictionary right_coll = clone(right as IDictionary);

                foreach (object key in left_coll.Keys)
                {
                    object left_sub  = left_coll[key];
                    object right_sub = null;
                    if (right_coll.Contains(key))
                    {
                        right_sub = right_coll[key];
                        right_coll.Remove(key);
                    }

                    if (right_sub == null && left_sub != null)
                    {
                        sub = new D.DifferenceNode(null, left_sub, null);
                    }
                    else if (left_sub is P.Property)
                    {
                        sub = _Compare(left_sub as P.Property, right_sub as P.Property);
                    }
                    else
                    {
                        sub = _CompareObject(left_sub, right_sub);
                    }
                    if (sub != null)
                    {
                        sub.Title = key.ToString();
                        node.Add(sub);
                    }
                }
                foreach (object key in right_coll)
                {
                    node.Add(key.ToString(), null, right_coll[key]);
                }

                return(node.ChildCount > 0 ? node : null);
            }

            if (left is ICollection)
            {
                D.DifferenceNode node = new D.DifferenceNode(null, left, right);
                D.DifferenceNode sub;

                Func <ICollection, List <object> > clone = (src) => {
                    List <object> dst = new List <object>();
                    foreach (object val in src)
                    {
                        dst.Add(val);
                    }
                    return(dst);
                };
                List <object> left_coll  = clone(left as ICollection);
                List <object> right_coll = clone(right as ICollection);

                for (int index = 0; index < left_coll.Count; ++index)
                {
                    object left_sub  = left_coll[index];
                    object right_sub = null;
                    if (index < right_coll.Count)
                    {
                        right_sub         = right_coll[index];
                        right_coll[index] = null;
                    }

                    if (right_sub == null && left_sub != null)
                    {
                        sub = new D.DifferenceNode(null, left_sub, null);
                    }
                    else if (left_sub is P.Property)
                    {
                        sub = _Compare(left_sub as P.Property, right_sub as P.Property);
                    }
                    else
                    {
                        sub = _CompareObject(left_sub, right_sub);
                    }
                    if (sub != null)
                    {
                        string title = left_sub.PrettyName();
                        if (string.IsNullOrEmpty(title))
                        {
                            title = index.ToString();
                        }
                        sub.Title = title;
                        node.Add(sub);
                    }
                }
                for (int index = 0; index < right_coll.Count; ++index)
                {
                    object right_sub = right_coll[index];
                    if (right_sub != null)
                    {
                        string title = right_sub.PrettyName();
                        if (string.IsNullOrEmpty(title))
                        {
                            title = index.ToString();
                        }
                        node.Add(title, null, right_sub);
                    }
                }

                return(node.ChildCount > 0 ? node : null);
            }

            return(null);
        }
        internal D.DifferenceNode _Compare(P.Property left, P.Property right)
        {
            D.DifferenceNode node = new D.DifferenceNode(left.ToString(), left, right);
            D.DifferenceNode sub;

            if ((left == null || right == null) && (left != right))
            {
                return(node);
            }

            // Do some by-name blacklisting to skips things like delta timestamps
            if (left is P.ValueProperty)
            {
                P.ValueProperty val_prop = left as P.ValueProperty;
                if (val_prop.Name != null)
                {
                    string name = val_prop.Name.ToString();
                    if (_blacklisted.Contains(name))
                    {
                        return(null);
                    }
                }
            }

            Dictionary <string, object> left_childs  = new Dictionary <string, object>(left.GetChilds());
            Dictionary <string, object> right_childs = new Dictionary <string, object>(right.GetChilds());

            while (left_childs.Count > 0)
            {
                var pair = left_childs.First();

                object left_sub = pair.Value;
                left_childs.Remove(pair.Key);

                object right_sub = null;
                if (right_childs.ContainsKey(pair.Key))
                {
                    right_sub = right_childs[pair.Key];
                    right_childs.Remove(pair.Key);
                }

                if (_blacklisted.Contains(pair.Key))
                {
                    continue;
                }

                if (right_sub == null && left_sub != null)
                {
                    sub = new D.DifferenceNode(null, left_sub, null);
                }
                else if (left_sub is P.Property)
                {
                    sub = _Compare(left_sub as P.Property, right_sub as P.Property);
                }
                else
                {
                    sub = _CompareObject(left_sub, right_sub);
                }
                if (sub != null)
                {
                    sub.Title = pair.Key;
                    node.Add(sub);
                }
            }

            foreach (var pair in right_childs)
            {
                if (!_blacklisted.Contains(pair.Key))
                {
                    node.Add(pair.Key, null, pair.Value);
                }
            }

            return((node.ChildCount > 0) ? node : null);
        }