diff --git a/pom.xml b/pom.xml
index 72a12bd8..bee16a7f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
net.iponweb.disthene.reader
disthene-reader
jar
- 2.0.7
+ 2.0.8
disthene-reader
http://maven.apache.org
diff --git a/src/main/java/net/iponweb/disthene/reader/graphite/functions/MinMaxFunction.java b/src/main/java/net/iponweb/disthene/reader/graphite/functions/MinMaxFunction.java
new file mode 100644
index 00000000..fb2235c3
--- /dev/null
+++ b/src/main/java/net/iponweb/disthene/reader/graphite/functions/MinMaxFunction.java
@@ -0,0 +1,59 @@
+package net.iponweb.disthene.reader.graphite.functions;
+
+import net.iponweb.disthene.reader.beans.TimeSeries;
+import net.iponweb.disthene.reader.exceptions.EvaluationException;
+import net.iponweb.disthene.reader.exceptions.InvalidArgumentException;
+import net.iponweb.disthene.reader.exceptions.TimeSeriesNotAlignedException;
+import net.iponweb.disthene.reader.graphite.Target;
+import net.iponweb.disthene.reader.graphite.evaluation.TargetEvaluator;
+import net.iponweb.disthene.reader.utils.CollectionUtils;
+import net.iponweb.disthene.reader.utils.TimeSeriesUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Andrei Ivanov
+ */
+public class MinMaxFunction extends DistheneFunction {
+
+ public MinMaxFunction(String text) {
+ super(text, "minMax");
+ }
+
+ @Override
+ public List evaluate(TargetEvaluator evaluator) throws EvaluationException {
+ List processedArguments = new ArrayList<>(evaluator.eval((Target) arguments.get(0)));
+
+ if (processedArguments.size() == 0) return new ArrayList<>();
+
+ if (!TimeSeriesUtils.checkAlignment(processedArguments)) {
+ throw new TimeSeriesNotAlignedException();
+ }
+
+ int length = processedArguments.get(0).getValues().length;
+
+ for (TimeSeries ts : processedArguments) {
+ Double min = CollectionUtils.min(Arrays.asList(ts.getValues()));
+ Double max = CollectionUtils.max(Arrays.asList(ts.getValues()));
+ if (min != null && max != null) {
+ double range = max - min;
+ for (int i = 0; i < length; i++) {
+ if (ts.getValues()[i] != null ) {
+ ts.getValues()[i] = (ts.getValues()[i] - min) / range;
+ }
+ }
+ }
+ setResultingName(ts);
+ }
+
+ return processedArguments;
+ }
+
+ @Override
+ public void checkArguments() throws InvalidArgumentException {
+ if (arguments.size() != 1) throw new InvalidArgumentException("minMax: number of arguments is " + arguments.size() + ". Must be one.");
+ if (!(arguments.get(0) instanceof Target)) throw new InvalidArgumentException("minMax: argument is " + arguments.get(0).getClass().getName() + ". Must be series");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/iponweb/disthene/reader/graphite/functions/registry/FunctionRegistry.java b/src/main/java/net/iponweb/disthene/reader/graphite/functions/registry/FunctionRegistry.java
index 4cb93712..f069d3e6 100644
--- a/src/main/java/net/iponweb/disthene/reader/graphite/functions/registry/FunctionRegistry.java
+++ b/src/main/java/net/iponweb/disthene/reader/graphite/functions/registry/FunctionRegistry.java
@@ -73,6 +73,7 @@ public class FunctionRegistry {
registry.put("maximumBelow", MaximumBelowFunction.class);
registry.put("minimumAbove", MinimumAboveFunction.class);
registry.put("minimumBelow", MinimumBelowFunction.class);
+ registry.put("minMax", MinMaxFunction.class);
registry.put("maxSeries", MaxSeriesFunction.class);
registry.put("minSeries", MinSeriesFunction.class);
registry.put("mostDeviant", MostDeviantFunction.class);