Search in sources :

Example 11 with TypeDefinition

use of graphql.language.TypeDefinition in project graphql-java by graphql-java.

the class TypeDefinitionRegistry method merge.

/**
 * This will merge these type registries together and return this one
 *
 * @param typeRegistry the registry to be merged into this one
 *
 * @return this registry
 *
 * @throws SchemaProblem if there are problems merging the types such as redefinitions
 */
public TypeDefinitionRegistry merge(TypeDefinitionRegistry typeRegistry) throws SchemaProblem {
    List<GraphQLError> errors = new ArrayList<>();
    Map<String, TypeDefinition> tempTypes = new LinkedHashMap<>();
    typeRegistry.types.values().forEach(newEntry -> {
        Optional<GraphQLError> defined = define(this.types, tempTypes, newEntry);
        defined.ifPresent(errors::add);
    });
    Map<String, ScalarTypeDefinition> tempScalarTypes = new LinkedHashMap<>();
    typeRegistry.scalarTypes.values().forEach(newEntry -> define(this.scalarTypes, tempScalarTypes, newEntry).ifPresent(errors::add));
    if (typeRegistry.schema != null && this.schema != null) {
        errors.add(new SchemaRedefinitionError(this.schema, typeRegistry.schema));
    }
    if (!errors.isEmpty()) {
        throw new SchemaProblem(errors);
    }
    if (this.schema == null) {
        // ensure schema is not overwritten by merge
        this.schema = typeRegistry.schema;
    }
    // ok commit to the merge
    this.types.putAll(tempTypes);
    this.scalarTypes.putAll(tempScalarTypes);
    // 
    // merge type extensions since they can be redefined by design
    typeRegistry.typeExtensions.forEach((key, value) -> {
        List<ObjectTypeExtensionDefinition> currentList = this.typeExtensions.computeIfAbsent(key, k -> new ArrayList<>());
        currentList.addAll(value);
    });
    typeRegistry.interfaceTypeExtensions.forEach((key, value) -> {
        List<InterfaceTypeExtensionDefinition> currentList = this.interfaceTypeExtensions.computeIfAbsent(key, k -> new ArrayList<>());
        currentList.addAll(value);
    });
    typeRegistry.unionTypeExtensions.forEach((key, value) -> {
        List<UnionTypeExtensionDefinition> currentList = this.unionTypeExtensions.computeIfAbsent(key, k -> new ArrayList<>());
        currentList.addAll(value);
    });
    typeRegistry.enumTypeExtensions.forEach((key, value) -> {
        List<EnumTypeExtensionDefinition> currentList = this.enumTypeExtensions.computeIfAbsent(key, k -> new ArrayList<>());
        currentList.addAll(value);
    });
    typeRegistry.scalarTypeExtensions.forEach((key, value) -> {
        List<ScalarTypeExtensionDefinition> currentList = this.scalarTypeExtensions.computeIfAbsent(key, k -> new ArrayList<>());
        currentList.addAll(value);
    });
    typeRegistry.inputObjectTypeExtensions.forEach((key, value) -> {
        List<InputObjectTypeExtensionDefinition> currentList = this.inputObjectTypeExtensions.computeIfAbsent(key, k -> new ArrayList<>());
        currentList.addAll(value);
    });
    return this;
}
Also used : SchemaRedefinitionError(graphql.schema.idl.errors.SchemaRedefinitionError) ObjectTypeExtensionDefinition(graphql.language.ObjectTypeExtensionDefinition) InputObjectTypeExtensionDefinition(graphql.language.InputObjectTypeExtensionDefinition) ArrayList(java.util.ArrayList) InterfaceTypeExtensionDefinition(graphql.language.InterfaceTypeExtensionDefinition) UnionTypeDefinition(graphql.language.UnionTypeDefinition) ScalarTypeDefinition(graphql.language.ScalarTypeDefinition) ObjectTypeDefinition(graphql.language.ObjectTypeDefinition) TypeDefinition(graphql.language.TypeDefinition) InterfaceTypeDefinition(graphql.language.InterfaceTypeDefinition) LinkedHashMap(java.util.LinkedHashMap) ScalarTypeDefinition(graphql.language.ScalarTypeDefinition) SchemaProblem(graphql.schema.idl.errors.SchemaProblem) GraphQLError(graphql.GraphQLError) EnumTypeExtensionDefinition(graphql.language.EnumTypeExtensionDefinition) ScalarTypeExtensionDefinition(graphql.language.ScalarTypeExtensionDefinition) InputObjectTypeExtensionDefinition(graphql.language.InputObjectTypeExtensionDefinition) UnionTypeExtensionDefinition(graphql.language.UnionTypeExtensionDefinition)

