// Path: xvfb-manager/src/main/java/com/github/mike10004/xvfbmanager/Poller.java
// public static class PollOutcome<E> {
// 
//     /**
//      * Reason polling stopped.
//      */
//     public final StopReason reason;
// 
//     /**
//      * An object that represents the resolved state of the poll.
//      */
//     public final @Nullable E content;
// 
//     /**
//      * Gets the polling duration. This may not be exact.
//      */
//     public final Duration duration;
// 
//     private final int numAttempts;
// 
//     private PollOutcome(StopReason reason, @Nullable E content, Duration duration, int numAttempts) {
//         this.reason = checkNotNull(reason);
//         this.content = content;
//         this.duration = checkNotNull(duration);
//         this.numAttempts = numAttempts;
//     }
// 
//     @Override
//     public String toString() {
//         return "PollOutcome{" +
//                 "reason=" + reason +
//                 ", content=" + content +
//                 ", duration=" + duration +
//                 ", attempts=" + numAttempts +
//                 '}';
//     }
// 
//     /**
//      * Gets the number of times the poll was attempted. This is the numbef of
//      * times the {@link #check(int) check()} function is invoked.
//      * @return count of attempts
//      */
//     public int getNumAttempts() {
//         return numAttempts;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         PollOutcome<?> that = (PollOutcome<?>) o;
// 
//         if (numAttempts != that.numAttempts) return false;
//         if (reason != that.reason) return false;
//         if (content != null ? !content.equals(that.content) : that.content != null) return false;
//         return duration.equals(that.duration);
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = reason.hashCode();
//         result = 31 * result + (content != null ? content.hashCode() : 0);
//         result = 31 * result + duration.hashCode();
//         result = 31 * result + numAttempts;
//         return result;
//     }
// }
// 
// Path: xvfb-manager/src/main/java/com/github/mike10004/xvfbmanager/Poller.java
// public enum StopReason {
// 
//     /**
//      * State was resolved to the poller's satisfaction.
//      */
//     RESOLVED,
// 
//     /**
//      * State was not resolved to the poller's satisfaction,
//      * but polling must cease anyway.
//      */
//     ABORTED,
// 
//     /**
//      * The poller's iterator of intervals was exhausted
//      * prior to resolution or abortion of polling.
//      */
//     TIMEOUT
// }


