Dynamic chunk sizing

Introducing `Doxport\Util\Chunk`:

The contract is:
 - The caller provides an initial estimate of the chunk size
 - The caller provides a *target* (wallclock) time, each chunk should take about this long to perform
 - The critical/timed section is wrapped in `begin()`/`end()` calls
 
Given this, `getEstimatedSize()` will return a suitable exponentially-weighted moving average of the size of chunk to attempt. The size estimate will vary to try and keep the time taken within the critical section to the target.