Example 12 with TypeDefinition

use of graphql.language.TypeDefinition in project graphql-java by graphql-java.

the class SchemaGenerator method buildObjectTypeInterfaces.

private void buildObjectTypeInterfaces(BuildContext buildCtx, ObjectTypeDefinition typeDefinition, GraphQLObjectType.Builder builder, List<ObjectTypeExtensionDefinition> extensions) {
    Map<String, GraphQLInterfaceType> interfaces = new LinkedHashMap<>();
    typeDefinition.getImplements().forEach(type -> {
        GraphQLInterfaceType newInterfaceType = buildOutputType(buildCtx, type);
        interfaces.put(newInterfaceType.getName(), newInterfaceType);
    });
    extensions.forEach(extension -> extension.getImplements().forEach(type -> {
        GraphQLInterfaceType interfaceType = buildOutputType(buildCtx, type);
        if (!interfaces.containsKey(interfaceType.getName())) {
            interfaces.put(interfaceType.getName(), interfaceType);
        }
    }));
    interfaces.values().forEach(builder::withInterface);
}
Also used : Arrays(java.util.Arrays) Value(graphql.language.Value) INPUT_FIELD_DEFINITION(graphql.introspection.Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION) GraphQLInputObjectType(graphql.schema.GraphQLInputObjectType) GraphQLFieldDefinition(graphql.schema.GraphQLFieldDefinition) GraphQLInterfaceType(graphql.schema.GraphQLInterfaceType) InputValueDefinition(graphql.language.InputValueDefinition) GraphQLInputObjectField(graphql.schema.GraphQLInputObjectField) GraphQLUnionType(graphql.schema.GraphQLUnionType) SchemaDefinition(graphql.language.SchemaDefinition) GraphQLEnumValueDefinition(graphql.schema.GraphQLEnumValueDefinition) UNION(graphql.introspection.Introspection.DirectiveLocation.UNION) EnumTypeDefinition(graphql.language.EnumTypeDefinition) Type(graphql.language.Type) INPUT_OBJECT(graphql.introspection.Introspection.DirectiveLocation.INPUT_OBJECT) TypeResolverProxy(graphql.schema.TypeResolverProxy) GraphQLEnumValueDefinition.newEnumValueDefinition(graphql.schema.GraphQLEnumValueDefinition.newEnumValueDefinition) DataFetcherFactory(graphql.schema.DataFetcherFactory) EnumValueDefinition(graphql.language.EnumValueDefinition) ObjectTypeExtensionDefinition(graphql.language.ObjectTypeExtensionDefinition) OBJECT(graphql.introspection.Introspection.DirectiveLocation.OBJECT) GraphQLError(graphql.GraphQLError) Map(java.util.Map) TypeName(graphql.language.TypeName) TypeResolver(graphql.schema.TypeResolver) OperationTypeDefinition(graphql.language.OperationTypeDefinition) GraphQLObjectType(graphql.schema.GraphQLObjectType) GraphQLDirective(graphql.schema.GraphQLDirective) NotAnInputTypeError(graphql.schema.idl.errors.NotAnInputTypeError) ObjectTypeDefinition(graphql.language.ObjectTypeDefinition) UnionTypeExtensionDefinition(graphql.language.UnionTypeExtensionDefinition) Collections.emptyList(java.util.Collections.emptyList) FieldDefinition(graphql.language.FieldDefinition) GraphQLInputType(graphql.schema.GraphQLInputType) Set(java.util.Set) TypeDefinition(graphql.language.TypeDefinition) GraphQLArgument(graphql.schema.GraphQLArgument) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) NotAnOutputTypeError(graphql.schema.idl.errors.NotAnOutputTypeError) List(java.util.List) Stream(java.util.stream.Stream) ENUM_VALUE(graphql.introspection.Introspection.DirectiveLocation.ENUM_VALUE) InterfaceTypeDefinition(graphql.language.InterfaceTypeDefinition) Optional(java.util.Optional) GraphQLEnumType(graphql.schema.GraphQLEnumType) InterfaceTypeExtensionDefinition(graphql.language.InterfaceTypeExtensionDefinition) DirectiveLocation(graphql.introspection.Introspection.DirectiveLocation) GraphQLScalarType(graphql.schema.GraphQLScalarType) InputObjectTypeDefinition(graphql.language.InputObjectTypeDefinition) SchemaProblem(graphql.schema.idl.errors.SchemaProblem) HashMap(java.util.HashMap) GraphQLType(graphql.schema.GraphQLType) Stack(java.util.Stack) ArrayList(java.util.ArrayList) ENUM(graphql.introspection.Introspection.DirectiveLocation.ENUM) Introspection(graphql.introspection.Introspection) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) UnionTypeDefinition(graphql.language.UnionTypeDefinition) DataFetcherFactories(graphql.schema.DataFetcherFactories) InputObjectTypeExtensionDefinition(graphql.language.InputObjectTypeExtensionDefinition) ScalarTypeExtensionDefinition(graphql.language.ScalarTypeExtensionDefinition) DataFetcher(graphql.schema.DataFetcher) GraphQLSchema(graphql.schema.GraphQLSchema) ScalarTypeDefinition(graphql.language.ScalarTypeDefinition) EnumTypeExtensionDefinition(graphql.language.EnumTypeExtensionDefinition) GraphQLOutputType(graphql.schema.GraphQLOutputType) Directive(graphql.language.Directive) GraphQLTypeReference(graphql.schema.GraphQLTypeReference) PublicApi(graphql.PublicApi) Assert.assertNotNull(graphql.Assert.assertNotNull) GraphQLTypeReference.typeRef(graphql.schema.GraphQLTypeReference.typeRef) Collections(java.util.Collections) GraphQLInterfaceType(graphql.schema.GraphQLInterfaceType) LinkedHashMap(java.util.LinkedHashMap)

