diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml
index 7a2d3a228e..90d67f742f 100644
--- a/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/classified-content-context.xml
@@ -41,6 +41,7 @@
class="org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceImpl"
parent="baseService" init-method="init">
+
diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml
index d3fb16bc30..b2dfe6af60 100644
--- a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml
@@ -23,6 +23,7 @@
+
@@ -39,12 +40,21 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/patch/rm-patch-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/patch/rm-patch-context.xml
index 784324a4ce..261e1a28b6 100755
--- a/rm-server/config/alfresco/module/org_alfresco_module_rm/patch/rm-patch-context.xml
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/patch/rm-patch-context.xml
@@ -4,34 +4,35 @@
-
+
-
-
+
+
-
-
-
-
+
+
+
+
-
+
-
+
-
+
-
+
+
diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/patch/rm-patch-v30-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/patch/rm-patch-v30-context.xml
new file mode 100644
index 0000000000..e20ca25d0b
--- /dev/null
+++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/patch/rm-patch-v30-context.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/BootstrapImporterModuleComponent.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/BootstrapImporterModuleComponent.java
index f204829fe6..b426c26cb5 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/BootstrapImporterModuleComponent.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/BootstrapImporterModuleComponent.java
@@ -40,9 +40,11 @@ public class BootstrapImporterModuleComponent extends ImporterModuleComponent
/** module patch executer */
private ModulePatchExecuter modulePatchExecuter;
-
+
/** record contributors group bootstrap component */
private RecordContributorsGroupBootstrapComponent recordContributorsGroupBootstrapComponent;
+ /** Clearances for special users bootstrap component. */
+ private ClearancesForSpecialUsersBootstrapComponent clearancesForSpecialUsersBootstrapComponent;
/**
* @param nodeService node service
@@ -57,8 +59,8 @@ public class BootstrapImporterModuleComponent extends ImporterModuleComponent
*/
public void setModulePatchExecuter(ModulePatchExecuter modulePatchExecuter)
{
- this.modulePatchExecuter = modulePatchExecuter;
- }
+ this.modulePatchExecuter = modulePatchExecuter;
+ }
/**
* @param recordContributorsGroupBootstrapComponent record contributors group bootstrap component
@@ -67,7 +69,16 @@ public class BootstrapImporterModuleComponent extends ImporterModuleComponent
{
this.recordContributorsGroupBootstrapComponent = recordContributorsGroupBootstrapComponent;
}
-
+
+ /**
+ * @param clearancesForSpecialUsersBootstrapComponent The bootstrap component that give the admin and system users
+ * the maximum clearance.
+ */
+ public void setClearancesForSpecialUsersBootstrapComponent(ClearancesForSpecialUsersBootstrapComponent clearancesForSpecialUsersBootstrapComponent)
+ {
+ this.clearancesForSpecialUsersBootstrapComponent = clearancesForSpecialUsersBootstrapComponent;
+ }
+
/**
* Need to check whether this module has already been executed.
*
@@ -80,9 +91,10 @@ public class BootstrapImporterModuleComponent extends ImporterModuleComponent
if (!nodeService.exists(nodeRef))
{
super.executeInternal();
-
- // bootstrap the record contributors group
+
+ // Bootstrap creation of initial data.
recordContributorsGroupBootstrapComponent.createRecordContributorsGroup();
+ clearancesForSpecialUsersBootstrapComponent.createClearancesForSpecialUsers();
// init module schema number
modulePatchExecuter.initSchemaVersion();
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ClearancesForSpecialUsersBootstrapComponent.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ClearancesForSpecialUsersBootstrapComponent.java
new file mode 100644
index 0000000000..cecbc9a0c4
--- /dev/null
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ClearancesForSpecialUsersBootstrapComponent.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2005-2015 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.module.org_alfresco_module_rm.bootstrap;
+
+import java.io.Serializable;
+
+import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceBootstrap;
+import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
+import org.alfresco.module.org_alfresco_module_rm.patch.v30.RMv30ClearancesForSpecialUsers;
+import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.PersonService;
+
+/**
+ * Provide the highest clearance to the admin and system users. This needs to be run once (either bootstrapped into a
+ * fresh system, or as part of an upgrade in {@link RMv30ClearancesForSpecialUsers}) per installation.
+ *
+ * @author tpage
+ */
+public class ClearancesForSpecialUsersBootstrapComponent implements ClassifiedContentModel
+{
+ private AuthenticationUtil authenticationUtil;
+ private NodeService nodeService;
+ private PersonService personService;
+ private ClassificationServiceBootstrap classificationServiceBootstrap;
+
+ public void setAuthenticationUtil(AuthenticationUtil authenticationUtil) { this.authenticationUtil = authenticationUtil; }
+ public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; }
+ public void setPersonService(PersonService personService) { this.personService = personService; }
+ public void setClassificationServiceBootstrap(ClassificationServiceBootstrap classificationServiceBootstrap) { this.classificationServiceBootstrap = classificationServiceBootstrap; }
+
+ /**
+ * Give the admin and system users the maximum clearance.
+ */
+ public void createClearancesForSpecialUsers()
+ {
+ // Ensure the classification levels are loaded before this patch runs. (Nb. This will result in the
+ // classification service bootstrap method being called twice on the start-up that includes this call).
+ classificationServiceBootstrap.onBootstrap(null);
+
+ Serializable mostSecureLevel = classificationServiceBootstrap.getClassificationLevelManager()
+ .getMostSecureLevel().getId();
+ String systemUserName = authenticationUtil.getSystemUserName();
+ NodeRef system = personService.getPerson(systemUserName);
+ nodeService.setProperty(system, PROP_CLEARANCE_LEVEL, mostSecureLevel);
+ String adminUserName = authenticationUtil.getAdminUserName();
+ NodeRef admin = personService.getPerson(adminUserName);
+ nodeService.setProperty(admin, PROP_CLEARANCE_LEVEL, mostSecureLevel);
+ }
+}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java
index 52e50a7858..d80b75cf90 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationService.java
@@ -34,7 +34,8 @@ import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationS
public interface ClassificationService
{
/**
- * Returns an immutable list of the defined classification levels.
+ * Returns an immutable list of the defined classification levels visible to the current user.
+ *
* @return classification levels in descending order from highest to lowest
* (where fewer users have access to the highest classification levels
* and therefore access to the most restricted documents).
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java
index b75d8c174d..ec2ce30787 100644
--- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/classification/ClassificationServiceImpl.java
@@ -40,13 +40,12 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
private ClassificationLevelManager levelManager;
/** The classification reasons currently configured in this server. */
private ClassificationReasonManager reasonManager;
+ private SecurityClearanceService securityClearanceService;
private ClassificationServiceBootstrap classificationServiceBootstrap;
public void setNodeService(NodeService service) { this.nodeService = service; }
- public void setClassificationServiceBootstrap(ClassificationServiceBootstrap classificationServiceBootstrap)
- {
- this.classificationServiceBootstrap = classificationServiceBootstrap;
- }
+ public void setSecurityClearanceService(SecurityClearanceService securityClearanceService) { this.securityClearanceService = securityClearanceService; }
+ public void setClassificationServiceBootstrap(ClassificationServiceBootstrap classificationServiceBootstrap) { this.classificationServiceBootstrap = classificationServiceBootstrap; }
/** Store the references to the classification level and reason managers in this class. */
public void init()
@@ -78,8 +77,8 @@ public class ClassificationServiceImpl extends ServiceBaseImpl
{
return Collections.emptyList();
}
- // FIXME Currently assume user has highest security clearance, this should be fixed as part of RM-2112.
- ClassificationLevel usersLevel = levelManager.getMostSecureLevel();
+ SecurityClearance securityClearance = securityClearanceService.getUserSecurityClearance();
+ ClassificationLevel usersLevel = securityClearance.getClearanceLevel().getHighestClassificationLevel();
return restrictList(levelManager.getClassificationLevels(), usersLevel);
}
diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/v30/RMv30ClearancesForSpecialUsers.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/v30/RMv30ClearancesForSpecialUsers.java
new file mode 100644
index 0000000000..cd3c9445ad
--- /dev/null
+++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/patch/v30/RMv30ClearancesForSpecialUsers.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2005-2015 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.module.org_alfresco_module_rm.patch.v30;
+
+import org.alfresco.module.org_alfresco_module_rm.bootstrap.ClearancesForSpecialUsersBootstrapComponent;
+import org.alfresco.module.org_alfresco_module_rm.patch.AbstractModulePatch;
+
+/**
+ * Patch to provide the highest clearance to the admin and system users.
+ *
+ * @author tpage
+ */
+public class RMv30ClearancesForSpecialUsers extends AbstractModulePatch
+{
+ private ClearancesForSpecialUsersBootstrapComponent bootstrapComponent;
+
+ public void setBootstrapComponent(ClearancesForSpecialUsersBootstrapComponent bootstrapComponent)
+ {
+ this.bootstrapComponent = bootstrapComponent;
+ }
+
+ /**
+ * Give the admin and system users the maximum clearance.
+ *
+ * @see org.alfresco.module.org_alfresco_module_rm.patch.AbstractModulePatch#applyInternal()
+ */
+ @Override
+ public void applyInternal()
+ {
+ bootstrapComponent.createClearancesForSpecialUsers();
+ }
+}
diff --git a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java
index 36b66555ef..aa727101cf 100644
--- a/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java
+++ b/rm-server/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/BaseRMTestCase.java
@@ -30,7 +30,8 @@ import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditSe
import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationService;
-import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService;
+import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService;
+import org.alfresco.module.org_alfresco_module_rm.classification.SecurityClearanceService;
import org.alfresco.module.org_alfresco_module_rm.dataset.DataSetService;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService;
@@ -163,6 +164,7 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
protected InplaceRecordService inplaceRecordService;
protected RelationshipService relationshipService;
protected ClassificationService classificationService;
+ protected SecurityClearanceService securityClearanceService;
protected ContentClassificationService contentClassificationService;
/** test data */
@@ -404,6 +406,7 @@ public abstract class BaseRMTestCase extends RetryingTransactionHelperTestCase
inplaceRecordService = (InplaceRecordService) applicationContext.getBean("InplaceRecordService");
relationshipService = (RelationshipService) applicationContext.getBean("RelationshipService");
classificationService = (ClassificationService) applicationContext.getBean("ClassificationService");
+ securityClearanceService = (SecurityClearanceService) applicationContext.getBean("SecurityClearanceService");
contentClassificationService = (ContentClassificationService) applicationContext.getBean("ContentClassificationService");
}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/BootstrapImporterModuleComponentUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/BootstrapImporterModuleComponentUnitTest.java
index 102304dd1e..0e5faeb982 100644
--- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/BootstrapImporterModuleComponentUnitTest.java
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/BootstrapImporterModuleComponentUnitTest.java
@@ -34,7 +34,7 @@ import org.mockito.Mock;
/**
* Bootstrap importer module component unit test
- *
+ *
* @author Roy Wetherall
* @since 2.3
*/
@@ -42,16 +42,17 @@ public class BootstrapImporterModuleComponentUnitTest extends BaseUnitTest
{
/** RM config node */
private static final NodeRef configNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "rm_config_folder");
-
+
/** mocks */
- @Mock(name="importer") private ImporterBootstrap mockedImporter;
- @Mock(name="modulePatchExecuter") private ModulePatchExecuter mockedModulePatchExecuter;
- @Mock(name="recordContributorsGroupBootstrapComponent") private RecordContributorsGroupBootstrapComponent mockedRecordContributorsGroupBootstrapComponent;
-
+ @Mock(name="importer") private ImporterBootstrap mockedImporter;
+ @Mock(name="modulePatchExecuter") private ModulePatchExecuter mockedModulePatchExecuter;
+ @Mock(name="recordContributorsGroupBootstrapComponent") private RecordContributorsGroupBootstrapComponent mockedRecordContributorsGroupBootstrapComponent;
+ @Mock(name="clearancesForSpecialUsersBootstrapComponent") private ClearancesForSpecialUsersBootstrapComponent mockedClearancesForSpecialUsersBootstrapComponent;
+
/** importer */
@InjectMocks
private BootstrapImporterModuleComponent importer;
-
+
/**
* Given that the system has already been bootstraped
* When I try and boostrap the system
@@ -62,16 +63,16 @@ public class BootstrapImporterModuleComponentUnitTest extends BaseUnitTest
{
// config node exists
doReturn(true).when(mockedNodeService).exists(configNodeRef);
-
+
// boostrap
importer.executeInternal();
-
+
// not bootstraped
verify(mockedImporter, never()).bootstrap();
verify(mockedModulePatchExecuter, never()).initSchemaVersion();
verify(mockedRecordContributorsGroupBootstrapComponent, never()).createRecordContributorsGroup();
}
-
+
/**
* Given that the system has not been bootstraped
* When I try and bootstrap the system
@@ -82,13 +83,13 @@ public class BootstrapImporterModuleComponentUnitTest extends BaseUnitTest
{
// config node does not exist
doReturn(false).when(mockedNodeService).exists(configNodeRef);
-
+
// boostrap
importer.executeInternal();
-
+
// not bootstraped
verify(mockedImporter, times(1)).bootstrap();
verify(mockedModulePatchExecuter, times(1)).initSchemaVersion();
- verify(mockedRecordContributorsGroupBootstrapComponent, times(1)).createRecordContributorsGroup();
+ verify(mockedRecordContributorsGroupBootstrapComponent, times(1)).createRecordContributorsGroup();
}
}
diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ClearancesForSpecialUsersBootstrapComponentUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ClearancesForSpecialUsersBootstrapComponentUnitTest.java
new file mode 100644
index 0000000000..b435481c50
--- /dev/null
+++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/bootstrap/ClearancesForSpecialUsersBootstrapComponentUnitTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2005-2015 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.module.org_alfresco_module_rm.bootstrap;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationLevel;
+import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationLevelManager;
+import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceBootstrap;
+import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
+import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.PersonService;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+/**
+ * Unit tests for {@link ClearancesForSpecialUsersBootstrapComponent}.
+ *
+ * @author tpage
+ */
+public class ClearancesForSpecialUsersBootstrapComponentUnitTest implements ClassifiedContentModel
+{
+ @InjectMocks ClearancesForSpecialUsersBootstrapComponent clearancesForSpecialUsersBootstrapComponent;
+ @Mock AuthenticationUtil mockAuthenticationUtil;
+ @Mock PersonService mockPersonService;
+ @Mock NodeService mockNodeService;
+ @Mock ClassificationServiceBootstrap mockClassificationServiceBootstrap;
+
+ @Before public void setUp()
+ {
+ initMocks(this);
+ }
+
+ /** Check that the system and admin users get assigned the provided clearance. */
+ @Test public void testCreateClearancesForSpecialUsers()
+ {
+ // Allow the classification level id to be found.
+ ClassificationLevel level = new ClassificationLevel("id", "displayLabelKey");
+ ClassificationLevelManager mockClassificationLevelManager = mock(ClassificationLevelManager.class);
+ when(mockClassificationLevelManager.getMostSecureLevel()).thenReturn(level);
+ when(mockClassificationServiceBootstrap.getClassificationLevelManager()).thenReturn(mockClassificationLevelManager);
+
+ // Set up the admin and system users.
+ when(mockAuthenticationUtil.getSystemUserName()).thenReturn("system");
+ NodeRef system = new NodeRef("system://node/");
+ when(mockPersonService.getPerson("system")).thenReturn(system);
+ when(mockAuthenticationUtil.getAdminUserName()).thenReturn("admin");
+ NodeRef admin = new NodeRef("admin://node/");
+ when(mockPersonService.getPerson("admin")).thenReturn(admin);
+
+ // Call the method under test.
+ clearancesForSpecialUsersBootstrapComponent.createClearancesForSpecialUsers();
+
+ verify(mockNodeService).setProperty(system, PROP_CLEARANCE_LEVEL, "id");
+ verify(mockNodeService).setProperty(admin, PROP_CLEARANCE_LEVEL, "id");
+ // Check that the classification levels were loaded.
+ verify(mockClassificationServiceBootstrap).onBootstrap(null);
+ }
+}