API-level modelling for ranges for charges.
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java b/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
index f04545b..1adcc04 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
@@ -132,6 +132,48 @@
   Boolean getProductEnabled(@PathVariable("productidentifier") final String productIdentifier);
 
   @RequestMapping(
+      value = "/products/{productidentifier}/balancesegmentsets/",
+      method = RequestMethod.POST,
+      produces = MediaType.APPLICATION_JSON_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsException(status = HttpStatus.CONFLICT, exception = ProductInUseException.class)
+  void createBalanceSegmentSet(
+      @PathVariable("productidentifier") final String productIdentifier,
+      final BalanceSegmentSet balanceSegmentSet);
+
+  @RequestMapping(
+      value = "/products/{productidentifier}/balancesegmentsets/{balancesegmentsetidentifier}",
+      method = RequestMethod.GET,
+      produces = MediaType.ALL_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE)
+  BalanceSegmentSet getBalanceSegmentSet(
+      @PathVariable("productidentifier") final String productIdentifier,
+      @PathVariable("balancesegmentsetidentifier") final String balanceSegmentSetIdentifier);
+
+  @RequestMapping(
+      value = "/products/{productidentifier}/balancesegmentsets/{balancesegmentsetidentifier}",
+      method = RequestMethod.PUT,
+      produces = MediaType.ALL_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE)
+  @ThrowsException(status = HttpStatus.CONFLICT, exception = ProductInUseException.class)
+  void changeBalanceSegmentSet(
+      @PathVariable("productidentifier") final String productIdentifier,
+      @PathVariable("balancesegmentsetidentifier") final String balanceSegmentSetIdentifier,
+      BalanceSegmentSet balanceSegmentSet);
+
+  @RequestMapping(
+      value = "/products/{productidentifier}/balancesegmentsets/{balancesegmentsetidentifier}",
+      method = RequestMethod.DELETE,
+      produces = MediaType.ALL_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsException(status = HttpStatus.CONFLICT, exception = ProductInUseException.class)
+  void deleteBalanceSegmentSet(
+      @PathVariable("productidentifier") final String productIdentifier,
+      @PathVariable("balancesegmentsetidentifier") final String balanceSegmentSetIdentifier);
+
+  @RequestMapping(
       value = "/products/{productidentifier}/tasks/",
       method = RequestMethod.GET,
       produces = MediaType.ALL_VALUE,
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/domain/BalanceSegmentSet.java b/api/src/main/java/io/mifos/portfolio/api/v1/domain/BalanceSegmentSet.java
new file mode 100644
index 0000000..7d4c3da
--- /dev/null
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/domain/BalanceSegmentSet.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.api.v1.domain;
+
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+import io.mifos.core.lang.validation.constraints.ValidIdentifiers;
+import io.mifos.portfolio.api.v1.validation.ValidSegmentList;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Objects;
+import java.util.SortedSet;
+
+/**
+ * @author Myrle Krantz
+ */
+@ValidSegmentList
+public class BalanceSegmentSet {
+  @ValidIdentifier
+  private String identifier;
+
+  private SortedSet<BigDecimal> segments;
+
+  @ValidIdentifiers
+  private List<String> segmentIdentifiers;
+
+  public BalanceSegmentSet() {
+  }
+
+  public BalanceSegmentSet(String identifier, SortedSet<BigDecimal> segments, List<String> segmentIdentifiers) {
+    this.identifier = identifier;
+    this.segments = segments;
+    this.segmentIdentifiers = segmentIdentifiers;
+  }
+
+  public String getIdentifier() {
+    return identifier;
+  }
+
+  public void setIdentifier(String identifier) {
+    this.identifier = identifier;
+  }
+
+  public SortedSet<BigDecimal> getSegments() {
+    return segments;
+  }
+
+  public void setSegments(SortedSet<BigDecimal> segments) {
+    this.segments = segments;
+  }
+
+  public List<String> getSegmentIdentifiers() {
+    return segmentIdentifiers;
+  }
+
+  public void setSegmentIdentifiers(List<String> segmentNames) {
+    this.segmentIdentifiers = segmentNames;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+    BalanceSegmentSet that = (BalanceSegmentSet) o;
+    return Objects.equals(identifier, that.identifier) &&
+        Objects.equals(segments, that.segments) &&
+        Objects.equals(segmentIdentifiers, that.segmentIdentifiers);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(identifier, segments, segmentIdentifiers);
+  }
+
+  @Override
+  public String toString() {
+    return "BalanceSegmentSet{" +
+        "identifier='" + identifier + '\'' +
+        ", segments=" + segments +
+        ", segmentIdentifiers=" + segmentIdentifiers +
+        '}';
+  }
+}
\ No newline at end of file
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/domain/ChargeDefinition.java b/api/src/main/java/io/mifos/portfolio/api/v1/domain/ChargeDefinition.java
index b7170d0..efa69f8 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/domain/ChargeDefinition.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/domain/ChargeDefinition.java
@@ -15,26 +15,25 @@
  */
 package io.mifos.portfolio.api.v1.domain;
 
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+import io.mifos.core.lang.validation.constraints.ValidIdentifiers;
+import io.mifos.portfolio.api.v1.validation.ValidChargeDefinition;
 import io.mifos.portfolio.api.v1.validation.ValidChargeReference;
 import io.mifos.portfolio.api.v1.validation.ValidPaymentCycleUnit;
-import io.mifos.core.lang.validation.constraints.ValidIdentifier;
 import org.hibernate.validator.constraints.NotBlank;
-import org.hibernate.validator.constraints.ScriptAssert;
 
 import javax.annotation.Nullable;
 import javax.validation.constraints.NotNull;
 import java.math.BigDecimal;
 import java.time.temporal.ChronoUnit;
+import java.util.List;
 import java.util.Objects;
 
 /**
  * @author Myrle Krantz
  */
 @SuppressWarnings({"unused", "WeakerAccess"})
-@ScriptAssert(lang = "javascript", script = "_this.amount !== null " +
-        "&& _this.amount.scale() <= 4 " +
-        "&& ((_this.accrueAction === null && _this.accrualAccountDesignator === null) || (_this.accrueAction !== null && _this.accrualAccountDesignator !== null))" +
-        "&& ((_this.chargeMethod == 'PROPORTIONAL' && _this.proportionalTo !== null) || (_this.chargeMethod == 'FIXED' && _this.proportionalTo === null))")
+@ValidChargeDefinition
 public class ChargeDefinition {
   @SuppressWarnings("WeakerAccess")
   public enum ChargeMethod {
@@ -82,6 +81,12 @@
 
   private boolean readOnly;
 
+  @ValidIdentifier(optional = true)
+  private String forSegmentSet;
+
+  @ValidIdentifiers(optional = true)
+  private List<String> forSegments;
+
   public ChargeDefinition() {
   }
 
@@ -190,6 +195,22 @@
     this.readOnly = readOnly;
   }
 
+  public String getForSegmentSet() {
+    return forSegmentSet;
+  }
+
+  public void setForSegmentSet(String forSegmentSet) {
+    this.forSegmentSet = forSegmentSet;
+  }
+
+  public List<String> getForSegments() {
+    return forSegments;
+  }
+
+  public void setForSegments(List<String> forSegments) {
+    this.forSegments = forSegments;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
@@ -207,12 +228,14 @@
         Objects.equals(fromAccountDesignator, that.fromAccountDesignator) &&
         Objects.equals(accrualAccountDesignator, that.accrualAccountDesignator) &&
         Objects.equals(toAccountDesignator, that.toAccountDesignator) &&
-        forCycleSizeUnit == that.forCycleSizeUnit;
+        forCycleSizeUnit == that.forCycleSizeUnit &&
+        Objects.equals(forSegmentSet, that.forSegmentSet) &&
+        Objects.equals(forSegments, that.forSegments);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(identifier, name, description, accrueAction, chargeAction, amount, chargeMethod, proportionalTo, fromAccountDesignator, accrualAccountDesignator, toAccountDesignator, forCycleSizeUnit, readOnly);
+    return Objects.hash(identifier, name, description, accrueAction, chargeAction, amount, chargeMethod, proportionalTo, fromAccountDesignator, accrualAccountDesignator, toAccountDesignator, forCycleSizeUnit, readOnly, forSegmentSet, forSegments);
   }
 
   @Override
@@ -231,6 +254,8 @@
         ", toAccountDesignator='" + toAccountDesignator + '\'' +
         ", forCycleSizeUnit=" + forCycleSizeUnit +
         ", readOnly=" + readOnly +
+        ", forSegmentSet='" + forSegmentSet + '\'' +
+        ", forSegments=" + forSegments +
         '}';
   }
 }
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/validation/CheckValidChargeDefinition.java b/api/src/main/java/io/mifos/portfolio/api/v1/validation/CheckValidChargeDefinition.java
new file mode 100644
index 0000000..4735798
--- /dev/null
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/validation/CheckValidChargeDefinition.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.api.v1.validation;
+
+import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * @author Myrle Krantz
+ */
+public class CheckValidChargeDefinition implements ConstraintValidator<ValidChargeDefinition, ChargeDefinition> {
+  @Override
+  public void initialize(ValidChargeDefinition constraintAnnotation) {
+  }
+
+  @SuppressWarnings("RedundantIfStatement")
+  @Override
+  public boolean isValid(ChargeDefinition value, ConstraintValidatorContext context) {
+    if (value.getAmount() == null)
+      return false;
+    if (value.getAmount().scale() > 4)
+      return false;
+    if (value.getAccrueAction() != null && value.getAccrualAccountDesignator() == null)
+      return false;
+    if (value.getAccrueAction() == null && value.getAccrualAccountDesignator() != null)
+      return false;
+    if (value.getChargeMethod() == ChargeDefinition.ChargeMethod.PROPORTIONAL &&
+        value.getProportionalTo() == null)
+      return false;
+    if (value.getChargeMethod() == ChargeDefinition.ChargeMethod.FIXED &&
+        value.getProportionalTo() != null)
+      return false;
+    if (value.getForSegmentSet() == null &&
+        value.getForSegments() != null)
+      return false;
+    if (value.getForSegmentSet() != null &&
+        value.getForSegments() == null)
+      return false;
+    if (value.getForSegmentSet() != null &&
+        value.getForSegments() != null &&
+        value.getForSegments().size() == 0)
+      return false;
+
+    return true;
+  }
+}
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/validation/CheckValidSegmentList.java b/api/src/main/java/io/mifos/portfolio/api/v1/validation/CheckValidSegmentList.java
new file mode 100644
index 0000000..aeb02ec
--- /dev/null
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/validation/CheckValidSegmentList.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.api.v1.validation;
+
+import io.mifos.portfolio.api.v1.domain.BalanceSegmentSet;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.math.BigDecimal;
+
+/**
+ * @author Myrle Krantz
+ */
+public class CheckValidSegmentList implements ConstraintValidator<ValidSegmentList, BalanceSegmentSet> {
+  @Override
+  public void initialize(ValidSegmentList constraintAnnotation) {
+
+  }
+
+  @Override
+  public boolean isValid(BalanceSegmentSet value, ConstraintValidatorContext context) {
+    if (value.getSegments() == null)
+      return false;
+    if (value.getSegmentIdentifiers() == null)
+      return false;
+
+    if (value.getSegments().size() + 1 != value.getSegmentIdentifiers().size())
+      return false;
+
+    for (final BigDecimal segment : value.getSegments()) {
+      if (segment.compareTo(BigDecimal.ZERO) <= 0)
+        return false;
+    }
+
+    return true;
+  }
+}
\ No newline at end of file
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/validation/ValidChargeDefinition.java b/api/src/main/java/io/mifos/portfolio/api/v1/validation/ValidChargeDefinition.java
new file mode 100644
index 0000000..680fe28
--- /dev/null
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/validation/ValidChargeDefinition.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.api.v1.validation;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Constraint(
+    validatedBy = {CheckValidChargeDefinition.class}
+)
+public @interface ValidChargeDefinition {
+  String message() default "Invalid charge definition.";
+
+  Class<?>[] groups() default {};
+
+  Class<? extends Payload>[] payload() default {};
+}
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/validation/ValidSegmentList.java b/api/src/main/java/io/mifos/portfolio/api/v1/validation/ValidSegmentList.java
new file mode 100644
index 0000000..15269ec
--- /dev/null
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/validation/ValidSegmentList.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.api.v1.validation;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Constraint(
+    validatedBy = {CheckValidSegmentList.class}
+)
+public @interface ValidSegmentList {
+  String message() default "Segments should be greater than 0 and should number the same as the identifiers.";
+
+  Class<?>[] groups() default {};
+
+  Class<? extends Payload>[] payload() default {};
+}
diff --git a/api/src/test/java/io/mifos/portfolio/api/v1/domain/BalanceSegmentSetTest.java b/api/src/test/java/io/mifos/portfolio/api/v1/domain/BalanceSegmentSetTest.java
new file mode 100644
index 0000000..c125654
--- /dev/null
+++ b/api/src/test/java/io/mifos/portfolio/api/v1/domain/BalanceSegmentSetTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.api.v1.domain;
+
+import io.mifos.core.test.domain.ValidationTest;
+import io.mifos.core.test.domain.ValidationTestCase;
+import org.junit.runners.Parameterized;
+
+import java.math.BigDecimal;
+import java.util.*;
+
+/**
+ * @author Myrle Krantz
+ */
+public class BalanceSegmentSetTest extends ValidationTest<BalanceSegmentSet> {
+  public BalanceSegmentSetTest(ValidationTestCase<BalanceSegmentSet> testCase) {
+    super(testCase);
+  }
+
+  @Override
+  protected BalanceSegmentSet createValidTestSubject() {
+    final BalanceSegmentSet ret = new BalanceSegmentSet();
+    ret.setIdentifier("valid");
+    ret.setSegments(new TreeSet<>(Arrays.asList(BigDecimal.valueOf(100), BigDecimal.valueOf(10_000))));
+    ret.setSegmentIdentifiers(Arrays.asList("small", "medium", "large"));
+    return ret;
+  }
+
+  @Parameterized.Parameters
+  public static Collection testCases() {
+    final Collection<ValidationTestCase> ret = new ArrayList<>();
+    ret.add(new ValidationTestCase<BalanceSegmentSet>("basicCase")
+        .adjustment(x -> {})
+        .valid(true));
+    ret.add(new ValidationTestCase<BalanceSegmentSet>("null segments")
+        .adjustment(x -> x.setSegments(null))
+        .valid(false));
+    ret.add(new ValidationTestCase<BalanceSegmentSet>("null identifiers")
+        .adjustment(x -> x.setSegmentIdentifiers(null))
+        .valid(false));
+    ret.add(new ValidationTestCase<BalanceSegmentSet>("too short identifier list")
+        .adjustment(x -> x.setSegmentIdentifiers(Arrays.asList("small", "large")))
+        .valid(false));
+    ret.add(new ValidationTestCase<BalanceSegmentSet>("negative segmentation")
+        .adjustment(x -> x.setSegments(new TreeSet<>(Arrays.asList(BigDecimal.ONE.negate(), BigDecimal.valueOf(100)))))
+        .valid(false));
+    ret.add(new ValidationTestCase<BalanceSegmentSet>("invalid identifier")
+        .adjustment(x -> x.setIdentifier("//"))
+        .valid(false));
+    ret.add(new ValidationTestCase<BalanceSegmentSet>("invalid segment identifier")
+        .adjustment(x -> x.setSegmentIdentifiers(Arrays.asList("small", "large", "//")))
+        .valid(false));
+    return ret;
+  }
+}
\ No newline at end of file
diff --git a/api/src/test/java/io/mifos/portfolio/api/v1/domain/ChargeDefinitionTest.java b/api/src/test/java/io/mifos/portfolio/api/v1/domain/ChargeDefinitionTest.java
index 750be0b..e8df923 100644
--- a/api/src/test/java/io/mifos/portfolio/api/v1/domain/ChargeDefinitionTest.java
+++ b/api/src/test/java/io/mifos/portfolio/api/v1/domain/ChargeDefinitionTest.java
@@ -24,7 +24,9 @@
 import java.math.BigDecimal;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 
 /**
  * @author Myrle Krantz
@@ -109,6 +111,24 @@
     ret.add(new ValidationTestCase<ChargeDefinition>("proportionalToMaximumBalance")
         .adjustment(x -> x.setProportionalTo("{maximumbalance}"))
         .valid(true));
+    ret.add(new ValidationTestCase<ChargeDefinition>("segment set set but not list")
+        .adjustment(x -> x.setForSegmentSet("xyz"))
+        .valid(false));
+    ret.add(new ValidationTestCase<ChargeDefinition>("segment list set but not set")
+        .adjustment(x -> x.setForSegments(Arrays.asList("mno", "xyz")))
+        .valid(false));
+    ret.add(new ValidationTestCase<ChargeDefinition>("empty segment list")
+        .adjustment(x -> { x.setForSegmentSet("xyz"); x.setForSegments(Collections.emptyList());})
+        .valid(false));
+    ret.add(new ValidationTestCase<ChargeDefinition>("valid segment references")
+        .adjustment(x -> { x.setForSegmentSet("xyz"); x.setForSegments(Collections.singletonList("abc"));})
+        .valid(true));
+    ret.add(new ValidationTestCase<ChargeDefinition>("invalid segment set identifier")
+        .adjustment(x -> { x.setForSegmentSet("//"); x.setForSegments(Collections.singletonList("abc"));})
+        .valid(false));
+    ret.add(new ValidationTestCase<ChargeDefinition>("invalid segment list set identifier")
+        .adjustment(x -> { x.setForSegmentSet("xyz"); x.setForSegments(Collections.singletonList("//"));})
+        .valid(false));
     return ret;
   }
 }