public UpgradePlan getUpgradePlan(Integer ver0, Integer ver1)
{
	// Init our bookkeeping data structure
	int n = versions.size();
	PNode[] pnodes = new PNode[n];
	Map<Integer,PNode> map = new TreeMap();
	int i=0;
	for (Integer ver : versions) {
		PNode pn = new PNode();
			pn.version = ver;
			pn.ix = i;
			pn.d = Integer.MAX_VALUE;
			pn.info = nodes.get(ver);
		pnodes[i] = pn;
		map.put(ver, pn);
		++i;
	}
	SortedSet<PNode> S = new TreeSet();
	SortedSet<PNode> Q = new TreeSet();

System.out.println("start: ver0 = " + ver0);
	PNode start = map.get(ver0);
	if (start == null) return null;		// ver0 just doesn't exist, cannot make an upgrade plan starting from it.
	Q.add(start);
	start.d = 0;

	while (Q.size() > 0) {
		// Extract-minimum of Q
		PNode u = Q.first();
		Q.remove(u);
		
		// Add u to S
		S.add(u);
		
		// relax-neighbors
		for (Upgrader up : u.info) {
			PNode v = map.get(up.version1());
			if (S.contains(v)) continue;
			if (v.d > u.d + 1) {
				v.d = u.d + 1;
				v.pred = u;
				v.predUpgrader = up;
				Q.add(v);
			}
		}
	}
	
	
	// Extract the answer
	LinkedList<Upgrader> path = new LinkedList();
	for (PNode v = map.get(ver1); v != start; v = v.pred) {
		if (v == null) return null;		// We didn't find a path.
		path.addFirst(v.predUpgrader);
	}

	Upgrader[] ret = new Upgrader[path.size()];
	path.toArray(ret);
	if (ret == null) return null;
	UpgradePlan uplan = new UpgradePlan(ret);
	return uplan;
}