From 3756ba57f6ebc5e3d256c25c220ae5b83f41eb22 Mon Sep 17 00:00:00 2001 From: Martin Schreier Date: Mon, 3 Jan 2022 20:26:49 +0100 Subject: Switching to generics for cache implementation --- .../src/test/resources/spring-context.xml | 2 + .../src/main/resources/META-INF/spring-context.xml | 2 + .../src/test/resources/spring-context.xml | 2 + .../managed/DefaultManagedRepositoryAdmin.java | 2 +- .../DefaultRedbackRuntimeConfigurationAdmin.java | 5 +- .../src/test/resources/spring-context.xml | 2 + .../svc/maven/MavenManagedRepositoryService.java | 4 +- .../DefaultRedbackRuntimeConfigurationService.java | 3 +- .../rest/services/DefaultRepositoriesService.java | 2 +- .../src/main/resources/META-INF/spring-context.xml | 4 +- .../rest/v2/svc/AbstractNativeRestServices.java | 2 +- .../NativeMavenManagedRepositoryServiceTest.java | 88 --------------------- .../NativeMavenManagedRepositoryServiceTest.java | 89 ++++++++++++++++++++++ .../src/main/webapp/WEB-INF/applicationContext.xml | 24 ++++++ .../metadata/model/ProjectVersionMetadata.java | 5 +- .../repository/DefaultMetadataResolver.java | 8 +- .../src/main/resources/META-INF/spring-context.xml | 4 +- 17 files changed, 145 insertions(+), 103 deletions(-) delete mode 100644 archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/NativeMavenManagedRepositoryServiceTest.java create mode 100644 archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/maven/NativeMavenManagedRepositoryServiceTest.java (limited to 'archiva-modules') diff --git a/archiva-modules/archiva-base/archiva-configuration/src/test/resources/spring-context.xml b/archiva-modules/archiva-base/archiva-configuration/src/test/resources/spring-context.xml index 46b2f71d8..4eb7b5be6 100755 --- a/archiva-modules/archiva-base/archiva-configuration/src/test/resources/spring-context.xml +++ b/archiva-modules/archiva-base/archiva-configuration/src/test/resources/spring-context.xml @@ -324,6 +324,8 @@ + + diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/resources/META-INF/spring-context.xml b/archiva-modules/archiva-base/archiva-policies/src/main/resources/META-INF/spring-context.xml index e42a9b8e7..2a9dc119e 100644 --- a/archiva-modules/archiva-base/archiva-policies/src/main/resources/META-INF/spring-context.xml +++ b/archiva-modules/archiva-base/archiva-policies/src/main/resources/META-INF/spring-context.xml @@ -37,6 +37,8 @@ + + diff --git a/archiva-modules/archiva-base/archiva-policies/src/test/resources/spring-context.xml b/archiva-modules/archiva-base/archiva-policies/src/test/resources/spring-context.xml index 91426974c..dfe404519 100755 --- a/archiva-modules/archiva-base/archiva-policies/src/test/resources/spring-context.xml +++ b/archiva-modules/archiva-base/archiva-policies/src/test/resources/spring-context.xml @@ -30,6 +30,8 @@ + + diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java index da240c111..7a8a98291 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/managed/DefaultManagedRepositoryAdmin.java @@ -109,7 +109,7 @@ public class DefaultManagedRepositoryAdmin @Inject @Named(value = "cache#namespaces") - private Cache> namespacesCache; + private Cache> namespacesCache; @Inject private IndexManagerFactory indexManagerFactory; diff --git a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/runtime/DefaultRedbackRuntimeConfigurationAdmin.java b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/runtime/DefaultRedbackRuntimeConfigurationAdmin.java index 1ed25d946..d15990189 100644 --- a/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/runtime/DefaultRedbackRuntimeConfigurationAdmin.java +++ b/archiva-modules/archiva-base/archiva-repository-admin/archiva-repository-admin-default/src/main/java/org/apache/archiva/admin/repository/runtime/DefaultRedbackRuntimeConfigurationAdmin.java @@ -34,6 +34,7 @@ import org.apache.archiva.configuration.util.ConfigMapper; import org.apache.archiva.redback.configuration.UserConfiguration; import org.apache.archiva.redback.configuration.UserConfigurationException; import org.apache.archiva.redback.configuration.UserConfigurationKeys; +import org.apache.archiva.redback.users.User; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -100,13 +101,13 @@ public class DefaultRedbackRuntimeConfigurationAdmin LDAP_MAPPER.addBooleanMapping( LDAP_BIND_AUTHENTICATOR_ENABLED, LdapConfiguration::isBindAuthenticatorEnabled ); } - private Cache usersCache; + private Cache usersCache; @Inject public DefaultRedbackRuntimeConfigurationAdmin( ArchivaConfiguration archivaConfiguration,// @Named( value = "userConfiguration#redback" ) // UserConfiguration userConfiguration, - @Named( value = "cache#users" ) Cache usersCache ) + @Named( value = "cache#users" ) Cache usersCache ) { this.archivaConfiguration = archivaConfiguration; this.userConfiguration = userConfiguration; diff --git a/archiva-modules/archiva-maven/archiva-maven-proxy/src/test/resources/spring-context.xml b/archiva-modules/archiva-maven/archiva-maven-proxy/src/test/resources/spring-context.xml index f9fccfbc1..18697b302 100755 --- a/archiva-modules/archiva-maven/archiva-maven-proxy/src/test/resources/spring-context.xml +++ b/archiva-modules/archiva-maven/archiva-maven-proxy/src/test/resources/spring-context.xml @@ -68,6 +68,8 @@ + + diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/v2/svc/maven/MavenManagedRepositoryService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/v2/svc/maven/MavenManagedRepositoryService.java index f8e3f314c..c8cd8522c 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/v2/svc/maven/MavenManagedRepositoryService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/v2/svc/maven/MavenManagedRepositoryService.java @@ -67,7 +67,7 @@ import static org.apache.archiva.security.common.ArchivaRoleConstants.*; * * * - * @author Martin Stockhammer + * @author Martin Schreier * @since 3.0 */ @Schema( name = "MavenManagedRepositoryService", description = "Managing and configuration of managed maven repositories" ) @@ -425,7 +425,7 @@ public interface MavenManagedRepositoryService permissions = { OPERATION_MANAGE_CONFIGURATION, OPERATION_DELETE_NAMESPACE }, resource = "{id}" ) - @Operation( summary = "Removes a group and all subfolders from the repository", + @Operation( summary = "Removes a maven group and all containing artifacts and sub groups from the repository", security = { @SecurityRequirement( name = OPERATION_MANAGE_CONFIGURATION diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRedbackRuntimeConfigurationService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRedbackRuntimeConfigurationService.java index 81b58aa94..ea3f17948 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRedbackRuntimeConfigurationService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRedbackRuntimeConfigurationService.java @@ -33,6 +33,7 @@ import org.apache.archiva.redback.policy.CookieSettings; import org.apache.archiva.redback.policy.PasswordRule; import org.apache.archiva.redback.rbac.RBACManager; import org.apache.archiva.redback.role.RoleManager; +import org.apache.archiva.redback.users.User; import org.apache.archiva.redback.users.UserManager; import org.apache.archiva.rest.api.model.ActionStatus; import org.apache.archiva.rest.api.model.RBACManagerImplementationInformation; @@ -88,7 +89,7 @@ public class DefaultRedbackRuntimeConfigurationService @Inject @Named(value = "cache#users") - private Cache usersCache; + private Cache usersCache; @Inject private LdapUserMapper ldapUserMapper; diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRepositoriesService.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRepositoriesService.java index 02e4f9ecb..f7871e75a 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRepositoriesService.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultRepositoriesService.java @@ -159,7 +159,7 @@ public class DefaultRepositoriesService */ @Inject @Named(value = "cache#namespaces") - private Cache> namespacesCache; + private Cache> namespacesCache; private List algorithms = Arrays.asList(ChecksumAlgorithm.SHA256, ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 ); diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/resources/META-INF/spring-context.xml b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/resources/META-INF/spring-context.xml index 6f5f1fc1f..044998678 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/resources/META-INF/spring-context.xml +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/resources/META-INF/spring-context.xml @@ -128,11 +128,13 @@ + + - + diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/AbstractNativeRestServices.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/AbstractNativeRestServices.java index 4949e55a7..b5b185684 100644 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/AbstractNativeRestServices.java +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/AbstractNativeRestServices.java @@ -68,7 +68,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; * Native REST tests do not use the JAX-RS client and can be used with a remote * REST API service. The tests * - * @author Martin Stockhammer + * @author Martin Schreier */ @Tag( "rest-native" ) @Tag( "rest-v2" ) diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/NativeMavenManagedRepositoryServiceTest.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/NativeMavenManagedRepositoryServiceTest.java deleted file mode 100644 index d078b454e..000000000 --- a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/NativeMavenManagedRepositoryServiceTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.apache.archiva.rest.v2.svc; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -import io.restassured.path.json.JsonPath; -import io.restassured.response.Response; -import org.apache.archiva.rest.api.v2.model.MavenManagedRepository; -import org.apache.archiva.rest.api.v2.svc.RestConfiguration; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.TestMethodOrder; - -import java.util.List; - -import static io.restassured.RestAssured.given; -import static io.restassured.http.ContentType.JSON; -import static org.junit.jupiter.api.Assertions.*; - -/** - * @author Martin Stockhammer - */ -@TestInstance( TestInstance.Lifecycle.PER_CLASS ) -@Tag( "rest-native" ) -@TestMethodOrder( MethodOrderer.OrderAnnotation.class ) -@DisplayName( "Native REST tests for V2 ManagedRepositoryService" ) -public class NativeMavenManagedRepositoryServiceTest extends AbstractNativeRestServices -{ - @Override - protected String getServicePath( ) - { - return "/repositories/maven/managed"; - } - - @BeforeAll - void setup( ) throws Exception - { - super.setupNative( ); - } - - @AfterAll - void destroy( ) throws Exception - { - super.shutdownNative( ); - } - - @Test - @Order( 1 ) - void testGetRepositories( ) - { - String token = getAdminToken( ); - Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) - .when( ) - .get( "" ) - .then( ).statusCode( 200 ).extract( ).response( ); - JsonPath json = response.getBody( ).jsonPath( ); - assertEquals( 2, json.getInt( "pagination.total_count" ) ); - assertEquals( 0, json.getInt( "pagination.offset" ) ); - assertEquals( Integer.valueOf( RestConfiguration.DEFAULT_PAGE_LIMIT ), json.getInt( "pagination.limit" ) ); - List repositories = json.getList( "data", MavenManagedRepository.class ); - assertEquals( "internal", repositories.get( 0 ).getId( ) ); - assertEquals( "snapshots", repositories.get( 1 ).getId( ) ); - } - - - -} diff --git a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/maven/NativeMavenManagedRepositoryServiceTest.java b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/maven/NativeMavenManagedRepositoryServiceTest.java new file mode 100644 index 000000000..9a8f932be --- /dev/null +++ b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/test/java/org/apache/archiva/rest/v2/svc/maven/NativeMavenManagedRepositoryServiceTest.java @@ -0,0 +1,89 @@ +package org.apache.archiva.rest.v2.svc.maven; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import io.restassured.path.json.JsonPath; +import io.restassured.response.Response; +import org.apache.archiva.rest.api.v2.model.MavenManagedRepository; +import org.apache.archiva.rest.api.v2.svc.RestConfiguration; +import org.apache.archiva.rest.v2.svc.AbstractNativeRestServices; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestMethodOrder; + +import java.util.List; + +import static io.restassured.RestAssured.given; +import static io.restassured.http.ContentType.JSON; +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Martin Schreier + */ +@TestInstance( TestInstance.Lifecycle.PER_CLASS ) +@Tag( "rest-native" ) +@TestMethodOrder( MethodOrderer.OrderAnnotation.class ) +@DisplayName( "Native REST tests for V2 ManagedRepositoryService" ) +public class NativeMavenManagedRepositoryServiceTest extends AbstractNativeRestServices +{ + @Override + protected String getServicePath( ) + { + return "/repositories/maven/managed"; + } + + @BeforeAll + void setup( ) throws Exception + { + super.setupNative( ); + } + + @AfterAll + void destroy( ) throws Exception + { + super.shutdownNative( ); + } + + @Test + @Order( 1 ) + void testGetRepositories( ) + { + String token = getAdminToken( ); + Response response = given( ).spec( getRequestSpec( token ) ).contentType( JSON ) + .when( ) + .get( "" ) + .then( ).statusCode( 200 ).extract( ).response( ); + JsonPath json = response.getBody( ).jsonPath( ); + assertEquals( 2, json.getInt( "pagination.total_count" ) ); + assertEquals( 0, json.getInt( "pagination.offset" ) ); + assertEquals( Integer.valueOf( RestConfiguration.DEFAULT_PAGE_LIMIT ), json.getInt( "pagination.limit" ) ); + List repositories = json.getList( "data", MavenManagedRepository.class ); + assertEquals( "internal", repositories.get( 0 ).getId( ) ); + assertEquals( "snapshots", repositories.get( 1 ).getId( ) ); + } + + + +} diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml index 0a64d5880..5751f60ea 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml @@ -119,6 +119,8 @@ + + @@ -132,6 +134,8 @@ + + @@ -147,6 +151,8 @@ + + @@ -158,6 +164,8 @@ + + @@ -169,6 +177,8 @@ + + @@ -180,6 +190,8 @@ + + @@ -191,6 +203,8 @@ + + @@ -202,6 +216,8 @@ + + @@ -217,6 +233,8 @@ + + @@ -228,6 +246,8 @@ + + @@ -239,6 +259,8 @@ + + @@ -250,6 +272,8 @@ + + diff --git a/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/ProjectVersionMetadata.java b/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/ProjectVersionMetadata.java index c6b749d6c..13ebf3849 100644 --- a/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/ProjectVersionMetadata.java +++ b/archiva-modules/metadata/metadata-model/src/main/java/org/apache/archiva/metadata/model/ProjectVersionMetadata.java @@ -20,6 +20,7 @@ package org.apache.archiva.metadata.model; */ import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -28,8 +29,10 @@ import java.util.Properties; @XmlRootElement( name = "projectVersionMetadata" ) public class ProjectVersionMetadata - extends FacetedMetadata + extends FacetedMetadata implements Serializable { + + private static final long serialVersionUID = 5506968284780639002L; /** * id is the version */ diff --git a/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/DefaultMetadataResolver.java b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/DefaultMetadataResolver.java index e94ff0969..b8903dfea 100644 --- a/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/DefaultMetadataResolver.java +++ b/archiva-modules/metadata/metadata-repository-api/src/main/java/org/apache/archiva/metadata/repository/DefaultMetadataResolver.java @@ -93,7 +93,7 @@ public class DefaultMetadataResolver */ @Inject @Named( value = "cache#namespaces" ) - private Cache> namespacesCache; + private Cache> namespacesCache; @Override public ProjectVersionMetadata resolveProjectVersion( RepositorySession session, String repoId, String namespace, @@ -193,7 +193,7 @@ public class DefaultMetadataResolver try { - Collection namespaces = namespacesCache.get( repoId ); + List namespaces = namespacesCache.get( repoId ); if ( namespaces != null ) { return namespaces; @@ -246,7 +246,7 @@ public class DefaultMetadataResolver { MetadataRepository metadataRepository = session.getRepository(); String cacheKey = repoId + "-" + namespace; - Collection namespaces = namespacesCache.get( cacheKey ); + List namespaces = namespacesCache.get( cacheKey ); if ( namespaces == null ) { namespaces = metadataRepository.getChildNamespaces( session, repoId, namespace ); @@ -299,7 +299,7 @@ public class DefaultMetadataResolver Collection exclusions = new ArrayList<>( projects ); String cacheKey = repoId + "-" + namespace; - Collection namespaces = namespacesCache.get( cacheKey ); + List namespaces = namespacesCache.get( cacheKey ); if ( namespaces == null ) { namespaces = metadataRepository.getChildNamespaces( session, repoId, namespace ); diff --git a/archiva-modules/metadata/metadata-repository-api/src/main/resources/META-INF/spring-context.xml b/archiva-modules/metadata/metadata-repository-api/src/main/resources/META-INF/spring-context.xml index 06b3213a5..6f4964fa4 100644 --- a/archiva-modules/metadata/metadata-repository-api/src/main/resources/META-INF/spring-context.xml +++ b/archiva-modules/metadata/metadata-repository-api/src/main/resources/META-INF/spring-context.xml @@ -41,11 +41,13 @@ + + - + -- cgit v1.2.3