// Path: berserker-commons/src/main/java/io/smartcat/berserker/api/RateGenerator.java
// public interface RateGenerator {
// 
//     /**
//      * Returns rate per second as a function of time.
//      *
//      * @param time Relative time in nanoseconds from starting load generator.
//      * @return Rate per second as a function of time.
//      */
//     double getRate(long time);
// }
// 
// Path: berserker-core/src/main/java/io/smartcat/berserker/rategenerator/ConstantRateGenerator.java
// public class ConstantRateGenerator implements RateGenerator {
// 
//     private final double perSecondRate;
// 
//     /**
//      * Constructs rate generator with specified <code>perSecondRate</code>.
//      *
//      * @param perSecondRate Rate of the rate generator per second, must be positive number.
//      */
//     public ConstantRateGenerator(double perSecondRate) {
//         if (perSecondRate <= 0) {
//             throw new IllegalArgumentException("Rate must be positive number.");
//         }
//         this.perSecondRate = perSecondRate;
//     }
// 
//     @Override
//     public double getRate(long time) {
//         return perSecondRate;
//     }
// }
// 
// Path: berserker-core/src/main/java/io/smartcat/berserker/rategenerator/RateGeneratorProxy.java
// public class RateGeneratorProxy implements RateGenerator {
// 
//     private RateGenerator delegate;
// 
//     /**
//      * Constructs proxy without delegate.
//      */
//     public RateGeneratorProxy() {
//     }
// 
//     /**
//      * Constructs proxy with specified <code>delegate</code>.
//      *
//      * @param delegate Value which will be evaluated and cached.
//      */
//     public RateGeneratorProxy(RateGenerator delegate) {
//         setDelegate(delegate);
//     }
// 
//     /**
//      * Sets value to this proxy.
//      *
//      * @param delegate Value which will be evaluated and cached.
//      */
//     public void setDelegate(RateGenerator delegate) {
//         if (delegate == null) {
//             throw new IllegalArgumentException("Delegate cannot be null.");
//         }
//         this.delegate = delegate;
//     }
// 
//     @Override
//     public double getRate(long time) {
//         checkDelegate();
//         return delegate.getRate(time);
//     }
// 
//     private void checkDelegate() {
//         if (delegate == null) {
//             throw new DelegateNotSetException();
//         }
//     }
// 
//     /**
//      * Signals that delegate is not set.
//      */
//     public static class DelegateNotSetException extends RuntimeException {
// 
//         private static final long serialVersionUID = 6257779717961934851L;
// 
//         /**
//          * Constructs {@link DelegateNotSetException} with default message.
//          */
//         public DelegateNotSetException() {
//             super("Delegate not set for ValueProxy.");
//         }
//     }
// }


import io.smartcat.berserker.api.RateGenerator;
import io.smartcat.berserker.rategenerator.ConstantRateGenerator;
import io.smartcat.berserker.rategenerator.RateGeneratorProxy;
import org.parboiled.Parboiled;
import org.parboiled.parserunners.ReportingParseRunner;
import org.parboiled.support.ParsingResult;
import java.util.HashMap;
import java.util.Map;
     */
    @SuppressWarnings("unchecked")
    public RateGeneratorConfigurationParser(Map<String, Object> config) {
        checkSectionExistence(config, RATES);
        checkSectionExistence(config, OUTPUT);
        this.rates = (Map<String, Object>) config.get(RATES);
        this.outputExpression = config.get(OUTPUT);
    }

    /**
     * Creates an instance of {@link RateGenerator} based on provided configuration.
     *
     * @return An instance of {@link RateGenerator}.
     */
    @SuppressWarnings({ "unchecked" })
    public RateGenerator build() {
        buildModel();
        return parseRateGeneratorExpression(outputExpression);
    }

    private void buildModel() {
        this.proxyValues = new HashMap<>();
        this.parser = Parboiled.createParser(RateGeneratorExpressionParser.class, proxyValues);
        this.parseRunner = new ReportingParseRunner<>(parser.rateGenerator());
        if (rates != null) {
            createProxies();
            parseRateGenerators();
        }
    }

