// returns (timer, estimated firing time) or null static Pair nextFiringTimerInVM() { L timers = allTimersInVM(); long time = now(); new Lowest best; for (O timer : timers) pcall { for (O entry : unnull((Collection) getOpt(timer, 'entries))) { Long firstTime = cast getOpt(entry, 'firstTime); Long period = cast getOpt(entry, 'period); if (firstTime != null && period != null) if (time >= firstTime) best.put(period-((time - firstTime) % period), timer); } } ret best.has() ? pair(best!, time+best.getScore()) : null; }