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.Count == 0 && right.Count == 0)
				return 0;
			
			NodeComparerWrapper comparer = new NodeComparerWrapper(threshold, this);
			
			Diff diff = new Diff(left, right, comparer, comparer);
			
			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;
		}
        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.Count == 0 && right.Count == 0)
            {
                return(0);
            }

            NodeComparerWrapper comparer = new NodeComparerWrapper(threshold, this);

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

            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);
        }