WidgetsCatalogMarkupController up 37/95337/1
authorDominik Mizyn <d.mizyn@samsung.com>
Tue, 10 Sep 2019 11:11:09 +0000 (13:11 +0200)
committerDominik Mizyn <d.mizyn@samsung.com>
Tue, 10 Sep 2019 11:11:16 +0000 (13:11 +0200)
WidgetsCatalogMarkupController up

Issue-ID: PORTAL-710
Change-Id: Ie8b58f17ec195f7facd94315c5f24181757c1c2a
Signed-off-by: Dominik Mizyn <d.mizyn@samsung.com>
15 files changed:
docs/tutorials/portal-BE/setting-up.rst
portal-BE/src/main/java/org/onap/portal/controller/LoginController.java
portal-BE/src/main/java/org/onap/portal/controller/UserController.java
portal-BE/src/main/java/org/onap/portal/controller/WidgetsCatalogMarkupController.java [new file with mode: 0644]
portal-BE/src/main/java/org/onap/portal/controller/WidgetsController.java
portal-BE/src/main/java/org/onap/portal/domain/db/cr/CrFilehistLog.java
portal-BE/src/main/java/org/onap/portal/domain/db/fn/FnRole.java
portal-BE/src/main/java/org/onap/portal/domain/dto/ecomp/WidgetServiceHeaders.java
portal-BE/src/main/java/org/onap/portal/domain/dto/transport/CentralV2RoleFunction.java
portal-BE/src/main/java/org/onap/portal/domain/dto/transport/ExternalAccessPerms.java
portal-BE/src/main/java/org/onap/portal/service/WidgetMService.java [new file with mode: 0644]
portal-BE/src/main/java/org/onap/portal/service/fn/FnUserService.java
portal-BE/src/main/java/org/onap/portal/service/fn/old/AppsCacheService.java
portal-BE/src/main/java/org/onap/portal/utils/EcompPortalUtils.java
portal-BE/src/main/java/org/onap/portal/utils/PortalConstants.java

index a2155c3..22d7f47 100644 (file)
@@ -26,6 +26,7 @@ Building
 ::
 
     cd portal-BE/
+    If you get this error "unable to prepare context: path ".\r" not found" please use this command dos2unix build.sh
     ./build.sh
 
 Viewing your app
