double ClusteringCoefficient::sequentialAvgLocal(const Graph &G) {
    WARN("DEPRECATED: use centrality.LocalClusteringCoefficient and take average");
	std::vector<std::vector<node> > edges(G.upperNodeIdBound());

	// copy edges with edge ids
	G.parallelForNodes([&](node u) {
		edges[u].reserve(G.degree(u));
		G.forEdgesOf(u, [&](node _u, node v, edgeid eid) {
			edges[u].emplace_back(v);
		});
	});

	//Node attribute: marker
	std::vector<bool> nodeMarker(G.upperNodeIdBound(), false);

	//Edge attribute: triangle count
	std::vector<count> triangleCount(G.upperNodeIdBound(), 0);

	// bucket sort
	count n = G.numberOfNodes();
	std::vector<node> sortedNodes(n);
	{
		std::vector<index> nodePos(n + 1, 0);

		G.forNodes([&](node u) {
			++nodePos[n - G.degree(u)];
		});

		// exclusive prefix sum
		index tmp = nodePos[0];
		index sum = tmp;
		nodePos[0] = 0;

		for (index i = 1; i < nodePos.size(); ++i) {
			tmp = nodePos[i];
			nodePos[i] = sum;
			sum += tmp;
		}

		G.forNodes([&](node u) {
			sortedNodes[nodePos[n - G.degree(u)]++] = u;
		});
	}

	for (node u : sortedNodes) {
		//Mark all neighbors
		for (auto v : edges[u]) {
			nodeMarker[v] = true;
		}

		//For all neighbors: check for already marked neighbors.
		for (auto v : edges[u]) {
			for (auto w = edges[v].begin(); w != edges[v].end(); ++w) {
				// delete the edge to u as we do not need to consider it again.
				// the opposite edge doesn't need to be deleted as we will never again consider
				// outgoing edges of u as u cannot be reached anymore after the uv loop.
				if (*w == u) {
					// move last element to current position in order to avoid changing too much
					*w = edges[v].back();
					edges[v].pop_back();
					if (w == edges[v].end()) // break if we were at the last element already
						break;
				}

				if (nodeMarker[*w]) { // triangle found - count it!
					++triangleCount[u];
					++triangleCount[*w];
					++triangleCount[v];
				}
			}

			nodeMarker[v] = false; // all triangles with u and v have been counted already
		}
	}

	double coefficient = 0;
	count size = 0;
	G.forNodes([&](node u) {
		count d = G.degree(u);
		if (d > 1) {
			coefficient += triangleCount[u] * 2.0 / (d * (d - 1));
			size++;
		}
	});

	return coefficient / size;
}
nsresult
nsXFormsMDGEngine::Rebuild()
{
#ifdef DEBUG_XF_MDG
  printf("nsXFormsMDGEngine::Rebuild()\n");
#endif
  nsresult rv = NS_OK;
  mJustRebuilt = PR_TRUE;
  mFirstCalculate = PR_FALSE;

  mGraph.Clear();
  mNodeStates.Clear();

  nsDeque sortedNodes(nsnull);

#ifdef DEBUG_XF_MDG
  printf("\tmNodesInGraph: %d\n", mNodesInGraph);
  printf("\tmNodeToMDG:    %d\n", mNodeToMDG.Count());
  printf("\tmNodeStates:   %d\n", mNodeStates.Count());
#endif

  // Initial scan for nsXFormsMDGNodes with no dependencies (mCount == 0)
  PRUint32 entries = mNodeToMDG.EnumerateRead(AddStartNodes, &sortedNodes);
  if (entries != mNodeToMDG.Count()) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

#ifdef DEBUG_XF_MDG
  printf("\tStartNodes:    %d\n", sortedNodes.GetSize());
#endif
  
  
  nsXFormsMDGNode* node;
  while ((node = static_cast<nsXFormsMDGNode*>(sortedNodes.Pop()))) {
    for (PRInt32 i = 0; i < node->mSuc.Count(); ++i) {
      nsXFormsMDGNode* sucNode = static_cast<nsXFormsMDGNode*>
                                            (node->mSuc[i]);
      NS_ASSERTION(sucNode, "XForms: NULL successor node");

      sucNode->mCount--;
      if (sucNode->mCount == 0) {
        sortedNodes.Push(sucNode);
      }
    }

    node->MarkDirty();

    if (!mGraph.AppendElement(node)) {
      return NS_ERROR_OUT_OF_MEMORY;
    }
  }

#ifdef DEBUG_XF_MDG
    printf("\tmGraph.Count() = %2d\n", mGraph.Count());
    printf("\tmNodesInGraph  = %2d\n", mNodesInGraph);
#endif

  if (mGraph.Count() != mNodesInGraph) {
    nsCOMPtr<nsIDOMElement> modelElement;
    if (mModel) {
      modelElement = mModel->GetDOMElement();
    }
    nsXFormsUtils::ReportError(NS_LITERAL_STRING("MDGLoopError"), modelElement);
    rv = NS_ERROR_ABORT;
  }

  mNodesInGraph = 0;

  return rv;
}