import com.github.mike10004.xvfbmanager.Poller.PollOutcome;
import com.github.mike10004.xvfbmanager.Poller.StopReason;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.primitives.Ints;
import java.io.File;
import java.io.IOException;
import static com.google.common.base.Preconditions.checkNotNull;
        this.pollIntervalMs = pollIntervalMs;
        this.sleeper = sleeper;
        this.lockFileUtility = checkNotNull(lockFileUtility);
    }

    @Override
    public void waitForCleanup(String display, long timeoutMs) throws LockFileCheckingException {
        File lockFile;
        try {
            lockFile = lockFileUtility.constructLockFilePathname(display);
        } catch (IOException e) {
            throw new LockFileCheckingException(e);
        }
        int maxNumPolls = Ints.checkedCast(Math.round(Math.ceil((float) timeoutMs / (float) pollIntervalMs)));
        long startTime = System.currentTimeMillis();
        PollOutcome<?> pollOutcome;
        try {
            pollOutcome = new Poller<Void>(sleeper) {
                @Override
                protected PollAnswer<Void> check(int pollAttemptsSoFar) {
                    long now = System.currentTimeMillis();
                    if (now - startTime > timeoutMs) {
                        return abortPolling();
                    }
                    return lockFile.exists() ? continuePolling() : resolve(null);
                }
            }.poll(pollIntervalMs, maxNumPolls);
        } catch (InterruptedException e) {
            throw new LockFileCheckingException(e);
        }
// Path: xvfb-manager/src/main/java/com/github/mike10004/xvfbmanager/Poller.java
// public static class PollOutcome<E> {
// 
//     /**
//      * Reason polling stopped.
//      */
//     public final StopReason reason;
// 
//     /**
//      * An object that represents the resolved state of the poll.
//      */
//     public final @Nullable E content;
// 
//     /**
//      * Gets the polling duration. This may not be exact.
//      */
//     public final Duration duration;
// 
//     private final int numAttempts;
// 
//     private PollOutcome(StopReason reason, @Nullable E content, Duration duration, int numAttempts) {
//         this.reason = checkNotNull(reason);
//         this.content = content;
//         this.duration = checkNotNull(duration);
//         this.numAttempts = numAttempts;
//     }
// 
//     @Override
//     public String toString() {
//         return "PollOutcome{" +
//                 "reason=" + reason +
//                 ", content=" + content +
//                 ", duration=" + duration +
//                 ", attempts=" + numAttempts +
//                 '}';
//     }
// 
//     /**
//      * Gets the number of times the poll was attempted. This is the numbef of
//      * times the {@link #check(int) check()} function is invoked.
//      * @return count of attempts
//      */
//     public int getNumAttempts() {
//         return numAttempts;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         PollOutcome<?> that = (PollOutcome<?>) o;
// 
//         if (numAttempts != that.numAttempts) return false;
//         if (reason != that.reason) return false;
//         if (content != null ? !content.equals(that.content) : that.content != null) return false;
//         return duration.equals(that.duration);
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = reason.hashCode();
//         result = 31 * result + (content != null ? content.hashCode() : 0);
//         result = 31 * result + duration.hashCode();
//         result = 31 * result + numAttempts;
//         return result;
//     }
// }
// 
// Path: xvfb-manager/src/main/java/com/github/mike10004/xvfbmanager/Poller.java
// public enum StopReason {
// 
//     /**
//      * State was resolved to the poller's satisfaction.
//      */
//     RESOLVED,
// 
//     /**
//      * State was not resolved to the poller's satisfaction,
//      * but polling must cease anyway.
//      */
//     ABORTED,
// 
//     /**
//      * The poller's iterator of intervals was exhausted
//      * prior to resolution or abortion of polling.
//      */
//     TIMEOUT
// }


// Path: xvfb-manager/src/main/java/com/github/mike10004/xvfbmanager/PollingXLockFileChecker.java
import com.github.mike10004.xvfbmanager.Poller.PollOutcome;
import com.github.mike10004.xvfbmanager.Poller.StopReason;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.primitives.Ints;
import java.io.File;
import java.io.IOException;
import static com.google.common.base.Preconditions.checkNotNull;

        this.pollIntervalMs = pollIntervalMs;
        this.sleeper = sleeper;
        this.lockFileUtility = checkNotNull(lockFileUtility);
    }

    @Override
    public void waitForCleanup(String display, long timeoutMs) throws LockFileCheckingException {
        File lockFile;
        try {
            lockFile = lockFileUtility.constructLockFilePathname(display);
        } catch (IOException e) {
            throw new LockFileCheckingException(e);
        }
        int maxNumPolls = Ints.checkedCast(Math.round(Math.ceil((float) timeoutMs / (float) pollIntervalMs)));
        long startTime = System.currentTimeMillis();
        PollOutcome<?> pollOutcome;
        try {
            pollOutcome = new Poller<Void>(sleeper) {
                @Override
                protected PollAnswer<Void> check(int pollAttemptsSoFar) {
                    long now = System.currentTimeMillis();
                    if (now - startTime > timeoutMs) {
                        return abortPolling();
                    }
                    return lockFile.exists() ? continuePolling() : resolve(null);
                }
            }.poll(pollIntervalMs, maxNumPolls);
        } catch (InterruptedException e) {
            throw new LockFileCheckingException(e);
        }
        if (pollOutcome.reason == StopReason.ABORTED || pollOutcome.reason == StopReason.TIMEOUT) {