index 0d6de15..3ada12f 100644 (file)
 package org.onap.portal.controller;
 
 import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.GetMapping;
 
 @Controller
 public class LoginController {
 
-       @RequestMapping(value = "login", method = RequestMethod.GET)
+       @GetMapping(value = "login")
        public String loginView() {
               return "login";
        }
index abc9185..c2dcccd 100644 (file)
@@ -50,10 +50,11 @@ import org.onap.portal.validation.DataValidator;
 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.onap.portalsdk.core.onboarding.util.CipherUtil;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
@@ -73,7 +74,7 @@ public class UserController {
               this.dataValidator = dataValidator;
        }
 
-       @RequestMapping(value = {"/portalApi/loggedinUser"}, method = RequestMethod.GET, produces = "application/json")
+       @GetMapping(value = {"/portalApi/loggedinUser"}, produces = MediaType.APPLICATION_JSON_VALUE)
        public PortalRestResponse<ProfileDetail> getLoggedinUser(Principal principal) {
               PortalRestResponse<ProfileDetail> portalRestResponse = null;
               try {
@@ -90,8 +91,7 @@ public class UserController {
               return portalRestResponse;
        }
 
-       @RequestMapping(value = {
-               "/portalApi/modifyLoggedinUser"}, method = RequestMethod.PUT, produces = "application/json")
+       @PutMapping(value = {"/portalApi/modifyLoggedinUser"}, produces = MediaType.APPLICATION_JSON_VALUE)
        public PortalRestResponse<String> modifyLoggedinUser(Principal principal,
                @RequestBody ProfileDetail profileDetail) {
               PortalRestResponse<String> portalRestResponse = null;
@@ -99,7 +99,8 @@ public class UserController {
                      String errorMsg = "";
                      if (!dataValidator.isValid(profileDetail)) {
                             errorMsg = "Required field(s) is missing";
-                            portalRestResponse = new PortalRestResponse<>(PortalRestStatusEnum.ERROR, dataValidator.getConstraintViolationsString(profileDetail), null);
+                            portalRestResponse = new PortalRestResponse<>(PortalRestStatusEnum.ERROR,
+                                    dataValidator.getConstraintViolationsString(profileDetail), null);
                             logger.error(EELFLoggerDelegate.errorLogger, "modifyLoggedinUser failed", errorMsg);
                      } else {
                             FnUser user = userService.loadUserByUsername(principal.getName());
@@ -109,7 +110,8 @@ public class UserController {
                             user.setMiddleName(profileDetail.getMiddleName());
                             user.setLoginId(profileDetail.getLoginId());
                             if (!HIDDEN_DEFAULT_PASSWORD.equals(profileDetail.getLoginPassword())) {
-                                   user.setLoginPwd(CipherUtil.encryptPKC(profileDetail.getLoginPassword(), "AGLDdG4D04BKm2IxIWEr8o==!"));
+                                   user.setLoginPwd(CipherUtil
+                                           .encryptPKC(profileDetail.getLoginPassword(), "AGLDdG4D04BKm2IxIWEr8o==!"));
                             }
                             userService.saveFnUser(principal, user);
                             // Update user info in the session
diff --git a/portal-BE/src/main/java/org/onap/portal/controller/WidgetsCatalogMarkupController.java b/portal-BE/src/main/java/org/onap/portal/controller/WidgetsCatalogMarkupController.java
new file mode 100644 (file)
index 0000000..06dd62d
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * ============LICENSE_START==========================================
+ * ONAP Portal
+ * ===================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ===================================================================
+ *
+ * Unless otherwise specified, all software contained herein is licensed
+ * under the Apache License, Version 2.0 (the "License");
+ * you may not use this software 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.
+ *
+ * Unless otherwise specified, all documentation contained herein is licensed
+ * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+ * you may not use this documentation except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *             https://creativecommons.org/licenses/by/4.0/
+ *
+ * Unless required by applicable law or agreed to in writing, documentation
+ * 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.
+ *
+ * ============LICENSE_END============================================
+ *
+ *
+ */
+
+package org.onap.portal.controller;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.onap.portal.domain.dto.ecomp.WidgetServiceHeaders;
+import org.onap.portal.logging.aop.EPAuditLog;
+import org.onap.portal.service.WidgetMService;
+import org.onap.portal.utils.EcompPortalUtils;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.util.SystemProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestClientException;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.multipart.commons.CommonsMultipartResolver;
+
+@EPAuditLog
+@RestController
+@EnableAspectJAutoProxy
+public class WidgetsCatalogMarkupController {
+
+       private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(WidgetsCatalogMarkupController.class);
+       private RestTemplate template = new RestTemplate();
+       private final String whatService = "widgets-service";
+
+       @Autowired
+       private WidgetMService widgetMService;
+
+       @Bean
+       public CommonsMultipartResolver multipartResolver() {
+              return new CommonsMultipartResolver();
+       }
+
+       static {
+              // for localhost testing only
+              javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
+
+                     public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
+                            if (hostname.equals("localhost")) {
+                                   return true;
+                            }
+                            return false;
+                     }
+              });
+       }
+
+       @GetMapping(value = "/portalApi/microservices/markup/{widgetId}")
+       public String getWidgetMarkup(HttpServletRequest request, HttpServletResponse response,
+               @PathVariable("widgetId") long widgetId) throws RestClientException, Exception {
+              return template
+                      .getForObject(
+                              EcompPortalUtils.widgetMsProtocol() + "://"
+                                      + widgetMService.getServiceLocation(whatService,
+                                      SystemProperties.getProperty("microservices.widget.local.port"))
+                                      + "/widget/microservices/markup/" + widgetId,
+                              String.class, WidgetServiceHeaders.getInstance());
+       }
+
+}
index 63309f3..6248a35 100644 (file)
@@ -49,6 +49,7 @@ import org.onap.portal.domain.db.fn.FnUser;
 import org.onap.portal.domain.dto.transport.FieldsValidator;
 import org.onap.portal.domain.dto.transport.OnboardingWidget;
 import org.onap.portal.domain.dto.transport.WidgetCatalogPersonalization;
+import org.onap.portal.logging.aop.EPAuditLog;
 import org.onap.portal.service.AdminRolesService;
 import org.onap.portal.service.PersUserWidgetService;
 import org.onap.portal.service.WidgetService;
@@ -59,14 +60,17 @@ import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
+@EPAuditLog
 @RestController
-@Configuration
 @EnableAspectJAutoProxy
 public class WidgetsController {
 
@@ -89,7 +93,7 @@ public class WidgetsController {
               this.persUserWidgetService = persUserWidgetService;
        }
 
-       @RequestMapping(value = {"/portalApi/widgets"}, method = RequestMethod.GET, produces = "application/json")
+       @GetMapping(value = {"/portalApi/widgets"}, produces = MediaType.APPLICATION_JSON_VALUE)
        public List<OnboardingWidget> getOnboardingWidgets(Principal principal, HttpServletRequest request,
                HttpServletResponse response) {
               FnUser user = fnUserService.loadUserByUsername(principal.getName());
@@ -113,8 +117,7 @@ public class WidgetsController {
               return onboardingWidgets;
        }
 
-       @RequestMapping(value = {"/portalApi/widgets/{widgetId}"}, method = {
-               RequestMethod.PUT}, produces = "application/json")
+       @PutMapping(value = {"/portalApi/widgets/{widgetId}"}, produces = MediaType.APPLICATION_JSON_VALUE)
        public FieldsValidator putOnboardingWidget(Principal principal, HttpServletRequest request,
                @PathVariable("widgetId") Long widgetId,
                @RequestBody OnboardingWidget onboardingWidget, HttpServletResponse response) {
@@ -149,7 +152,7 @@ public class WidgetsController {
               return true;
        }
 
-       @RequestMapping(value = {"/portalApi/widgets"}, method = {RequestMethod.POST}, produces = "application/json")
+       @PostMapping(value = {"/portalApi/widgets"}, produces = MediaType.APPLICATION_JSON_VALUE)
        public FieldsValidator postOnboardingWidget(Principal principal, HttpServletRequest request,
                @RequestBody OnboardingWidget onboardingWidget, HttpServletResponse response) {
               FnUser user = fnUserService.loadUserByUsername(principal.getName());
@@ -175,8 +178,7 @@ public class WidgetsController {
               return fieldsValidator;
        }
 
-       @RequestMapping(value = {"/portalApi/widgets/{widgetId}"}, method = {
-               RequestMethod.DELETE}, produces = "application/json")
+       @DeleteMapping(value = {"/portalApi/widgets/{widgetId}"}, produces = MediaType.APPLICATION_JSON_VALUE)
        public FieldsValidator deleteOnboardingWidget(Principal principal, HttpServletRequest request,
                @PathVariable("widgetId") Long widgetId, HttpServletResponse response) {
               FnUser user = fnUserService.loadUserByUsername(principal.getName());
@@ -192,8 +194,7 @@ public class WidgetsController {
               return fieldsValidator;
        }
 
-       @RequestMapping(value = {
-               "portalApi/widgetCatalogSelection"}, method = RequestMethod.PUT, produces = "application/json")
+       @PutMapping(value = {"portalApi/widgetCatalogSelection"}, produces = MediaType.APPLICATION_JSON_VALUE)
        public FieldsValidator putWidgetCatalogSelection(Principal principal, HttpServletRequest request,
                @RequestBody WidgetCatalogPersonalization persRequest, HttpServletResponse response) throws IOException {
               FieldsValidator result = new FieldsValidator();
@@ -205,7 +206,6 @@ public class WidgetsController {
                             return result;
                      }
               }
-
               try {
                      if (persRequest.getWidgetId() == null || user == null) {
                             EcompPortalUtils.setBadPermissions(user, response, "putWidgetCatalogSelection");
index 41e7a91..3dec4ee 100644 (file)
@@ -46,7 +46,6 @@ import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.Table;
 import javax.validation.constraints.Digits;
-import javax.validation.constraints.Positive;
 import javax.validation.constraints.Size;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
index 57d9079..8465ce2 100644 (file)
@@ -59,7 +59,6 @@ import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.validation.constraints.Digits;
 import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
 import javax.validation.constraints.Size;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
index 3e665fc..2be8c55 100644 (file)
@@ -41,9 +41,7 @@
 package org.onap.portal.domain.dto.ecomp;
 
 import java.nio.charset.Charset;
-import lombok.AllArgsConstructor;
 import lombok.Getter;
-import lombok.NoArgsConstructor;
 import lombok.Setter;
 import org.apache.commons.codec.binary.Base64;
 import org.onap.portal.utils.EcompPortalUtils;
index 438d393..4aa79cc 100644 (file)
@@ -50,7 +50,7 @@ import org.onap.portal.domain.dto.DomainVo;
 
 @Getter
 @Setter
-@EqualsAndHashCode()
+@EqualsAndHashCode
 @NoArgsConstructor
 @AllArgsConstructor
 public class CentralV2RoleFunction extends DomainVo implements Serializable, Comparable {
index 1358233..de176af 100644 (file)
@@ -118,12 +118,8 @@ public class ExternalAccessPerms implements Serializable, Comparable {
             return false;
         }
         if (type == null) {
-            if (other.type != null) {
-                return false;
-            }
-        } else if (!type.equals(other.type)) {
-            return false;
-        }
-        return true;
+            return other.type == null;
+        } else
+            return type.equals(other.type);
     }
 }
diff --git a/portal-BE/src/main/java/org/onap/portal/service/WidgetMService.java b/portal-BE/src/main/java/org/onap/portal/service/WidgetMService.java
new file mode 100644 (file)
index 0000000..624beed
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * ============LICENSE_START==========================================
+ * ONAP Portal
+ * ===================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ===================================================================
+ *
+ * Unless otherwise specified, all software contained herein is licensed
+ * under the Apache License, Version 2.0 (the "License");
+ * you may not use this software 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.
+ *
+ * Unless otherwise specified, all documentation contained herein is licensed
+ * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+ * you may not use this documentation except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *             https://creativecommons.org/licenses/by/4.0/
+ *
+ * Unless required by applicable law or agreed to in writing, documentation
+ * 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.
+ *
+ * ============LICENSE_END============================================
+ *
+ *
+ */
+
+package org.onap.portal.service;
+
+import org.onap.portal.utils.EcompPortalUtils;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.springframework.stereotype.Service;
+
+@Service
+public class WidgetMService {
+
+       private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(WidgetMService.class);
+
+       public String getServiceLocation(String service, String fallbackPortOnLocalHost) {
+              logger.debug(EELFLoggerDelegate.debugLogger, "Requested Service: " + service);
+              String localFallbackServiceLocation =
+                      EcompPortalUtils.localOrDockerHost() + ":" + fallbackPortOnLocalHost;
+              logger.debug(EELFLoggerDelegate.debugLogger,
+                      "returned service location: " + localFallbackServiceLocation);
+              return localFallbackServiceLocation;
+       }
+}
index cd966fb..855e827 100644 (file)
@@ -44,7 +44,6 @@ import java.security.Principal;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
-import java.util.stream.Collectors;
 import org.onap.portal.dao.fn.FnUserDao;
 import org.onap.portal.domain.db.fn.FnUser;
 import org.springframework.beans.factory.annotation.Autowired;
index 3c02f81..7703420 100644 (file)
@@ -137,12 +137,12 @@ public class AppsCacheService {
 
        public List<OnboardingApp> getAppsFullList() {
                refreshAppsMap(quickRefreshCacheConf);
-               List<FnApp> appList = new ArrayList<FnApp> (appsMap.values());
+               List<FnApp> appList = new ArrayList<>(appsMap.values());
                appList.removeIf(app -> app.getId() == 1);
                List<FnApp> appsFinalList = appList.stream()
                .filter(app -> app.getEnabled() && !app.getOpen()).collect(Collectors.toList());
                
-               List<OnboardingApp> onboardingAppsList = new ArrayList<OnboardingApp>();
+               List<OnboardingApp> onboardingAppsList = new ArrayList<>();
                for (FnApp app : appsFinalList) {
                        OnboardingApp onboardingApp = new OnboardingApp();
                        appsService.createOnboardingFromApp(app, onboardingApp);
@@ -154,9 +154,7 @@ public class AppsCacheService {
        public FnApp getApp(Long appId) {
                refreshAppsMap(quickRefreshCacheConf);
                FnApp app = appsMap.get(appId);
-               if(app != null)
-                       return app;
-               return null;            
+               return app;
        }
 
        public FnApp getAppFromUeb(String appKey) {
@@ -166,9 +164,7 @@ public class AppsCacheService {
        public FnApp getAppFromUeb(String appKey, Integer quickCacheRefresh) {
                refreshAppsMap(quickCacheRefresh == 1 ? quickRefreshCacheConf:slowRefreshCacheConf);
                FnApp app = uebAppsMap.get(appKey);
-               if(app != null)
-                       return app;
-               return null;            
+               return app;
        }
 
 }
index 9e3a5d4..ed03f4a 100644 (file)
@@ -103,7 +103,7 @@ public class EcompPortalUtils {
         * @return List of tokens split from the source
         */
        public static List<String> parsingByRegularExpression(String source, String regex) {
-               List<String> tokens = new ArrayList<String>();
+               List<String> tokens = new ArrayList<>();
                if (source != null && source.length() > 0) {
                        String[] parsed = source.split(regex);
                        for (String token : parsed) {
@@ -225,7 +225,7 @@ public class EcompPortalUtils {
                String responseCode = MDC.get(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE);
                int responseCodeInt = 0;
                try {
-                       if (responseCode != null && responseCode != "") {
+                       if (responseCode != null && !responseCode.isEmpty()) {
                                responseCodeInt = Integer.valueOf(responseCode);
                        }
                } catch (Exception e) {
@@ -530,7 +530,7 @@ public class EcompPortalUtils {
                        logger.error(EELFLoggerDelegate.errorLogger,
                                        "Please check in system.properties whether the property exists or not!");
                        return false;
-               } else if (new Boolean(rmtCentralAccess)) {
+               } else if (Boolean.valueOf(rmtCentralAccess)) {
                        logger.debug(EELFLoggerDelegate.debugLogger, "checkIfRemoteCentralAccessAllowed: {}", rmtCentralAccess);
                        result = true;
                }
index 0379bbe..521826f 100644 (file)
 package org.onap.portal.utils;
 
 public interface PortalConstants {
-       public static final Long PORTAL_APP_ID = 1L;
-       public static final Long DEFAULT_NOTIFICATION_CREATOR = 1L;
-       public static final String REST_AUX_API = "/auxapi";
-       public static final String PORTAL_AUX_API = "/portalApi";
-       public static final Long ACCOUNT_ADMIN_ROLE_ID = 999L;
-       public static final Long SYS_ADMIN_ROLE_ID = 1L;
-       public static final String ADMIN_ROLE = "Account Administrator";
-       public static final String PORTAL_ADMIN_ROLE = "System Administrator";
-       public static final Integer AUDIT_LOG_COMMENT_SIZE = 990;
+       Long PORTAL_APP_ID = 1L;
+       Long DEFAULT_NOTIFICATION_CREATOR = 1L;
+       String REST_AUX_API = "/auxapi";
+       String PORTAL_AUX_API = "/portalApi";
+       Long ACCOUNT_ADMIN_ROLE_ID = 999L;
+       Long SYS_ADMIN_ROLE_ID = 1L;
+       String ADMIN_ROLE = "Account Administrator";
+       String PORTAL_ADMIN_ROLE = "System Administrator";
+       Integer AUDIT_LOG_COMMENT_SIZE = 990;
 }