package org.opendaylight.controller.sal.binding.generator.impl;
import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.*;
-import static org.opendaylight.controller.yang.model.util.SchemaContextUtil.findDataSchemaNode;
-import static org.opendaylight.controller.yang.model.util.SchemaContextUtil.findParentModule;
-
-import java.util.*;
+import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Future;
+import javax.management.Notification;
+
import org.opendaylight.controller.binding.generator.util.ReferencedTypeImpl;
import org.opendaylight.controller.binding.generator.util.Types;
import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
import org.opendaylight.controller.sal.binding.model.api.GeneratedType;
import org.opendaylight.controller.sal.binding.model.api.Type;
-import org.opendaylight.controller.sal.binding.model.api.type.builder.*;
+import org.opendaylight.controller.sal.binding.model.api.type.builder.EnumBuilder;
+import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
+import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
+import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.controller.sal.binding.model.api.type.builder.MethodSignatureBuilder;
+import org.opendaylight.controller.sal.binding.yang.types.GroupingDefinitionDependencySort;
import org.opendaylight.controller.sal.binding.yang.types.TypeProviderImpl;
-import org.opendaylight.controller.yang.binding.Notification;
-import org.opendaylight.controller.yang.common.QName;
-import org.opendaylight.controller.yang.common.RpcResult;
-import org.opendaylight.controller.yang.model.api.*;
-import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
-import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
-import org.opendaylight.controller.yang.model.util.DataNodeIterator;
-import org.opendaylight.controller.yang.model.util.ExtendedType;
-import org.opendaylight.controller.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.model.util.UnionType;
public final class BindingGeneratorImpl implements BindingGenerator {
private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
private TypeProvider typeProvider;
private SchemaContext schemaContext;
+ private final Map<SchemaPath, GeneratedType> allGroupings = new HashMap<SchemaPath, GeneratedType>();
public BindingGeneratorImpl() {
super();
final Set<Module> modules = context.getModules();
genTypeBuilders = new HashMap<>();
for (final Module module : modules) {
+ generatedTypes.addAll(allGroupingsToGenTypes(module));
generatedTypes.add(moduleToDataType(module));
generatedTypes.addAll(allTypeDefinitionsToGenTypes(module));
generatedTypes.addAll(allContainersToGenTypes(module));
generatedTypes.addAll(allRPCMethodsToGenType(module));
generatedTypes.addAll(allNotificationsToGenType(module));
generatedTypes.addAll(allIdentitiesToGenTypes(module, context));
- generatedTypes.addAll(allGroupingsToGenTypes(module));
+
}
return generatedTypes;
}
for (final Module contextModule : contextModules) {
final List<Type> generatedTypes = new ArrayList<>();
+ generatedTypes.addAll(allGroupingsToGenTypes(contextModule));
generatedTypes.add(moduleToDataType(contextModule));
generatedTypes.addAll(allTypeDefinitionsToGenTypes(contextModule));
generatedTypes.addAll(allContainersToGenTypes(contextModule));
generatedTypes.addAll(allRPCMethodsToGenType(contextModule));
generatedTypes.addAll(allNotificationsToGenType(contextModule));
generatedTypes.addAll(allIdentitiesToGenTypes(contextModule, context));
- generatedTypes.addAll(allGroupingsToGenTypes(contextModule));
if (modules.contains(contextModule)) {
filteredGenTypes.addAll(generatedTypes);
final List<ContainerSchemaNode> schemaContainers = it.allContainers();
final String basePackageName = moduleNamespaceToPackageName(module);
for (final ContainerSchemaNode container : schemaContainers) {
- generatedTypes.add(containerToGenType(basePackageName, container));
+ if (!container.isAddedByUses()) {
+ generatedTypes.add(containerToGenType(basePackageName, container));
+ }
}
return generatedTypes;
}
final String basePackageName = moduleNamespaceToPackageName(module);
if (schemaLists != null) {
for (final ListSchemaNode list : schemaLists) {
- generatedTypes.addAll(listToGenType(basePackageName, list));
+ if (!list.isAddedByUses()) {
+ generatedTypes.addAll(listToGenType(basePackageName, list));
+ }
}
}
return generatedTypes;
final List<GeneratedType> generatedTypes = new ArrayList<>();
for (final ChoiceNode choice : choiceNodes) {
- if (choice != null) {
+ if ((choice != null) && !choice.isAddedByUses()) {
generatedTypes.addAll(choiceToGeneratedType(basePackageName, choice));
}
}
}
final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data");
+ addInterfaceDefinition(module, moduleDataTypeBuilder);
final String basePackageName = moduleNamespaceToPackageName(module);
if (moduleDataTypeBuilder != null) {
if (rpc != null) {
String rpcName = parseToClassName(rpc.getQName().getLocalName());
- MethodSignatureBuilder method = interfaceBuilder.addMethod(rpcName);
+ String rpcMethodName = parseToValidParamName(rpcName);
+ MethodSignatureBuilder method = interfaceBuilder.addMethod(rpcMethodName);
final List<DataNodeIterator> rpcInOut = new ArrayList<>();
if (input != null) {
rpcInOut.add(new DataNodeIterator(input));
GeneratedTypeBuilder inType = addRawInterfaceDefinition(basePackageName, input, rpcName);
+ addInterfaceDefinition(input, inType);
resolveDataSchemaNodes(basePackageName, inType, input.getChildNodes());
Type inTypeInstance = inType.toInstance();
genRPCTypes.add(inTypeInstance);
Type outTypeInstance = Types.typeForClass(Void.class);
if (output != null) {
rpcInOut.add(new DataNodeIterator(output));
-
GeneratedTypeBuilder outType = addRawInterfaceDefinition(basePackageName, output, rpcName);
+ addInterfaceDefinition(output, outType);
resolveDataSchemaNodes(basePackageName, outType, output.getChildNodes());
outTypeInstance = outType.toInstance();
genRPCTypes.add(outTypeInstance);
List<ContainerSchemaNode> nContainers = it.allContainers();
if ((nContainers != null) && !nContainers.isEmpty()) {
for (final ContainerSchemaNode container : nContainers) {
- genRPCTypes.add(containerToGenType(basePackageName, container));
+ if (!container.isAddedByUses()) {
+ genRPCTypes.add(containerToGenType(basePackageName, container));
+ }
}
}
List<ListSchemaNode> nLists = it.allLists();
if ((nLists != null) && !nLists.isEmpty()) {
for (final ListSchemaNode list : nLists) {
- genRPCTypes.addAll(listToGenType(basePackageName, list));
+ if (!list.isAddedByUses()) {
+ genRPCTypes.addAll(listToGenType(basePackageName, list));
+ }
}
}
}
// Containers
for (ContainerSchemaNode node : it.allContainers()) {
- genNotifyTypes.add(containerToGenType(basePackageName, node));
+ if (!node.isAddedByUses()) {
+ genNotifyTypes.add(containerToGenType(basePackageName, node));
+ }
}
// Lists
for (ListSchemaNode node : it.allLists()) {
- genNotifyTypes.addAll(listToGenType(basePackageName, node));
+ if (!node.isAddedByUses()) {
+ genNotifyTypes.addAll(listToGenType(basePackageName, node));
+ }
}
final GeneratedTypeBuilder notificationTypeBuilder = addDefaultInterfaceDefinition(basePackageName,
notification);
final List<Type> genTypes = new ArrayList<>();
final String basePackageName = moduleNamespaceToPackageName(module);
final Set<GroupingDefinition> groupings = module.getGroupings();
- if (groupings != null && !groupings.isEmpty()) {
- for (final GroupingDefinition grouping : groupings) {
- genTypes.add(groupingToGenType(basePackageName, grouping));
- }
+ List<GroupingDefinition> groupingsSortedByDependencies;
+ // groupingsSortedByDependencies =
+ // sortGroupingDefinitionsByUses(groupings);
+ groupingsSortedByDependencies = GroupingDefinitionDependencySort.sort(groupings);
+
+ for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
+ GeneratedType genType = groupingToGenType(basePackageName, grouping);
+ genTypes.add(genType);
+ SchemaPath schemaPath = grouping.getPath();
+ allGroupings.put(schemaPath, genType);
}
return genTypes;
}
if ((targetSchemaNode != null) && (targetSchemaNode.getQName() != null)
&& (targetSchemaNode.getQName().getLocalName() != null)) {
final Module targetModule = findParentModule(schemaContext, targetSchemaNode);
-
final String targetBasePackage = moduleNamespaceToPackageName(targetModule);
final String targetPackageName = packageNameForGeneratedType(targetBasePackage, targetSchemaNode.getPath());
-
final String targetSchemaNodeName = targetSchemaNode.getQName().getLocalName();
final Set<DataSchemaNode> augChildNodes = augSchema.getChildNodes();
- final GeneratedTypeBuilder augTypeBuilder = addRawAugmentGenTypeDefinition(augmentPackageName,
- targetPackageName, targetSchemaNodeName, augSchema);
- if (augTypeBuilder != null) {
- genTypes.add(augTypeBuilder.toInstance());
+
+ if (!(targetSchemaNode instanceof ChoiceNode)) {
+ final GeneratedTypeBuilder augTypeBuilder = addRawAugmentGenTypeDefinition(augmentPackageName,
+ targetPackageName, targetSchemaNodeName, augSchema);
+ addInterfaceDefinition(augSchema, augTypeBuilder);
+
+ final GeneratedType augType = augTypeBuilder.toInstance();
+ genTypes.add(augType);
+ } else {
+ final Type refChoiceType = new ReferencedTypeImpl(targetPackageName,
+ parseToClassName(targetSchemaNodeName));
+ final ChoiceNode choiceTarget = (ChoiceNode) targetSchemaNode;
+ final Set<ChoiceCaseNode> choiceCaseNodes = choiceTarget.getCases();
+ genTypes.addAll(augmentCasesToGenTypes(augmentPackageName, refChoiceType, choiceCaseNodes));
}
genTypes.addAll(augmentationBodyToGenTypes(augmentPackageName, augChildNodes));
+ }
+ return genTypes;
+ }
+ private List<GeneratedType> augmentCasesToGenTypes(final String augmentPackageName, final Type refChoiceType,
+ final Set<ChoiceCaseNode> choiceCaseNodes) {
+ if (augmentPackageName == null) {
+ throw new IllegalArgumentException("Augment Package Name string cannot be NULL!");
+ }
+ if (choiceCaseNodes == null) {
+ throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
}
+ final List<GeneratedType> genTypes = generateTypesFromAugmentedChoiceCases(augmentPackageName, refChoiceType,
+ choiceCaseNodes);
return genTypes;
}
} else if (childNode instanceof ListSchemaNode) {
genTypes.addAll(listToGenType(augBasePackageName, (ListSchemaNode) childNode));
}
+ } else if (childNode instanceof ChoiceNode) {
+ final ChoiceNode choice = (ChoiceNode) childNode;
+ for (final ChoiceCaseNode caseNode : choice.getCases()) {
+ augSchemaIts.add(new DataNodeIterator(caseNode));
+ }
+ genTypes.addAll(choiceToGeneratedType(augBasePackageName, (ChoiceNode) childNode));
}
}
for (final DataNodeIterator it : augSchemaIts) {
final List<ContainerSchemaNode> augContainers = it.allContainers();
final List<ListSchemaNode> augLists = it.allLists();
+ final List<ChoiceNode> augChoices = it.allChoices();
- if ((augContainers != null) && !augContainers.isEmpty()) {
+ if (augContainers != null) {
for (final ContainerSchemaNode container : augContainers) {
genTypes.add(containerToGenType(augBasePackageName, container));
}
}
- if ((augLists != null) && !augLists.isEmpty()) {
+ if (augLists != null) {
for (final ListSchemaNode list : augLists) {
genTypes.addAll(listToGenType(augBasePackageName, list));
}
}
+ if (augChoices != null) {
+ for (final ChoiceNode choice : augChoices) {
+ genTypes.addAll(choiceToGeneratedType(augBasePackageName, choice));
+ }
+ }
}
return genTypes;
}
final GeneratedTypeBuilder typeBuilder, final Set<DataSchemaNode> schemaNodes) {
if ((schemaNodes != null) && (typeBuilder != null)) {
for (final DataSchemaNode schemaNode : schemaNodes) {
- if (schemaNode.isAugmenting()) {
+ if (schemaNode.isAugmenting() || schemaNode.isAddedByUses()) {
continue;
}
addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder);
}
final String choiceName = choiceNode.getQName().getLocalName();
- if (choiceName != null) {
+ if (choiceName != null && !choiceNode.isAddedByUses()) {
final String packageName = packageNameForGeneratedType(basePackageName, choiceNode.getPath());
final GeneratedTypeBuilder choiceType = addDefaultInterfaceDefinition(packageName, choiceNode);
constructGetter(typeBuilder, choiceName, choiceNode.getDescription(), choiceType);
final List<GeneratedType> generatedTypes = new ArrayList<>();
for (final ChoiceCaseNode caseNode : caseNodes) {
- if (caseNode != null) {
+ if (caseNode != null && !caseNode.isAddedByUses()) {
+ final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
+ final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
+ caseTypeBuilder.addImplementsType(refChoiceType);
+
+ final Set<DataSchemaNode> childNodes = caseNode.getChildNodes();
+ if (childNodes != null) {
+ resolveDataSchemaNodes(basePackageName, caseTypeBuilder, childNodes);
+ }
+ generatedTypes.add(caseTypeBuilder.toInstance());
+ }
+ }
+
+ return generatedTypes;
+ }
+
+ private List<GeneratedType> generateTypesFromAugmentedChoiceCases(final String basePackageName,
+ final Type refChoiceType, final Set<ChoiceCaseNode> caseNodes) {
+ if (basePackageName == null) {
+ throw new IllegalArgumentException("Base Package Name cannot be NULL!");
+ }
+ if (refChoiceType == null) {
+ throw new IllegalArgumentException("Referenced Choice Type cannot be NULL!");
+ }
+ if (caseNodes == null) {
+ throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
+ }
+
+ final List<GeneratedType> generatedTypes = new ArrayList<>();
+ for (final ChoiceCaseNode caseNode : caseNodes) {
+ if (caseNode != null && caseNode.isAugmenting()) {
final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
caseTypeBuilder.addImplementsType(refChoiceType);
leafDesc = "";
}
- if (leafName != null) {
+ if (leafName != null && !leaf.isAddedByUses()) {
final TypeDefinition<?> typeDef = leaf.getType();
Type returnType = null;
- if (!(typeDef instanceof EnumTypeDefinition)) {
+ if (typeDef instanceof EnumTypeDefinition) {
returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
- } else {
final EnumTypeDefinition enumTypeDef = enumTypeDefFromExtendedType(typeDef);
final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName,
typeBuilder);
returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
}
((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
+ } else if (typeDef instanceof UnionType) {
+ GeneratedTOBuilder genTOBuilder = addEnclosedTOToTypeBuilder(typeDef, typeBuilder, leafName);
+ if (genTOBuilder != null) {
+ returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
+ }
+ } else if (typeDef instanceof BitsTypeDefinition) {
+ GeneratedTOBuilder genTOBuilder = addEnclosedTOToTypeBuilder(typeDef, typeBuilder, leafName);
+ if (genTOBuilder != null) {
+ returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
+ }
+ } else {
+ returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
}
if (returnType != null) {
constructGetter(typeBuilder, leafName, leafDesc, returnType);
- if (!leaf.isConfiguration()) {
- constructSetter(typeBuilder, leafName, leafDesc, returnType);
- }
return true;
}
}
leafDesc = "";
}
- if (leafName != null) {
+ if (leafName != null && !leaf.isAddedByUses()) {
final TypeDefinition<?> typeDef = leaf.getType();
// TODO: properly resolve enum types
nodeDesc = "";
}
- if (nodeName != null) {
+ if (nodeName != null && !node.isAddedByUses()) {
final TypeDefinition<?> type = node.getType();
final Type listType = Types.listTypeFor(typeProvider.javaTypeForSchemaDefinitionType(type));
constructGetter(typeBuilder, nodeName, nodeDesc, listType);
- if (!node.isConfiguration()) {
- constructSetter(typeBuilder, nodeName, nodeDesc, listType);
- }
return true;
}
}
if ((containerNode != null) && (typeBuilder != null)) {
final String nodeName = containerNode.getQName().getLocalName();
- if (nodeName != null) {
+ if (nodeName != null && !containerNode.isAddedByUses()) {
final String packageName = packageNameForGeneratedType(basePackageName, containerNode.getPath());
final GeneratedTypeBuilder rawGenType = addDefaultInterfaceDefinition(packageName, containerNode);
if ((schemaNode != null) && (typeBuilder != null)) {
final String listName = schemaNode.getQName().getLocalName();
- if (listName != null) {
+ if (listName != null && !schemaNode.isAddedByUses()) {
final String packageName = packageNameForGeneratedType(basePackageName, schemaNode.getPath());
final GeneratedTypeBuilder rawGenType = addDefaultInterfaceDefinition(packageName, schemaNode);
constructGetter(typeBuilder, listName, schemaNode.getDescription(), Types.listTypeFor(rawGenType));
- if (!schemaNode.isConfiguration()) {
- constructSetter(typeBuilder, listName, schemaNode.getDescription(), Types.listTypeFor(rawGenType));
- }
return true;
}
}
}
/**
- * Method instantiates new Generated Type Builder and sets the implements definitions of Data Object and
- * Augmentable.
+ * Method instantiates new Generated Type Builder and sets the implements
+ * definitions of Data Object and Augmentable.
*
- * @param packageName Generated Type Package Name
- * @param schemaNode Schema Node definition
+ * @param packageName
+ * Generated Type Package Name
+ * @param schemaNode
+ * Schema Node definition
* @return Generated Type Builder instance for Schema Node definition
*/
private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
final GeneratedTypeBuilder builder = addRawInterfaceDefinition(packageName, schemaNode, "");
builder.addImplementsType(Types.DATA_OBJECT);
- builder.addImplementsType(Types.augmentableTypeFor(builder));
+ if (!(schemaNode instanceof GroupingDefinition)) {
+ builder.addImplementsType(Types.augmentableTypeFor(builder));
+ }
+
+ if (schemaNode instanceof DataNodeContainer) {
+ addInterfaceDefinition((DataNodeContainer) schemaNode, builder);
+ }
+
return builder;
}
}
return genTOBuilder;
}
+
+ private GeneratedTOBuilder addEnclosedTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
+ String leafName) {
+ String className = parseToClassName(leafName);
+ GeneratedTOBuilder genTOBuilder = null;
+ if (typeDef instanceof UnionType) {
+ genTOBuilder = ((TypeProviderImpl) typeProvider).addUnionGeneratedTypeDefinition(
+ typeBuilder.getFullyQualifiedName(), typeDef, className);
+ } else if (typeDef instanceof BitsTypeDefinition) {
+ genTOBuilder = ((TypeProviderImpl) typeProvider).bitsTypedefToTransferObject(
+ typeBuilder.getFullyQualifiedName(), typeDef, className);
+ }
+ if (genTOBuilder != null) {
+ typeBuilder.addEnclosingTransferObject(genTOBuilder);
+ return genTOBuilder;
+ }
+ return null;
+
+ }
+
+ /**
+ * Adds the implemented types to type builder. The method passes through the
+ * list of elements which contains {@code dataNodeContainer} and adds them
+ * as <i>implements type</i> to <code>builder</code>
+ *
+ * @param dataNodeContainer
+ * element which contains the list of used YANG groupings
+ * @param builder
+ * builder to which are added implemented types according to
+ * <code>dataNodeContainer</code>
+ * @return generated type builder which contains implemented types
+ */
+ private GeneratedTypeBuilder addInterfaceDefinition(final DataNodeContainer dataNodeContainer,
+ final GeneratedTypeBuilder builder) {
+ for (UsesNode usesNode : dataNodeContainer.getUses()) {
+ if (usesNode.getGroupingPath() != null) {
+ GeneratedType genType = allGroupings.get(usesNode.getGroupingPath());
+ builder.addImplementsType(new ReferencedTypeImpl(genType.getPackageName(), genType.getName()));
+ }
+ }
+ return builder;
+ }
+
}