Example 13 with TypeDefinition

use of graphql.language.TypeDefinition in project graphql-java by graphql-java.

the class SchemaGenerator method buildInputType.

private GraphQLInputType buildInputType(BuildContext buildCtx, Type rawType) {
    TypeDefinition typeDefinition = buildCtx.getTypeDefinition(rawType);
    TypeInfo typeInfo = TypeInfo.typeInfo(rawType);
    GraphQLInputType inputType = buildCtx.hasInputType(typeDefinition);
    if (inputType != null) {
        return typeInfo.decorate(inputType);
    }
    if (buildCtx.stackContains(typeInfo)) {
        // we have circled around so put in a type reference and fix it later
        return typeInfo.decorate(typeRef(typeInfo.getName()));
    }
    buildCtx.push(typeInfo);
    if (typeDefinition instanceof InputObjectTypeDefinition) {
        inputType = buildInputObjectType(buildCtx, (InputObjectTypeDefinition) typeDefinition);
    } else if (typeDefinition instanceof EnumTypeDefinition) {
        inputType = buildEnumType(buildCtx, (EnumTypeDefinition) typeDefinition);
    } else if (typeDefinition instanceof ScalarTypeDefinition) {
        inputType = buildScalar(buildCtx, (ScalarTypeDefinition) typeDefinition);
    } else {
        // typeDefinition is not a valid InputType
        throw new NotAnInputTypeError(typeDefinition);
    }
    buildCtx.put(inputType);
    buildCtx.pop();
    return typeInfo.decorate(inputType);
}
Also used : GraphQLInputType(graphql.schema.GraphQLInputType) ScalarTypeDefinition(graphql.language.ScalarTypeDefinition) EnumTypeDefinition(graphql.language.EnumTypeDefinition) NotAnInputTypeError(graphql.schema.idl.errors.NotAnInputTypeError) InputObjectTypeDefinition(graphql.language.InputObjectTypeDefinition) EnumTypeDefinition(graphql.language.EnumTypeDefinition) OperationTypeDefinition(graphql.language.OperationTypeDefinition) ObjectTypeDefinition(graphql.language.ObjectTypeDefinition) TypeDefinition(graphql.language.TypeDefinition) InterfaceTypeDefinition(graphql.language.InterfaceTypeDefinition) InputObjectTypeDefinition(graphql.language.InputObjectTypeDefinition) UnionTypeDefinition(graphql.language.UnionTypeDefinition) ScalarTypeDefinition(graphql.language.ScalarTypeDefinition)

