// Path: misc/src/main/java/at/willhaben/willtest/misc/utils/WhFluentWait.java
// public class WhFluentWait<T> extends FluentWait<T> {
// 
//     public WhFluentWait(T input) {
//         super(input);
//     }
// 
//     public WhFluentWait(T input, Clock clock, Sleeper sleeper) {
//         super(input, clock, sleeper);
//     }
// 
//     /**
//      * Waits until the given condition is met. Throws an {@link AssertionError} instead of a {@link TimeoutException}
//      * when the condition fails because the error is known.
//      * @param errorMessage concrete error message describing the failure
//      * @param isTrue the parameter to pass to the {@link ExpectedCondition}
//      * @param <V> The function's expected return type.
//      * @return The function's return value if the function returned something different
//      *         from null or false before the timeout expired.
//      * @throws AssertionError if the timeout expires
//      */
//     public <V> V until(String errorMessage, Function<? super T, V> isTrue) {
//         try {
//             return super.until(isTrue);
//         } catch (TimeoutException e) {
//             if (Objects.nonNull(errorMessage) && !"".equals(errorMessage)) {
//                 throw new AssertionError(errorMessage, e);
//             } else {
//                 //Regex replacing parts that hinder allure from grouping erros in the report when using "require" without custom error messages
//                 throw new TimeoutException(e.getMessage().replaceAll("Build info:(?:.+\\s+)*Driver info:.+",""), e.getCause());
//             }
//         }
//     }
// 
//     @Override
//     public <V> V until(Function<? super T, V> isTrue) {
//         return super.until(isTrue);
//     }
// }
// 
// Path: misc/src/main/java/at/willhaben/willtest/misc/utils/XPathOrCssUtil.java
// public class XPathOrCssUtil {
// 
//     /**
//      * Generates a {@link By}. Checks for the first character in the string. A leading '/' generates a
//      * {@link By#xpath(String)} otherwise a {@link By#cssSelector(String)}.
//      * @param xPathOrCss locator string
//      * @return locator for selenium
//      */
//     public static By mapToBy(String xPathOrCss) {
//         if (xPathOrCss.startsWith("/")) {
//             return By.xpath(xPathOrCss);
//         } else {
//             return By.cssSelector(xPathOrCss);
//         }
//     }
// }


import at.willhaben.willtest.misc.utils.WhFluentWait;
import at.willhaben.willtest.misc.utils.XPathOrCssUtil;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.FluentWait;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.function.Predicate;

    /**
     * Used to check if an element is available or visible.
     * @param by locator of the element to check
     * @return Builder for checking appearance of element.
     */
    public IsAvailableBuilder is(By by) {
        return new IsAvailableBuilder(this, by);
    }

    /**
     * Same as {@link #getWait(long)} with a default wait of {@value DEFAULT_WAIT_TIMEOUT} seconds.
     * @return
     */
    protected WhFluentWait<WebDriver> getWait() {
        return getWait(DEFAULT_WAIT_TIMEOUT);
    }

    /**
     * Generates a default {@link FluentWait} which ignores {@link NoSuchElementException} and
     * {@link StaleElementReferenceException}. Polls every 250 milliseconds.
     * @param timeout Timeout in seconds
     * @return Waiter
     */
    protected WhFluentWait<WebDriver> getWait(long timeout) {
        return getWait(Duration.ofSeconds(timeout), Duration.ofMillis(250L));
    }

    protected WhFluentWait<WebDriver> getWait(Duration waitFor, Duration polling) {
        return (WhFluentWait<WebDriver>) new WhFluentWait<>(driver)
// Path: misc/src/main/java/at/willhaben/willtest/misc/utils/WhFluentWait.java
// public class WhFluentWait<T> extends FluentWait<T> {
// 
//     public WhFluentWait(T input) {
//         super(input);
//     }
// 
//     public WhFluentWait(T input, Clock clock, Sleeper sleeper) {
//         super(input, clock, sleeper);
//     }
// 
//     /**
//      * Waits until the given condition is met. Throws an {@link AssertionError} instead of a {@link TimeoutException}
//      * when the condition fails because the error is known.
//      * @param errorMessage concrete error message describing the failure
//      * @param isTrue the parameter to pass to the {@link ExpectedCondition}
//      * @param <V> The function's expected return type.
//      * @return The function's return value if the function returned something different
//      *         from null or false before the timeout expired.
//      * @throws AssertionError if the timeout expires
//      */
//     public <V> V until(String errorMessage, Function<? super T, V> isTrue) {
//         try {
//             return super.until(isTrue);
//         } catch (TimeoutException e) {
//             if (Objects.nonNull(errorMessage) && !"".equals(errorMessage)) {
//                 throw new AssertionError(errorMessage, e);
//             } else {
//                 //Regex replacing parts that hinder allure from grouping erros in the report when using "require" without custom error messages
//                 throw new TimeoutException(e.getMessage().replaceAll("Build info:(?:.+\\s+)*Driver info:.+",""), e.getCause());
//             }
//         }
//     }
// 
//     @Override
//     public <V> V until(Function<? super T, V> isTrue) {
//         return super.until(isTrue);
//     }
// }
// 
// Path: misc/src/main/java/at/willhaben/willtest/misc/utils/XPathOrCssUtil.java
// public class XPathOrCssUtil {
// 
//     /**
//      * Generates a {@link By}. Checks for the first character in the string. A leading '/' generates a
//      * {@link By#xpath(String)} otherwise a {@link By#cssSelector(String)}.
//      * @param xPathOrCss locator string
//      * @return locator for selenium
//      */
//     public static By mapToBy(String xPathOrCss) {
//         if (xPathOrCss.startsWith("/")) {
//             return By.xpath(xPathOrCss);
//         } else {
//             return By.cssSelector(xPathOrCss);
//         }
//     }
// }


// Path: misc/src/main/java/at/willhaben/willtest/misc/pages/PageObject.java
import at.willhaben.willtest.misc.utils.WhFluentWait;
import at.willhaben.willtest.misc.utils.XPathOrCssUtil;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.FluentWait;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.function.Predicate;


    /**
     * Used to check if an element is available or visible.
     * @param by locator of the element to check
     * @return Builder for checking appearance of element.
     */
    public IsAvailableBuilder is(By by) {
        return new IsAvailableBuilder(this, by);
    }

    /**
     * Same as {@link #getWait(long)} with a default wait of {@value DEFAULT_WAIT_TIMEOUT} seconds.
     * @return
     */
    protected WhFluentWait<WebDriver> getWait() {
        return getWait(DEFAULT_WAIT_TIMEOUT);
    }

    /**
     * Generates a default {@link FluentWait} which ignores {@link NoSuchElementException} and
     * {@link StaleElementReferenceException}. Polls every 250 milliseconds.
     * @param timeout Timeout in seconds
     * @return Waiter
     */
    protected WhFluentWait<WebDriver> getWait(long timeout) {
        return getWait(Duration.ofSeconds(timeout), Duration.ofMillis(250L));
    }

    protected WhFluentWait<WebDriver> getWait(Duration waitFor, Duration polling) {
        return (WhFluentWait<WebDriver>) new WhFluentWait<>(driver)
                .withTimeout(waitFor)