Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit 48c6e68

Browse files
authored
Java, adds min/maxContains (#361)
* Adds min/maxContains handling in templates * Regen 310sample * Updates docs * Makes containsPathToSchemas nullable, fixes java tests * Samples regen
1 parent e8bd86a commit 48c6e68

File tree

138 files changed

+556
-124
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+556
-124
lines changed

docs/generators/java.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,12 @@ These options may be applied as additional-properties (cli) or configOptions (pl
289289
|Format|✓|OAS2,OAS3
290290
|If|✗|OAS3
291291
|Items|✓|OAS2,OAS3
292-
|MaxContains||OAS3
292+
|MaxContains||OAS3
293293
|MaxItems|✓|OAS2,OAS3
294294
|MaxLength|✓|OAS2,OAS3
295295
|MaxProperties|✓|OAS2,OAS3
296296
|Maximum|✓|OAS2,OAS3
297-
|MinContains||OAS3
297+
|MinContains||OAS3
298298
|MinItems|✓|OAS2,OAS3
299299
|MinLength|✓|OAS2,OAS3
300300
|MinProperties|✓|OAS2,OAS3

samples/client/3_0_3_unit_test/java/.openapi-generator/FILES

+2
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,12 @@ src/main/java/org/openapijsonschematools/client/schemas/validation/LongEnumValid
237237
src/main/java/org/openapijsonschematools/client/schemas/validation/LongValueMethod.java
238238
src/main/java/org/openapijsonschematools/client/schemas/validation/MapSchemaValidator.java
239239
src/main/java/org/openapijsonschematools/client/schemas/validation/MapUtils.java
240+
src/main/java/org/openapijsonschematools/client/schemas/validation/MaxContainsValidator.java
240241
src/main/java/org/openapijsonschematools/client/schemas/validation/MaxItemsValidator.java
241242
src/main/java/org/openapijsonschematools/client/schemas/validation/MaxLengthValidator.java
242243
src/main/java/org/openapijsonschematools/client/schemas/validation/MaxPropertiesValidator.java
243244
src/main/java/org/openapijsonschematools/client/schemas/validation/MaximumValidator.java
245+
src/main/java/org/openapijsonschematools/client/schemas/validation/MinContainsValidator.java
244246
src/main/java/org/openapijsonschematools/client/schemas/validation/MinItemsValidator.java
245247
src/main/java/org/openapijsonschematools/client/schemas/validation/MinLengthValidator.java
246248
src/main/java/org/openapijsonschematools/client/schemas/validation/MinPropertiesValidator.java

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/AdditionalPropertiesValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public AdditionalPropertiesValidator(Class<? extends JsonSchema> additionalPrope
1919
JsonSchema schema,
2020
@Nullable Object arg,
2121
ValidationMetadata validationMetadata,
22-
List<PathToSchemasMap> containsPathToSchemas
22+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2323
) {
2424
if (!(arg instanceof Map<?, ?> mapArg)) {
2525
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/AllOfValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public AllOfValidator(List<Class<? extends JsonSchema>> allOf) {
1515
JsonSchema schema,
1616
@Nullable Object arg,
1717
ValidationMetadata validationMetadata,
18-
List<PathToSchemasMap> containsPathToSchemas
18+
@Nullable List<PathToSchemasMap> containsPathToSchemas
1919
) {
2020
PathToSchemasMap pathToSchemas = new PathToSchemasMap();
2121
for(Class<? extends JsonSchema> allOfClass: allOf) {

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/AnyOfValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public AnyOfValidator(List<Class<? extends JsonSchema>> anyOf) {
1818
JsonSchema schema,
1919
@Nullable Object arg,
2020
ValidationMetadata validationMetadata,
21-
List<PathToSchemasMap> containsPathToSchemas
21+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2222
) {
2323
PathToSchemasMap pathToSchemas = new PathToSchemasMap();
2424
List<Class<? extends JsonSchema>> validatedAnyOfClasses = new ArrayList<>();

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/ConstValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public ConstValidator(@Nullable Object constValue) {
1919
JsonSchema schema,
2020
@Nullable Object arg,
2121
ValidationMetadata validationMetadata,
22-
List<PathToSchemasMap> containsPathToSchemas
22+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2323
) {
2424
if (arg instanceof Number) {
2525
BigDecimal castArg = getBigDecimal((Number) arg);

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/ContainsValidator.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ public ContainsValidator(Class<? extends JsonSchema> contains) {
1818
JsonSchema schema,
1919
@Nullable Object arg,
2020
ValidationMetadata validationMetadata,
21-
List<PathToSchemasMap> containsPathToSchemas
21+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2222
) {
2323
if (!(arg instanceof List)) {
2424
return null;
2525
}
26-
if (containsPathToSchemas.isEmpty()) {
26+
if (containsPathToSchemas == null || containsPathToSchemas.isEmpty()) {
2727
throw new ValidationException(
2828
"Validation failed for contains keyword in class="+schema.getClass()
2929
+ " at pathToItem="+validationMetadata.pathToItem()+". No "
@@ -44,7 +44,7 @@ public List<PathToSchemasMap> getContainsPathToSchemas(
4444
if (!(arg instanceof List)) {
4545
return new ArrayList<>();
4646
}
47-
List<PathToSchemasMap> containsPathToSchemas = new ArrayList<>();
47+
@Nullable List<PathToSchemasMap> containsPathToSchemas = new ArrayList<>();
4848
int i = 0;
4949
for(Object itemValue: (List<?>) arg) {
5050
PathToSchemasMap thesePathToSchemas = new PathToSchemasMap();

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/EnumValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ private boolean enumContainsArg(@Nullable Object arg){
2424
JsonSchema schema,
2525
@Nullable Object arg,
2626
ValidationMetadata validationMetadata,
27-
List<PathToSchemasMap> containsPathToSchemas
27+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2828
) {
2929
if (enumValues.isEmpty()) {
3030
throw new ValidationException("No value can match enum because enum is empty");

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/ExclusiveMaximumValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public ExclusiveMaximumValidator(Number exclusiveMaximum) {
1717
JsonSchema schema,
1818
@Nullable Object arg,
1919
ValidationMetadata validationMetadata,
20-
List<PathToSchemasMap> containsPathToSchemas
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2121
) {
2222
if (!(arg instanceof Number)) {
2323
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/ExclusiveMinimumValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public ExclusiveMinimumValidator(Number exclusiveMinimum) {
1717
JsonSchema schema,
1818
@Nullable Object arg,
1919
ValidationMetadata validationMetadata,
20-
List<PathToSchemasMap> containsPathToSchemas
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2121
) {
2222
if (!(arg instanceof Number)) {
2323
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/FormatValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ private Void validateStringFormat(String arg, ValidationMetadata validationMetad
148148
JsonSchema schema,
149149
@Nullable Object arg,
150150
ValidationMetadata validationMetadata,
151-
List<PathToSchemasMap> containsPathToSchemas
151+
@Nullable List<PathToSchemasMap> containsPathToSchemas
152152
) {
153153
if (arg instanceof Number) {
154154
validateNumericFormat(

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/ItemsValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public ItemsValidator(Class<? extends JsonSchema> items) {
1717
JsonSchema schema,
1818
@Nullable Object arg,
1919
ValidationMetadata validationMetadata,
20-
List<PathToSchemasMap> containsPathToSchemas
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2121
) {
2222
if (!(arg instanceof List)) {
2323
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java

+17-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public abstract class JsonSchema {
4747
public final @Nullable Object constValue;
4848
public final boolean constValueSet;
4949
public final @Nullable Class<? extends JsonSchema> contains;
50+
public final @Nullable Integer maxContains;
51+
public final @Nullable Integer minContains;
5052
private final LinkedHashMap<String, KeywordValidator> keywordToValidator;
5153

5254
protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) {
@@ -236,6 +238,20 @@ protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) {
236238
new ContainsValidator(this.contains)
237239
);
238240
}
241+
this.maxContains = jsonSchemaInfo.maxContains;
242+
if (this.maxContains != null) {
243+
keywordToValidator.put(
244+
"maxContains",
245+
new MaxContainsValidator(this.maxContains)
246+
);
247+
}
248+
this.minContains = jsonSchemaInfo.minContains;
249+
if (this.minContains != null) {
250+
keywordToValidator.put(
251+
"minContains",
252+
new MinContainsValidator(this.minContains)
253+
);
254+
}
239255
this.keywordToValidator = keywordToValidator;
240256
}
241257

@@ -250,7 +266,7 @@ public static PathToSchemasMap validate(
250266
LinkedHashSet<String> disabledKeywords = validationMetadata.configuration().disabledKeywordFlags().getKeywords();
251267
PathToSchemasMap pathToSchemas = new PathToSchemasMap();
252268
LinkedHashMap<String, KeywordValidator> thisKeywordToValidator = jsonSchema.keywordToValidator;
253-
List<PathToSchemasMap> containsPathToSchemas = new ArrayList<>();
269+
@Nullable List<PathToSchemasMap> containsPathToSchemas = null;
254270
KeywordValidator containsValidator = thisKeywordToValidator.get("contains");
255271
if (containsValidator != null) {
256272
containsPathToSchemas = containsValidator.getContainsPathToSchemas(arg, validationMetadata);

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java

+10
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,14 @@ public JsonSchemaInfo contains(Class<? extends JsonSchema> contains) {
147147
this.contains = contains;
148148
return this;
149149
}
150+
public @Nullable Integer maxContains = null;
151+
public JsonSchemaInfo maxContains(Integer maxContains) {
152+
this.maxContains = maxContains;
153+
return this;
154+
}
155+
public @Nullable Integer minContains = null;
156+
public JsonSchemaInfo minContains(Integer minContains) {
157+
this.minContains = minContains;
158+
return this;
159+
}
150160
}

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/KeywordValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public interface KeywordValidator {
1111
JsonSchema schema,
1212
@Nullable Object arg,
1313
ValidationMetadata validationMetadata,
14-
List<PathToSchemasMap> containsPathToSchemas
14+
@Nullable List<PathToSchemasMap> containsPathToSchemas
1515
) throws ValidationException;
1616

1717
default List<PathToSchemasMap> getContainsPathToSchemas(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.openapijsonschematools.client.schemas.validation;
2+
3+
import org.checkerframework.checker.nullness.qual.Nullable;
4+
import org.openapijsonschematools.client.exceptions.ValidationException;
5+
6+
import java.util.List;
7+
8+
public class MaxContainsValidator implements KeywordValidator {
9+
public final int maxContains;
10+
11+
public MaxContainsValidator(int maxContains) {
12+
this.maxContains = maxContains;
13+
}
14+
15+
@Override
16+
public @Nullable PathToSchemasMap validate(
17+
JsonSchema schema,
18+
@Nullable Object arg,
19+
ValidationMetadata validationMetadata,
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
21+
) {
22+
if (!(arg instanceof List)) {
23+
return null;
24+
}
25+
if (containsPathToSchemas == null) {
26+
return null;
27+
}
28+
if (containsPathToSchemas.size() > maxContains) {
29+
throw new ValidationException(
30+
"Validation failed for maxContains keyword in class="+schema.getClass()+
31+
" at pathToItem="+validationMetadata.pathToItem()+". Too many items validated to the contains schema."
32+
);
33+
}
34+
return null;
35+
}
36+
}

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/MaxItemsValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public MaxItemsValidator(int maxItems) {
1717
JsonSchema schema,
1818
@Nullable Object arg,
1919
ValidationMetadata validationMetadata,
20-
List<PathToSchemasMap> containsPathToSchemas
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2121
) {
2222
if (!(arg instanceof List)) {
2323
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/MaxLengthValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public MaxLengthValidator(int maxLength) {
1717
JsonSchema schema,
1818
@Nullable Object arg,
1919
ValidationMetadata validationMetadata,
20-
List<PathToSchemasMap> containsPathToSchemas
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2121
) {
2222
if (!(arg instanceof String)) {
2323
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/MaxPropertiesValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public MaxPropertiesValidator(int maxProperties) {
1818
JsonSchema schema,
1919
@Nullable Object arg,
2020
ValidationMetadata validationMetadata,
21-
List<PathToSchemasMap> containsPathToSchemas
21+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2222
) {
2323
if (!(arg instanceof Map)) {
2424
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/MaximumValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public MaximumValidator(Number maximum) {
1717
JsonSchema schema,
1818
@Nullable Object arg,
1919
ValidationMetadata validationMetadata,
20-
List<PathToSchemasMap> containsPathToSchemas
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2121
) {
2222
if (!(arg instanceof Number)) {
2323
return null;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.openapijsonschematools.client.schemas.validation;
2+
3+
import org.checkerframework.checker.nullness.qual.Nullable;
4+
import org.openapijsonschematools.client.exceptions.ValidationException;
5+
6+
import java.util.List;
7+
8+
public class MinContainsValidator implements KeywordValidator {
9+
public final int minContains;
10+
11+
public MinContainsValidator(int minContains) {
12+
this.minContains = minContains;
13+
}
14+
15+
@Override
16+
public @Nullable PathToSchemasMap validate(
17+
JsonSchema schema,
18+
@Nullable Object arg,
19+
ValidationMetadata validationMetadata,
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
21+
) {
22+
if (!(arg instanceof List)) {
23+
return null;
24+
}
25+
if (containsPathToSchemas == null) {
26+
return null;
27+
}
28+
if (containsPathToSchemas.size() < minContains) {
29+
throw new ValidationException(
30+
"Validation failed for minContains keyword in class="+schema.getClass()+
31+
" at pathToItem="+validationMetadata.pathToItem()+". Too few items validated to the contains schema."
32+
);
33+
}
34+
return null;
35+
}
36+
}

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/MinItemsValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public MinItemsValidator(int minItems) {
1717
JsonSchema schema,
1818
@Nullable Object arg,
1919
ValidationMetadata validationMetadata,
20-
List<PathToSchemasMap> containsPathToSchemas
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2121
) {
2222
if (!(arg instanceof List)) {
2323
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/MinLengthValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public MinLengthValidator(int minLength) {
1717
JsonSchema schema,
1818
@Nullable Object arg,
1919
ValidationMetadata validationMetadata,
20-
List<PathToSchemasMap> containsPathToSchemas
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2121
) {
2222
if (!(arg instanceof String)) {
2323
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/MinPropertiesValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public MinPropertiesValidator(int minProperties) {
1818
JsonSchema schema,
1919
@Nullable Object arg,
2020
ValidationMetadata validationMetadata,
21-
List<PathToSchemasMap> containsPathToSchemas
21+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2222
) {
2323
if (!(arg instanceof Map)) {
2424
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/MinimumValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public MinimumValidator(Number minimum) {
1717
JsonSchema schema,
1818
@Nullable Object arg,
1919
ValidationMetadata validationMetadata,
20-
List<PathToSchemasMap> containsPathToSchemas
20+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2121
) {
2222
if (!(arg instanceof Number)) {
2323
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/MultipleOfValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public MultipleOfValidator(BigDecimal multipleOf) {
1818
JsonSchema schema,
1919
@Nullable Object arg,
2020
ValidationMetadata validationMetadata,
21-
List<PathToSchemasMap> containsPathToSchemas
21+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2222
) {
2323
if (!(arg instanceof Number)) {
2424
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/NotValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public NotValidator(Class<? extends JsonSchema> not) {
2222
JsonSchema schema,
2323
@Nullable Object arg,
2424
ValidationMetadata validationMetadata,
25-
List<PathToSchemasMap> containsPathToSchemas
25+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2626
) {
2727
PathToSchemasMap pathToSchemas;
2828
try {

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/OneOfValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public OneOfValidator(List<Class<? extends JsonSchema>> oneOf) {
1818
JsonSchema schema,
1919
@Nullable Object arg,
2020
ValidationMetadata validationMetadata,
21-
List<PathToSchemasMap> containsPathToSchemas
21+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2222
) {
2323
PathToSchemasMap pathToSchemas = new PathToSchemasMap();
2424
List<Class<? extends JsonSchema>> validatedOneOfClasses = new ArrayList<>();

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PatternValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public PatternValidator(Pattern pattern) {
1818
JsonSchema schema,
1919
@Nullable Object arg,
2020
ValidationMetadata validationMetadata,
21-
List<PathToSchemasMap> containsPathToSchemas
21+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2222
) {
2323
if (!(arg instanceof String)) {
2424
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertiesValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public PropertiesValidator(Map<String, Class<? extends JsonSchema>> properties)
2020
JsonSchema schema,
2121
@Nullable Object arg,
2222
ValidationMetadata validationMetadata,
23-
List<PathToSchemasMap> containsPathToSchemas
23+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2424
) {
2525
if (!(arg instanceof Map<?, ?> mapArg)) {
2626
return null;

samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/RequiredValidator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public RequiredValidator(Set<String> required) {
2020
JsonSchema schema,
2121
@Nullable Object arg,
2222
ValidationMetadata validationMetadata,
23-
List<PathToSchemasMap> containsPathToSchemas
23+
@Nullable List<PathToSchemasMap> containsPathToSchemas
2424
) {
2525
if (!(arg instanceof Map)) {
2626
return null;

0 commit comments

Comments
 (0)