// Path: berserker-commons/src/main/java/io/smartcat/berserker/api/RateGenerator.java
// public interface RateGenerator {
// 
//     /**
//      * Returns rate per second as a function of time.
//      *
//      * @param time Relative time in nanoseconds from starting load generator.
//      * @return Rate per second as a function of time.
//      */
//     double getRate(long time);
// }
// 
// Path: berserker-core/src/main/java/io/smartcat/berserker/rategenerator/ConstantRateGenerator.java
// public class ConstantRateGenerator implements RateGenerator {
// 
//     private final double perSecondRate;
// 
//     /**
//      * Constructs rate generator with specified <code>perSecondRate</code>.
//      *
//      * @param perSecondRate Rate of the rate generator per second, must be positive number.
//      */
//     public ConstantRateGenerator(double perSecondRate) {
//         if (perSecondRate <= 0) {
//             throw new IllegalArgumentException("Rate must be positive number.");
//         }
//         this.perSecondRate = perSecondRate;
//     }
// 
//     @Override
//     public double getRate(long time) {
//         return perSecondRate;
//     }
// }
// 
// Path: berserker-core/src/main/java/io/smartcat/berserker/rategenerator/RateGeneratorProxy.java
// public class RateGeneratorProxy implements RateGenerator {
// 
//     private RateGenerator delegate;
// 
//     /**
//      * Constructs proxy without delegate.
//      */
//     public RateGeneratorProxy() {
//     }
// 
//     /**
//      * Constructs proxy with specified <code>delegate</code>.
//      *
//      * @param delegate Value which will be evaluated and cached.
//      */
//     public RateGeneratorProxy(RateGenerator delegate) {
//         setDelegate(delegate);
//     }
// 
//     /**
//      * Sets value to this proxy.
//      *
//      * @param delegate Value which will be evaluated and cached.
//      */
//     public void setDelegate(RateGenerator delegate) {
//         if (delegate == null) {
//             throw new IllegalArgumentException("Delegate cannot be null.");
//         }
//         this.delegate = delegate;
//     }
// 
//     @Override
//     public double getRate(long time) {
//         checkDelegate();
//         return delegate.getRate(time);
//     }
// 
//     private void checkDelegate() {
//         if (delegate == null) {
//             throw new DelegateNotSetException();
//         }
//     }
// 
//     /**
//      * Signals that delegate is not set.
//      */
//     public static class DelegateNotSetException extends RuntimeException {
// 
//         private static final long serialVersionUID = 6257779717961934851L;
// 
//         /**
//          * Constructs {@link DelegateNotSetException} with default message.
//          */
//         public DelegateNotSetException() {
//             super("Delegate not set for ValueProxy.");
//         }
//     }
// }


// Path: berserker-core/src/main/java/io/smartcat/berserker/configuration/rategenerator/RateGeneratorConfigurationParser.java
import io.smartcat.berserker.api.RateGenerator;
import io.smartcat.berserker.rategenerator.ConstantRateGenerator;
import io.smartcat.berserker.rategenerator.RateGeneratorProxy;
import org.parboiled.Parboiled;
import org.parboiled.parserunners.ReportingParseRunner;
import org.parboiled.support.ParsingResult;
import java.util.HashMap;
import java.util.Map;

     */
    @SuppressWarnings("unchecked")
    public RateGeneratorConfigurationParser(Map<String, Object> config) {
        checkSectionExistence(config, RATES);
        checkSectionExistence(config, OUTPUT);
        this.rates = (Map<String, Object>) config.get(RATES);
        this.outputExpression = config.get(OUTPUT);
    }

    /**
     * Creates an instance of {@link RateGenerator} based on provided configuration.
     *
     * @return An instance of {@link RateGenerator}.
     */
    @SuppressWarnings({ "unchecked" })
    public RateGenerator build() {
        buildModel();
        return parseRateGeneratorExpression(outputExpression);
    }

    private void buildModel() {
        this.proxyValues = new HashMap<>();
        this.parser = Parboiled.createParser(RateGeneratorExpressionParser.class, proxyValues);
        this.parseRunner = new ReportingParseRunner<>(parser.rateGenerator());
        if (rates != null) {
            createProxies();
            parseRateGenerators();
        }
    }

    private void checkSectionExistence(Map<String, Object> config, String name) {