Example 14 with TypeDefinition

use of graphql.language.TypeDefinition in project graphql-java by graphql-java.

the class SchemaGenerator method buildUnionType.

private GraphQLUnionType buildUnionType(BuildContext buildCtx, UnionTypeDefinition typeDefinition) {
    GraphQLUnionType.Builder builder = GraphQLUnionType.newUnionType();
    builder.definition(typeDefinition);
    builder.name(typeDefinition.getName());
    builder.description(schemaGeneratorHelper.buildDescription(typeDefinition, typeDefinition.getDescription()));
    builder.typeResolver(getTypeResolverForUnion(buildCtx, typeDefinition));
    List<UnionTypeExtensionDefinition> extensions = unionTypeExtensions(typeDefinition, buildCtx);
    typeDefinition.getMemberTypes().forEach(mt -> {
        GraphQLOutputType outputType = buildOutputType(buildCtx, mt);
        if (outputType instanceof GraphQLTypeReference) {
            builder.possibleType((GraphQLTypeReference) outputType);
        } else {
            builder.possibleType((GraphQLObjectType) outputType);
        }
    });
    builder.withDirectives(buildDirectives(typeDefinition.getDirectives(), directivesOf(extensions), UNION));
    extensions.forEach(extension -> extension.getMemberTypes().forEach(mt -> {
        GraphQLOutputType outputType = buildOutputType(buildCtx, mt);
        if (!builder.containType(outputType.getName())) {
            if (outputType instanceof GraphQLTypeReference) {
                builder.possibleType((GraphQLTypeReference) outputType);
            } else {
                builder.possibleType((GraphQLObjectType) outputType);
            }
        }
    }));
    return builder.build();
}
Also used : Arrays(java.util.Arrays) Value(graphql.language.Value) INPUT_FIELD_DEFINITION(graphql.introspection.Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION) GraphQLInputObjectType(graphql.schema.GraphQLInputObjectType) GraphQLFieldDefinition(graphql.schema.GraphQLFieldDefinition) GraphQLInterfaceType(graphql.schema.GraphQLInterfaceType) InputValueDefinition(graphql.language.InputValueDefinition) GraphQLInputObjectField(graphql.schema.GraphQLInputObjectField) GraphQLUnionType(graphql.schema.GraphQLUnionType) SchemaDefinition(graphql.language.SchemaDefinition) GraphQLEnumValueDefinition(graphql.schema.GraphQLEnumValueDefinition) UNION(graphql.introspection.Introspection.DirectiveLocation.UNION) EnumTypeDefinition(graphql.language.EnumTypeDefinition) Type(graphql.language.Type) INPUT_OBJECT(graphql.introspection.Introspection.DirectiveLocation.INPUT_OBJECT) TypeResolverProxy(graphql.schema.TypeResolverProxy) GraphQLEnumValueDefinition.newEnumValueDefinition(graphql.schema.GraphQLEnumValueDefinition.newEnumValueDefinition) DataFetcherFactory(graphql.schema.DataFetcherFactory) EnumValueDefinition(graphql.language.EnumValueDefinition) ObjectTypeExtensionDefinition(graphql.language.ObjectTypeExtensionDefinition) OBJECT(graphql.introspection.Introspection.DirectiveLocation.OBJECT) GraphQLError(graphql.GraphQLError) Map(java.util.Map) TypeName(graphql.language.TypeName) TypeResolver(graphql.schema.TypeResolver) OperationTypeDefinition(graphql.language.OperationTypeDefinition) GraphQLObjectType(graphql.schema.GraphQLObjectType) GraphQLDirective(graphql.schema.GraphQLDirective) NotAnInputTypeError(graphql.schema.idl.errors.NotAnInputTypeError) ObjectTypeDefinition(graphql.language.ObjectTypeDefinition) UnionTypeExtensionDefinition(graphql.language.UnionTypeExtensionDefinition) Collections.emptyList(java.util.Collections.emptyList) FieldDefinition(graphql.language.FieldDefinition) GraphQLInputType(graphql.schema.GraphQLInputType) Set(java.util.Set) TypeDefinition(graphql.language.TypeDefinition) GraphQLArgument(graphql.schema.GraphQLArgument) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) NotAnOutputTypeError(graphql.schema.idl.errors.NotAnOutputTypeError) List(java.util.List) Stream(java.util.stream.Stream) ENUM_VALUE(graphql.introspection.Introspection.DirectiveLocation.ENUM_VALUE) InterfaceTypeDefinition(graphql.language.InterfaceTypeDefinition) Optional(java.util.Optional) GraphQLEnumType(graphql.schema.GraphQLEnumType) InterfaceTypeExtensionDefinition(graphql.language.InterfaceTypeExtensionDefinition) DirectiveLocation(graphql.introspection.Introspection.DirectiveLocation) GraphQLScalarType(graphql.schema.GraphQLScalarType) InputObjectTypeDefinition(graphql.language.InputObjectTypeDefinition) SchemaProblem(graphql.schema.idl.errors.SchemaProblem) HashMap(java.util.HashMap) GraphQLType(graphql.schema.GraphQLType) Stack(java.util.Stack) ArrayList(java.util.ArrayList) ENUM(graphql.introspection.Introspection.DirectiveLocation.ENUM) Introspection(graphql.introspection.Introspection) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) UnionTypeDefinition(graphql.language.UnionTypeDefinition) DataFetcherFactories(graphql.schema.DataFetcherFactories) InputObjectTypeExtensionDefinition(graphql.language.InputObjectTypeExtensionDefinition) ScalarTypeExtensionDefinition(graphql.language.ScalarTypeExtensionDefinition) DataFetcher(graphql.schema.DataFetcher) GraphQLSchema(graphql.schema.GraphQLSchema) ScalarTypeDefinition(graphql.language.ScalarTypeDefinition) EnumTypeExtensionDefinition(graphql.language.EnumTypeExtensionDefinition) GraphQLOutputType(graphql.schema.GraphQLOutputType) Directive(graphql.language.Directive) GraphQLTypeReference(graphql.schema.GraphQLTypeReference) PublicApi(graphql.PublicApi) Assert.assertNotNull(graphql.Assert.assertNotNull) GraphQLTypeReference.typeRef(graphql.schema.GraphQLTypeReference.typeRef) Collections(java.util.Collections) GraphQLOutputType(graphql.schema.GraphQLOutputType) GraphQLTypeReference(graphql.schema.GraphQLTypeReference) GraphQLUnionType(graphql.schema.GraphQLUnionType) UnionTypeExtensionDefinition(graphql.language.UnionTypeExtensionDefinition) GraphQLObjectType(graphql.schema.GraphQLObjectType)

