// Path: src/main/java/io/qameta/htmlelements/context/Context.java
// public class Context {
// 
//     public static final String DESCRIPTION_KEY = "description";
// 
//     public static final String LISTENERS_KEY = "listeners";
// 
//     public static final String PROPERTIES_KEY = "properties";
// 
//     public static final String PARAMETERS_KEY = "parameters";
// 
//     public static final String DRIVER_KEY = "driver";
// 
//     private Context parent;
// 
//     private Store store;
// 
//     private ExtensionRegistry registry;
// 
//     private Context() {
//         this.store = new DefaultStore();
//     }
// 
//     public Optional<Context> getParent() {
//         return Optional.ofNullable(parent);
//     }
// 
//     private void setParent(Context parent) {
//         this.parent = parent;
//     }
// 
//     public Store getStore() {
//         return store;
//     }
// 
//     public ExtensionRegistry getRegistry() {
//         return registry;
//     }
// 
//     private void setRegistry(ExtensionRegistry registry) {
//         this.registry = registry;
//     }
// 
//     public Context newChildContext(Method method, Class<?> proxyClass) {
//         Context childContext = new Context();
//         childContext.getStore().put(DESCRIPTION_KEY, ReflectionUtils.getDescription(method, null));
//         childContext.setRegistry(ExtensionRegistry.create(proxyClass));
//         childContext.getRegistry().registerExtensions(method);
//         childContext.setParent(this);
//         //extension
//         getStore().get(PROPERTIES_KEY, Properties.class).ifPresent(properties -> {
//             Properties child = new Properties();
//             child.putAll(properties);
//             childContext.getStore().put(PROPERTIES_KEY, child);
//         });
//         getStore().get(PARAMETERS_KEY, Properties.class).ifPresent(properties -> {
//             Properties child = new Properties();
//             child.putAll(properties);
//             childContext.getStore().put(PARAMETERS_KEY, child);
//         });
//         getStore().get(LISTENERS_KEY, List.class).ifPresent(listeners -> {
//             childContext.getStore().put(LISTENERS_KEY, listeners);
//         });
//         getStore().get(DRIVER_KEY, WebDriver.class).ifPresent(driver -> {
//             childContext.getStore().put(DRIVER_KEY, driver);
//         });
//         return childContext;
//     }
// 
//     public static Context newWebPageContext(Class<?> webPageClass, WebDriver driver) {
//         Context context = new Context();
//         context.setRegistry(ExtensionRegistry.create(webPageClass));
//         context.getStore().put(DESCRIPTION_KEY, ReflectionUtils.getDescription(webPageClass));
//         context.getStore().put(DRIVER_KEY, driver);
//         return context;
//     }
// 
// 
// }
// 
// Path: src/main/java/io/qameta/htmlelements/statement/RetryStatement.java
// public class RetryStatement implements StatementWrapper {
// 
//     public static final String TIMEOUT_KEY = "retry.timeout";
// 
//     public static final String POLLING_KEY = "retry.polling";
// 
//     private Duration timeout;
// 
//     private Duration polling;
// 
//     private List<Class<? extends Throwable>> ignoring;
// 
//     public RetryStatement(Properties properties) {
//         this.timeout = new Duration(Long.parseLong(properties.getProperty(TIMEOUT_KEY, "5")), TimeUnit.SECONDS);
//         this.polling = new Duration(Long.parseLong(properties.getProperty(POLLING_KEY, "250")), TimeUnit.MILLISECONDS);
//         this.ignoring = new ArrayList<>();
//     }
// 
//     public RetryStatement withTimeout(long time, TimeUnit unit) {
//         this.timeout = new Duration(time, unit);
//         return this;
//     }
// 
//     public RetryStatement pollingEvery(long time, TimeUnit unit) {
//         this.polling = new Duration(time, unit);
//         return this;
//     }
// 
//     @SafeVarargs
//     public final RetryStatement ignoring(Class<? extends Throwable>... exceptionType) {
//         this.ignoring.addAll(Arrays.asList(exceptionType));
//         return this;
//     }
// 
//     @Override
//     public Statement apply(Statement statement) throws Throwable {
//         return () -> {
//             Clock clock = new SystemClock();
//             long end = clock.laterBy(timeout.in(TimeUnit.MILLISECONDS));
//             Throwable lastException;
//             do {
//                 try {
//                     return statement.evaluate();
//                 } catch (Throwable e) {
//                     lastException = e;
//                     if (ignoring.stream().anyMatch(clazz -> clazz.isInstance(e))) {
//                         try {
//                             Thread.sleep(polling.in(TimeUnit.MILLISECONDS));
//                         } catch (InterruptedException i) {
//                             break;
//                         }
//                     } else {
//                         Throwables.propagate(e);
//                     }
//                 }
//             } while ((clock.isNowBefore(end)));
//             throw lastException;
//         };
//     }
// 
// }


import io.qameta.htmlelements.context.Context;
import io.qameta.htmlelements.statement.RetryStatement;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Properties;
package io.qameta.htmlelements.extension;



