offset = $offset; return $this; } public function setFrequency($frequency) { if (!is_int($frequency)) { throw new Exception(pht('Metronome frequency must be an integer.')); } if ($frequency < 1) { throw new Exception(pht('Metronome frequency must be 1 or more.')); } $this->frequency = $frequency; return $this; } public function setOffsetFromSeed($seed) { $offset = PhabricatorHash::digestToRange($seed, 0, 0x7FFFFFFF); return $this->setOffset($offset); } public function getFrequency() { if ($this->frequency === null) { throw new PhutilInvalidStateException('setFrequency'); } return $this->frequency; } public function getOffset() { $frequency = $this->getFrequency(); return ($this->offset % $frequency); } public function getNextTickAfter($epoch) { $frequency = $this->getFrequency(); $offset = $this->getOffset(); $remainder = ($epoch % $frequency); if ($remainder < $offset) { return ($epoch - $remainder) + $offset; } else { return ($epoch - $remainder) + $frequency + $offset; } } public function didTickBetween($min, $max) { if ($max < $min) { throw new Exception( pht( 'Maximum tick window must not be smaller than minimum tick window.')); } $next = $this->getNextTickAfter($min); return ($next <= $max); } }