docs: function topologicalSort(graph) {
      const allNodes = {}, outgoingEdgeCount = {}, inverseEdges = {};
      Object.keys(graph).forEach((fromNode) => {
          allNodes[fromNode] = true;
          outgoingEdgeCount[fromNode] = graph[fromNode].length;
          graph[fromNode].forEach((toNode) => {
              allNodes[toNode] = true;
              outgoingEdgeCount[toNode] = outgoingEdgeCount[toNode] || 0;
              inverseEdges[toNode] = inverseEdges[toNode] || [];
              inverseEdges[toNode].push(fromNode);
          });
      });
      // https://en.wikipedia.org/wiki/Topological_sorting
      const S = [], L = [];
      Object.keys(allNodes).forEach((node) => {
          if (outgoingEdgeCount[node] === 0) {
              delete outgoingEdgeCount[node];
              S.push(node);
          }
      });
      while (S.length > 0) {
          // Ensure the exact same order all the time with the same inputs
          S.sort();
          const n = S.shift();
          L.push(n);
          const myInverseEdges = inverseEdges[n] || [];
          myInverseEdges.forEach((m) => {
              outgoingEdgeCount[m]--;
              if (outgoingEdgeCount[m] === 0) {
                  delete outgoingEdgeCount[m];
                  S.push(m);
              }
          });
      }
      if (Object.keys(outgoingEdgeCount).length > 0) {
          throw new Error('Cannot do topological sort on cyclic graph, remaining nodes: ' + Object.keys(outgoingEdgeCount));
      }
      return L;
  }