/**
 * eroshenkoam
 * 22.03.17
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(Retry.Extension.class)
public @interface Retry {

    int timeoutInSeconds() default 5;

    int poolingInMillis() default 250;

    Class<? extends Throwable>[] ignoring() default {};

    class Extension implements ContextEnricher {

        @Override
// Path: src/main/java/io/qameta/htmlelements/context/Context.java
// public class Context {
// 
//     public static final String DESCRIPTION_KEY = "description";
// 
//     public static final String LISTENERS_KEY = "listeners";
// 
//     public static final String PROPERTIES_KEY = "properties";
// 
//     public static final String PARAMETERS_KEY = "parameters";
// 
//     public static final String DRIVER_KEY = "driver";
// 
//     private Context parent;
// 
//     private Store store;
// 
//     private ExtensionRegistry registry;
// 
//     private Context() {
//         this.store = new DefaultStore();
//     }
// 
//     public Optional<Context> getParent() {
//         return Optional.ofNullable(parent);
//     }
// 
//     private void setParent(Context parent) {
//         this.parent = parent;
//     }
// 
//     public Store getStore() {
//         return store;
//     }
// 
//     public ExtensionRegistry getRegistry() {
//         return registry;
//     }
// 
//     private void setRegistry(ExtensionRegistry registry) {
//         this.registry = registry;
//     }
// 
//     public Context newChildContext(Method method, Class<?> proxyClass) {
//         Context childContext = new Context();
//         childContext.getStore().put(DESCRIPTION_KEY, ReflectionUtils.getDescription(method, null));
//         childContext.setRegistry(ExtensionRegistry.create(proxyClass));
//         childContext.getRegistry().registerExtensions(method);
//         childContext.setParent(this);
//         //extension
//         getStore().get(PROPERTIES_KEY, Properties.class).ifPresent(properties -> {
//             Properties child = new Properties();
//             child.putAll(properties);
//             childContext.getStore().put(PROPERTIES_KEY, child);
//         });
//         getStore().get(PARAMETERS_KEY, Properties.class).ifPresent(properties -> {
//             Properties child = new Properties();
//             child.putAll(properties);
//             childContext.getStore().put(PARAMETERS_KEY, child);
//         });
//         getStore().get(LISTENERS_KEY, List.class).ifPresent(listeners -> {
//             childContext.getStore().put(LISTENERS_KEY, listeners);
//         });
//         getStore().get(DRIVER_KEY, WebDriver.class).ifPresent(driver -> {
//             childContext.getStore().put(DRIVER_KEY, driver);
//         });
//         return childContext;
//     }
// 
//     public static Context newWebPageContext(Class<?> webPageClass, WebDriver driver) {
//         Context context = new Context();
//         context.setRegistry(ExtensionRegistry.create(webPageClass));
//         context.getStore().put(DESCRIPTION_KEY, ReflectionUtils.getDescription(webPageClass));
//         context.getStore().put(DRIVER_KEY, driver);
//         return context;
//     }
// 
// 
// }
// 
// Path: src/main/java/io/qameta/htmlelements/statement/RetryStatement.java
// public class RetryStatement implements StatementWrapper {
// 
//     public static final String TIMEOUT_KEY = "retry.timeout";
// 
//     public static final String POLLING_KEY = "retry.polling";
// 
//     private Duration timeout;
// 
//     private Duration polling;
// 
//     private List<Class<? extends Throwable>> ignoring;
// 
//     public RetryStatement(Properties properties) {
//         this.timeout = new Duration(Long.parseLong(properties.getProperty(TIMEOUT_KEY, "5")), TimeUnit.SECONDS);
//         this.polling = new Duration(Long.parseLong(properties.getProperty(POLLING_KEY, "250")), TimeUnit.MILLISECONDS);
//         this.ignoring = new ArrayList<>();
//     }
// 
//     public RetryStatement withTimeout(long time, TimeUnit unit) {
//         this.timeout = new Duration(time, unit);
//         return this;
//     }
// 
//     public RetryStatement pollingEvery(long time, TimeUnit unit) {
//         this.polling = new Duration(time, unit);
//         return this;
//     }
// 
//     @SafeVarargs
//     public final RetryStatement ignoring(Class<? extends Throwable>... exceptionType) {
//         this.ignoring.addAll(Arrays.asList(exceptionType));
//         return this;
//     }
// 
//     @Override
//     public Statement apply(Statement statement) throws Throwable {
//         return () -> {
//             Clock clock = new SystemClock();
//             long end = clock.laterBy(timeout.in(TimeUnit.MILLISECONDS));
//             Throwable lastException;
//             do {
//                 try {
//                     return statement.evaluate();
//                 } catch (Throwable e) {
//                     lastException = e;
//                     if (ignoring.stream().anyMatch(clazz -> clazz.isInstance(e))) {
//                         try {
//                             Thread.sleep(polling.in(TimeUnit.MILLISECONDS));
//                         } catch (InterruptedException i) {
//                             break;
//                         }
//                     } else {
//                         Throwables.propagate(e);
//                     }
//                 }
//             } while ((clock.isNowBefore(end)));
//             throw lastException;
//         };
//     }
// 
// }


// Path: src/main/java/io/qameta/htmlelements/extension/Retry.java
import io.qameta.htmlelements.context.Context;
import io.qameta.htmlelements.statement.RetryStatement;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Properties;

package io.qameta.htmlelements.extension;



/**
 * eroshenkoam
 * 22.03.17
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(Retry.Extension.class)
public @interface Retry {

    int timeoutInSeconds() default 5;

    int poolingInMillis() default 250;

    Class<? extends Throwable>[] ignoring() default {};

    class Extension implements ContextEnricher {

        @Override
        public void enrich(Context context, Method method, Object[] args) {