int IComparer.Compare(object left, object right)
        {
            float ret;

            Pair pair = new Pair(left, right, differ);

            if (left.GetType() != right.GetType())
            {
                ret = 1;
            }
            else if (useCache && differ.comparisonCache.ContainsKey(pair))
            {
                ret = (float)differ.comparisonCache[pair];
            }
            else
            {
                NodeInterface comparer = differ.GetInterface(left);
                ret = comparer.Compare(left, right, differ);
            }

            if (useCache)
            {
                differ.comparisonCache[pair] = ret;
            }

            if (ret < minimumDifference && ret > threshold)
            {
                minimumDifference = ret;
            }

            if (ret <= threshold)
            {
                return(0);
            }
            else
            {
                return(1);
            }
        }
        private float CompareLists(IList left, IList right, float threshold, bool output)
        {
            // Given two lists, find the elements in the list that correspond.
            // Two elements correspond if their 'difference metric' is less than
            // or equal to threshold.  For the hunks of correspondent items,
            // recursively descend into items not truly equal.  For hunks of
            // irreconsiliable material, raise the threshold to the next useful
            // level and rescan the items.

            if (left == null)
            {
                throw new ArgumentNullException("left");
            }
            if (right == null)
            {
                throw new ArgumentNullException("right");
            }

            if (left.Count == 0 && right.Count == 0)
            {
                return(0);
            }

            NodeComparerWrapper comparer = new NodeComparerWrapper(threshold, this);

            Diff diff = new Diff(left, right, comparer, new HashCodeProvider(this));

            int nitems = 0, ndiffs = 0;

            foreach (Diff.Hunk hunk in diff)
            {
                if (hunk.Same || (hunk.Left.Count == 1 && hunk.Right.Count == 1))
                {
                    // This comprises a block of correspondent items who
                    // differ by no more than the threshold value.

                    nitems += hunk.Left.Count;

                    bool inSameRegion = false;

                    for (int i = 0; i < hunk.Left.Count; i++)
                    {
                        object oleft  = hunk.Left[i];
                        object oright = hunk.Right[i];

                        NodeInterface ileft  = GetInterface(oleft);
                        NodeInterface iright = GetInterface(oright);

                        IList cleft = null, cright = null;
                        cleft  = ileft.GetChildren(oleft);
                        cright = iright.GetChildren(oright);

                        float comp = 0;
                        if (ileft == iright)
                        {
                            comp = ileft.Compare(oleft, oright, this);
                        }

                        // If the nodes are equal, emit one node.
                        if (ileft == iright && comp == 0)
                        {
                            if (output)
                            {
                                if (!inSameRegion)
                                {
                                    WritePushSame(); inSameRegion = true;
                                }
                                WriteNodeSame(ileft, oleft, oright);
                            }

                            // Recurse into the lists of each node.
                        }
                        else if (ileft == iright && cleft != null && cright != null && cleft.Count > 0 && cright.Count > 0 && comp <= 1.0)
                        {
                            if (output && inSameRegion)
                            {
                                WritePopSame(); inSameRegion = false;
                            }
                            if (output)
                            {
                                WritePushNode(ileft, oleft, oright);
                            }
                            float d = CompareLists(cleft, cright, 0, output);
                            d *= hunk.Left.Count;
                            if (d < 1)
                            {
                                d = 1;
                            }
                            ndiffs += (int)d;
                            if (output)
                            {
                                WritePopNode();
                            }

                            // The nodes are not equal, so emit removed and added nodes.
                        }
                        else
                        {
                            if (output && inSameRegion)
                            {
                                WritePopSame(); inSameRegion = false;
                            }
                            if (output)
                            {
                                WriteNodeChange(ileft, oleft, iright, oright);
                            }
                            ndiffs += hunk.Left.Count;
                        }
                    }

                    if (output && inSameRegion)
                    {
                        WritePopSame();
                    }
                }
                else
                {
                    int ct = hunk.Left.Count + hunk.Right.Count;
                    nitems += ct;
                    ndiffs += ct;

                    if (output)
                    {
                        bool noRecurse = comparer.minimumDifference >= 1;
                        if (hunk.Right.Count == 0 || (hunk.Left.Count > 0 && noRecurse))
                        {
                            WriteNodesRemoved(hunk.Left);
                        }
                        if (hunk.Left.Count == 0 || (hunk.Right.Count > 0 && noRecurse))
                        {
                            WriteNodesAdded(hunk.Right);
                        }
                        if (hunk.Right.Count != 0 && hunk.Left.Count != 0 && !noRecurse)
                        {
                            CompareLists(hunk.Left, hunk.Right, comparer.minimumDifference, output);
                        }
                    }
                }
            }

            return((float)ndiffs / (float)nitems);
        }