Example 15 with TypeDefinition

use of graphql.language.TypeDefinition in project graphql-java by graphql-java.

the class SchemaDiff method checkType.

private void checkType(DiffCtx ctx, Type oldType, Type newType) {
    String typeName = getTypeName(oldType);
    // prevent circular references
    if (ctx.examiningType(typeName)) {
        return;
    }
    if (isSystemScalar(typeName)) {
        return;
    }
    if (isReservedType(typeName)) {
        return;
    }
    Optional<TypeDefinition> oldTD = ctx.getOldTypeDef(oldType, TypeDefinition.class);
    Optional<TypeDefinition> newTD = ctx.getNewTypeDef(newType, TypeDefinition.class);
    if (!oldTD.isPresent()) {
        ctx.report(DiffEvent.apiInfo().typeName(typeName).reasonMsg("Type '%s' is missing", typeName).build());
        return;
    }
    TypeDefinition oldDef = oldTD.get();
    ctx.report(DiffEvent.apiInfo().typeName(typeName).typeKind(getTypeKind(oldDef)).reasonMsg("Examining type '%s' ...", typeName).build());
    if (!newTD.isPresent()) {
        ctx.report(DiffEvent.apiBreakage().category(DiffCategory.MISSING).typeName(typeName).typeKind(getTypeKind(oldDef)).reasonMsg("The new API does not have a type called '%s'", typeName).build());
        ctx.exitType();
        return;
    }
    TypeDefinition newDef = newTD.get();
    if (!oldDef.getClass().equals(newDef.getClass())) {
        ctx.report(DiffEvent.apiBreakage().category(DiffCategory.INVALID).typeName(typeName).typeKind(getTypeKind(oldDef)).components(getTypeKind(oldDef), getTypeKind(newDef)).reasonMsg("The new API has changed '%s' from a '%s' to a '%s'", typeName, getTypeKind(oldDef), getTypeKind(newDef)).build());
        ctx.exitType();
        return;
    }
    if (oldDef instanceof ObjectTypeDefinition) {
        checkObjectType(ctx, (ObjectTypeDefinition) oldDef, (ObjectTypeDefinition) newDef);
    }
    if (oldDef instanceof InterfaceTypeDefinition) {
        checkInterfaceType(ctx, (InterfaceTypeDefinition) oldDef, (InterfaceTypeDefinition) newDef);
    }
    if (oldDef instanceof UnionTypeDefinition) {
        checkUnionType(ctx, (UnionTypeDefinition) oldDef, (UnionTypeDefinition) newDef);
    }
    if (oldDef instanceof InputObjectTypeDefinition) {
        checkInputObjectType(ctx, (InputObjectTypeDefinition) oldDef, (InputObjectTypeDefinition) newDef);
    }
    if (oldDef instanceof EnumTypeDefinition) {
        checkEnumType(ctx, (EnumTypeDefinition) oldDef, (EnumTypeDefinition) newDef);
    }
    if (oldDef instanceof ScalarTypeDefinition) {
        checkScalarType(ctx, (ScalarTypeDefinition) oldDef, (ScalarTypeDefinition) newDef);
    }
    ctx.exitType();
}
Also used : ScalarTypeDefinition(graphql.language.ScalarTypeDefinition) InputObjectTypeDefinition(graphql.language.InputObjectTypeDefinition) ObjectTypeDefinition(graphql.language.ObjectTypeDefinition) EnumTypeDefinition(graphql.language.EnumTypeDefinition) InputObjectTypeDefinition(graphql.language.InputObjectTypeDefinition) InterfaceTypeDefinition(graphql.language.InterfaceTypeDefinition) UnionTypeDefinition(graphql.language.UnionTypeDefinition) InputObjectTypeDefinition(graphql.language.InputObjectTypeDefinition) EnumTypeDefinition(graphql.language.EnumTypeDefinition) UnionTypeDefinition(graphql.language.UnionTypeDefinition) OperationTypeDefinition(graphql.language.OperationTypeDefinition) ScalarTypeDefinition(graphql.language.ScalarTypeDefinition) ObjectTypeDefinition(graphql.language.ObjectTypeDefinition) TypeDefinition(graphql.language.TypeDefinition) InterfaceTypeDefinition(graphql.language.InterfaceTypeDefinition)

Aggregations

InterfaceTypeDefinition (graphql.language.InterfaceTypeDefinition)15 ObjectTypeDefinition (graphql.language.ObjectTypeDefinition)15 TypeDefinition (graphql.language.TypeDefinition)15 UnionTypeDefinition (graphql.language.UnionTypeDefinition)15 EnumTypeDefinition (graphql.language.EnumTypeDefinition)13 InputObjectTypeDefinition (graphql.language.InputObjectTypeDefinition)13 ScalarTypeDefinition (graphql.language.ScalarTypeDefinition)13 OperationTypeDefinition (graphql.language.OperationTypeDefinition)12 Type (graphql.language.Type)9 TypeName (graphql.language.TypeName)9 ArrayList (java.util.ArrayList)9 GraphQLError (graphql.GraphQLError)8 ObjectTypeExtensionDefinition (graphql.language.ObjectTypeExtensionDefinition)8 SchemaDefinition (graphql.language.SchemaDefinition)8 SchemaProblem (graphql.schema.idl.errors.SchemaProblem)8 List (java.util.List)8 Map (java.util.Map)8 Directive (graphql.language.Directive)7 EnumValueDefinition (graphql.language.EnumValueDefinition)7 FieldDefinition (graphql.language.FieldDefinition)7