protected static List<CalendarBooking> filterCalendarBookings( List<CalendarBooking> calendarBookings, PermissionChecker permissionChecker, String actionId) throws PortalException, SystemException { calendarBookings = ListUtil.copy(calendarBookings); Iterator<CalendarBooking> itr = calendarBookings.iterator(); while (itr.hasNext()) { CalendarBooking calendarBooking = itr.next(); if (!CalendarPermission.contains( permissionChecker, calendarBooking.getCalendarId(), ACTION_VIEW_BOOKING_DETAILS)) { if (!CalendarPermission.contains( permissionChecker, calendarBooking.getCalendarId(), actionId)) { itr.remove(); } else { filterCalendarBooking(calendarBooking, permissionChecker); } } } return calendarBookings; }
protected List<Role> getGroupRoles(long groupId, String resourceName) throws PortalException { List<Role> roles = groupRolesMap.get(groupId); if (roles != null) { return roles; } Group group = GroupLocalServiceUtil.getGroup(groupId); roles = ListUtil.copy( ResourceActionsUtil.getRoles(group.getCompanyId(), group, resourceName, null)); Map<Team, Role> teamRoleMap = RoleLocalServiceUtil.getTeamRoleMap(groupId); for (Map.Entry<Team, Role> entry : teamRoleMap.entrySet()) { Team team = entry.getKey(); Role teamRole = entry.getValue(); teamRole.setName(PermissionExporter.ROLE_TEAM_PREFIX + team.getName()); teamRole.setDescription(team.getDescription()); roles.add(teamRole); } groupRolesMap.put(groupId, roles); return roles; }
public static List<WikiNode> orderNodes(List<WikiNode> nodes, String[] visibleNodeNames) { if ((visibleNodeNames == null) || (visibleNodeNames.length == 0)) { return nodes; } nodes = ListUtil.copy(nodes); List<WikiNode> orderedNodes = new ArrayList<WikiNode>(nodes.size()); for (String visibleNodeName : visibleNodeNames) { for (WikiNode node : nodes) { if (node.getName().equals(visibleNodeName)) { orderedNodes.add(node); nodes.remove(node); break; } } } orderedNodes.addAll(nodes); return orderedNodes; }
@Override public List<?> list(boolean copy, boolean unmodifiable) throws ORMException { try { List<?> list = sessionImpl.list( queryString, positionalParameterMap, namedParameterMap, strictName, firstResult, maxResults, flushModeType, lockModeType, sqlQuery, entityClass); if ((entityClass == null) && !list.isEmpty()) { list = _transformList(list); } if (unmodifiable) { list = new UnmodifiableList<Object>(list); } else if (copy) { list = ListUtil.copy(list); } return list; } catch (Exception e) { throw ExceptionTranslator.translate(e); } }
public List<KBArticle> getKBArticleAndAllDescendants( long resourcePrimKey, int status, OrderByComparator orderByComparator) throws SystemException { List<KBArticle> kbArticles = getKBArticles(new long[] {resourcePrimKey}, status, null); kbArticles = ListUtil.copy(kbArticles); Long[][] params = new Long[][] {new Long[] {resourcePrimKey}}; while ((params = KnowledgeBaseUtil.getParams(params[0])) != null) { List<KBArticle> curKBArticles = null; if (status == WorkflowConstants.STATUS_ANY) { curKBArticles = kbArticlePersistence.findByP_L(ArrayUtil.toArray(params[1]), true); } else if (status == WorkflowConstants.STATUS_APPROVED) { curKBArticles = kbArticlePersistence.findByP_M(ArrayUtil.toArray(params[1]), true); } else { curKBArticles = kbArticlePersistence.findByP_S(ArrayUtil.toArray(params[1]), status); } kbArticles.addAll(curKBArticles); long[] resourcePrimKeys = StringUtil.split(ListUtil.toString(curKBArticles, "resourcePrimKey"), 0L); params[0] = ArrayUtil.append(params[0], ArrayUtil.toArray(resourcePrimKeys)); } if (orderByComparator != null) { kbArticles = ListUtil.sort(kbArticles, orderByComparator); } return new UnmodifiableList<KBArticle>(kbArticles); }
public static List<AssetEntry> getAssetEntries( long[] groupIds, long[] classNameIds, long[] assetTagIds, long resourcePrimKey, int start, int end, String orderByColumn) throws PortalException { AssetEntryQuery assetEntryQuery = new AssetEntryQuery(); assetEntryQuery.setAnyTagIds(assetTagIds); assetEntryQuery.setClassNameIds(classNameIds); assetEntryQuery.setEnd(end + 1); assetEntryQuery.setGroupIds(groupIds); assetEntryQuery.setOrderByCol1(orderByColumn); assetEntryQuery.setStart(start); List<AssetEntry> assetEntries = ListUtil.copy(AssetEntryServiceUtil.getEntries(assetEntryQuery)); AssetEntry assetEntry = null; for (AssetEntry curAssetEntry : assetEntries) { if (curAssetEntry.getClassPK() == resourcePrimKey) { assetEntry = curAssetEntry; } } assetEntries.remove(assetEntry); return ListUtil.subList(assetEntries, 0, 10); }
protected List<Layout> addUserGroupLayouts( Group group, LayoutSet layoutSet, List<Layout> layouts, long parentLayoutId) throws Exception { layouts = ListUtil.copy(layouts); List<UserGroup> userUserGroups = UserGroupLocalServiceUtil.getUserUserGroups(group.getClassPK()); for (UserGroup userGroup : userUserGroups) { Group userGroupGroup = userGroup.getGroup(); List<Layout> userGroupLayouts = LayoutLocalServiceUtil.getLayouts( userGroupGroup.getGroupId(), layoutSet.isPrivateLayout(), parentLayoutId); for (Layout userGroupLayout : userGroupLayouts) { Layout virtualLayout = new VirtualLayout(userGroupLayout, group); layouts.add(virtualLayout); } } return layouts; }
@Override public List<String> getPortletResourceActions(Portlet portlet) { List<String> actions = ListUtil.copy(getPortletResourceActions(portlet.getPortletId())); synchronized (this) { checkPortletActions(portlet, actions); setActions(_portletResourceActions, portlet.getPortletId(), actions); } return actions; }
protected void addResources( long companyId, long groupId, long userId, Resource resource, boolean portletActions, PermissionedModel permissionedModel) throws PortalException, SystemException { List<String> actionIds = null; if (portletActions) { actionIds = ResourceActionsUtil.getPortletResourceActions(resource.getName()); } else { actionIds = ResourceActionsUtil.getModelResourceActions(resource.getName()); actionIds = ListUtil.copy(actionIds); filterOwnerActions(resource.getName(), actionIds); } Role role = roleLocalService.getRole(companyId, RoleConstants.OWNER); if (resourceBlockLocalService.isSupported(resource.getName())) { if (permissionedModel == null) { throw new IllegalArgumentException("Permissioned model is null"); } // Scope is assumed to always be individual resourceBlockLocalService.setIndividualScopePermissions( resource.getCompanyId(), groupId, resource.getName(), permissionedModel, role.getRoleId(), actionIds); } else { resourcePermissionLocalService.setOwnerResourcePermissions( resource.getCompanyId(), resource.getName(), resource.getScope(), resource.getPrimKey(), role.getRoleId(), userId, actionIds.toArray(new String[actionIds.size()])); } }
protected List<Calendar> filterCalendars(List<Calendar> calendars, String actionId) throws PrincipalException { calendars = ListUtil.copy(calendars); Iterator<Calendar> itr = calendars.iterator(); while (itr.hasNext()) { Calendar calendar = itr.next(); if (!CalendarPermission.contains(getPermissionChecker(), calendar, actionId)) { itr.remove(); } } return calendars; }
public List<Layout> getChildren(PermissionChecker permissionChecker) throws PortalException, SystemException { List<Layout> layouts = ListUtil.copy(getChildren()); Iterator<Layout> itr = layouts.iterator(); while (itr.hasNext()) { Layout layout = itr.next(); if (layout.isHidden() || !LayoutPermissionUtil.contains(permissionChecker, layout, ActionKeys.VIEW)) { itr.remove(); } } return layouts; }
protected List<AssetTag> filterTags(List<AssetTag> tags) throws PortalException { PermissionChecker permissionChecker = getPermissionChecker(); tags = ListUtil.copy(tags); Iterator<AssetTag> itr = tags.iterator(); while (itr.hasNext()) { AssetTag tag = itr.next(); if (!AssetTagPermission.contains(permissionChecker, tag, ActionKeys.VIEW)) { itr.remove(); } } return tags; }
protected List<AssetCategory> filterCategories(List<AssetCategory> categories) throws PortalException { PermissionChecker permissionChecker = getPermissionChecker(); categories = ListUtil.copy(categories); Iterator<AssetCategory> itr = categories.iterator(); while (itr.hasNext()) { AssetCategory category = itr.next(); if (!AssetCategoryPermission.contains(permissionChecker, category, ActionKeys.VIEW)) { itr.remove(); } } return categories; }
/** @deprecated As of 7.0.0, with no direct replacement */ @Deprecated protected List<AssetVocabulary> filterVocabularies(List<AssetVocabulary> vocabularies) throws PortalException { PermissionChecker permissionChecker = getPermissionChecker(); vocabularies = ListUtil.copy(vocabularies); Iterator<AssetVocabulary> itr = vocabularies.iterator(); while (itr.hasNext()) { AssetVocabulary vocabulary = itr.next(); if (!AssetVocabularyPermission.contains(permissionChecker, vocabulary, ActionKeys.VIEW)) { itr.remove(); } } return vocabularies; }
protected List<Layout> addChildUserGroupLayouts(Group group, List<Layout> layouts) throws Exception { layouts = ListUtil.copy(layouts); List<Layout> childLayouts = new ArrayList<Layout>(); for (Layout layout : layouts) { Layout childLayout = layout; Group layoutGroup = layout.getGroup(); if (layoutGroup.isUserGroup()) { childLayout = new VirtualLayout(layout, group); } childLayouts.add(childLayout); } return childLayouts; }
public static List<WikiNode> getNodes( List<WikiNode> nodes, String[] hiddenNodes, PermissionChecker permissionChecker) { nodes = ListUtil.copy(nodes); Arrays.sort(hiddenNodes); Iterator<WikiNode> itr = nodes.iterator(); while (itr.hasNext()) { WikiNode node = itr.next(); if (!(Arrays.binarySearch(hiddenNodes, node.getName()) < 0) || !WikiNodePermission.contains(permissionChecker, node, ActionKeys.VIEW)) { itr.remove(); } } return nodes; }
@Override public void validate( long groupId, String className, long classTypePK, long[] categoryIds, String[] entryNames) throws PortalException { if (className.equals(DLFileEntryConstants.getClassName())) { DLFileEntry dlFileEntry = _dlFileEntryLocalService.fetchDLFileEntry(classTypePK); if ((dlFileEntry == null) || (dlFileEntry.getRepositoryId() != groupId)) { return; } } List<AssetVocabulary> assetVocabularies = _assetVocabularyLocalService.getGroupVocabularies(groupId, false); Group group = _groupLocalService.getGroup(groupId); if (!group.isCompany()) { Group companyGroup = _groupLocalService.fetchCompanyGroup(group.getCompanyId()); if (companyGroup != null) { assetVocabularies = ListUtil.copy(assetVocabularies); assetVocabularies.addAll( _assetVocabularyLocalService.getGroupVocabularies(companyGroup.getGroupId())); } } long classNameId = _classNameLocalService.getClassNameId(className); if (isCategorizable(classNameId)) { for (AssetVocabulary assetVocabulary : assetVocabularies) { validate(classNameId, classTypePK, categoryIds, assetVocabulary); } } }
@Indexable(type = IndexableType.REINDEX) @Override public AssetCategory updateCategory( long userId, long categoryId, long parentCategoryId, Map<Locale, String> titleMap, Map<Locale, String> descriptionMap, long vocabularyId, String[] categoryProperties, ServiceContext serviceContext) throws PortalException { // Category String name = titleMap.get(LocaleUtil.getSiteDefault()); name = ModelHintsUtil.trimString(AssetCategory.class.getName(), "name", name); if (categoryProperties == null) { categoryProperties = new String[0]; } validate(categoryId, parentCategoryId, name, vocabularyId); if (parentCategoryId > 0) { assetCategoryPersistence.findByPrimaryKey(parentCategoryId); } AssetCategory category = assetCategoryPersistence.findByPrimaryKey(categoryId); String oldName = category.getName(); if (vocabularyId != category.getVocabularyId()) { assetVocabularyPersistence.findByPrimaryKey(vocabularyId); parentCategoryId = AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID; category.setVocabularyId(vocabularyId); updateChildrenVocabularyId(category, vocabularyId); } category.setParentCategoryId(parentCategoryId); category.setName(name); category.setTitleMap(titleMap); category.setDescriptionMap(descriptionMap); assetCategoryPersistence.update(category); // Properties List<AssetCategoryProperty> oldCategoryProperties = assetCategoryPropertyPersistence.findByCategoryId(categoryId); oldCategoryProperties = ListUtil.copy(oldCategoryProperties); for (int i = 0; i < categoryProperties.length; i++) { String[] categoryProperty = StringUtil.split( categoryProperties[i], AssetCategoryConstants.PROPERTY_KEY_VALUE_SEPARATOR); if (categoryProperty.length <= 1) { categoryProperty = StringUtil.split(categoryProperties[i], CharPool.COLON); } String key = StringPool.BLANK; if (categoryProperty.length > 0) { key = GetterUtil.getString(categoryProperty[0]); } String value = StringPool.BLANK; if (categoryProperty.length > 1) { value = GetterUtil.getString(categoryProperty[1]); } if (Validator.isNotNull(key)) { boolean addCategoryProperty = true; AssetCategoryProperty oldCategoryProperty = null; Iterator<AssetCategoryProperty> iterator = oldCategoryProperties.iterator(); while (iterator.hasNext()) { oldCategoryProperty = iterator.next(); if ((categoryId == oldCategoryProperty.getCategoryId()) && key.equals(oldCategoryProperty.getKey())) { addCategoryProperty = false; if (!value.equals(oldCategoryProperty.getValue())) { assetCategoryPropertyLocalService.updateCategoryProperty( userId, oldCategoryProperty.getCategoryPropertyId(), key, value); } iterator.remove(); break; } } if (addCategoryProperty) { assetCategoryPropertyLocalService.addCategoryProperty(userId, categoryId, key, value); } } } for (AssetCategoryProperty categoryProperty : oldCategoryProperties) { assetCategoryPropertyLocalService.deleteAssetCategoryProperty(categoryProperty); } // Indexer if (!oldName.equals(name)) { List<AssetEntry> entries = assetCategoryPersistence.getAssetEntries(category.getCategoryId()); assetEntryLocalService.reindex(entries); } return category; }
protected void addModelResources( long companyId, long groupId, long userId, Resource resource, String[] groupPermissions, String[] guestPermissions, PermissionedModel permissionedModel) throws PortalException, SystemException { // Owner permissions Role ownerRole = roleLocalService.getRole(companyId, RoleConstants.OWNER); List<String> ownerActionIds = ResourceActionsUtil.getModelResourceActions(resource.getName()); ownerActionIds = ListUtil.copy(ownerActionIds); filterOwnerActions(resource.getName(), ownerActionIds); String[] ownerPermissions = ownerActionIds.toArray(new String[ownerActionIds.size()]); // Group permissions Role defaultGroupRole = null; if (groupId > 0) { defaultGroupRole = roleLocalService.getDefaultGroupRole(groupId); if (groupPermissions == null) { groupPermissions = new String[0]; } } // Guest permissions Role guestRole = roleLocalService.getRole(companyId, RoleConstants.GUEST); if (guestPermissions == null) { guestPermissions = new String[0]; } if (resourceBlockLocalService.isSupported(resource.getName())) { if (permissionedModel == null) { throw new IllegalArgumentException("Permissioned model is null"); } // Scope is assumed to always be individual resourceBlockLocalService.setIndividualScopePermissions( resource.getCompanyId(), groupId, resource.getName(), permissionedModel, ownerRole.getRoleId(), ownerActionIds); if (groupId > 0) { resourceBlockLocalService.setIndividualScopePermissions( resource.getCompanyId(), groupId, resource.getName(), permissionedModel, defaultGroupRole.getRoleId(), Arrays.asList(groupPermissions)); } resourceBlockLocalService.setIndividualScopePermissions( resource.getCompanyId(), groupId, resource.getName(), permissionedModel, guestRole.getRoleId(), Arrays.asList(guestPermissions)); } else { resourcePermissionLocalService.setOwnerResourcePermissions( resource.getCompanyId(), resource.getName(), resource.getScope(), resource.getPrimKey(), ownerRole.getRoleId(), userId, ownerPermissions); if (groupId > 0) { resourcePermissionLocalService.setResourcePermissions( resource.getCompanyId(), resource.getName(), resource.getScope(), resource.getPrimKey(), defaultGroupRole.getRoleId(), groupPermissions); } resourcePermissionLocalService.setResourcePermissions( resource.getCompanyId(), resource.getName(), resource.getScope(), resource.getPrimKey(), guestRole.getRoleId(), guestPermissions); } }
protected List<Portlet> getEmbeddedPortlets( List<Portlet> columnPortlets, List<Portlet> staticPortlets) { if (_embeddedPortlets != null) { return _embeddedPortlets; } List<Portlet> portlets = new ArrayList<>(); Layout layout = getLayout(); List<PortletPreferences> portletPreferences = PortletPreferencesLocalServiceUtil.getPortletPreferences( PortletKeys.PREFS_OWNER_ID_DEFAULT, PortletKeys.PREFS_OWNER_TYPE_LAYOUT, layout.getPlid()); if (isCustomizable() && hasUserPreferences()) { portletPreferences = ListUtil.copy(portletPreferences); portletPreferences.addAll( PortletPreferencesLocalServiceUtil.getPortletPreferences( _portalPreferences.getUserId(), PortletKeys.PREFS_OWNER_TYPE_USER, layout.getPlid())); } for (PortletPreferences portletPreference : portletPreferences) { String portletId = portletPreference.getPortletId(); Portlet portlet = PortletLocalServiceUtil.getPortletById(getCompanyId(), portletId); if (Validator.isNull(portletId) || columnPortlets.contains(portlet) || staticPortlets.contains(portlet) || !portlet.isReady() || portlet.isUndeployedPortlet() || !portlet.isActive()) { continue; } if (portlet != null) { Portlet embeddedPortlet = portlet; if (portlet.isInstanceable()) { // Instanceable portlets do not need to be cloned because // they are already cloned. See the method getPortletById in // the class PortletLocalServiceImpl and how it references // the method getClonedInstance in the class PortletImpl. } else { embeddedPortlet = (Portlet) embeddedPortlet.clone(); } // We set embedded portlets as static on order to avoid adding // the close and/or move icons. embeddedPortlet.setStatic(true); portlets.add(embeddedPortlet); } } _embeddedPortlets = portlets; return _embeddedPortlets; }
protected void doAddPermissionFields_6( long companyId, long groupId, String className, String classPK, Document doc) throws Exception { Group group = null; if (groupId > 0) { group = GroupLocalServiceUtil.getGroup(groupId); } List<Role> roles = ListUtil.copy(ResourceActionsUtil.getRoles(companyId, group, className, null)); if (groupId > 0) { List<Role> teamRoles = RoleLocalServiceUtil.getTeamRoles(groupId); roles.addAll(teamRoles); } long[] roleIdsArray = new long[roles.size()]; for (int i = 0; i < roleIdsArray.length; i++) { Role role = roles.get(i); roleIdsArray[i] = role.getRoleId(); } boolean[] hasResourcePermissions = null; if (ResourceBlockLocalServiceUtil.isSupported(className)) { ResourceBlockIdsBag resourceBlockIdsBag = ResourceBlockLocalServiceUtil.getResourceBlockIdsBag( companyId, groupId, className, roleIdsArray); long actionId = ResourceBlockLocalServiceUtil.getActionId(className, ActionKeys.VIEW); List<Long> resourceBlockIds = resourceBlockIdsBag.getResourceBlockIds(actionId); hasResourcePermissions = new boolean[roleIdsArray.length]; for (long resourceBlockId : resourceBlockIds) { for (int i = 0; i < roleIdsArray.length; i++) { int count = ResourceBlockPermissionLocalServiceUtil.getResourceBlockPermissionsCount( resourceBlockId, roleIdsArray[i]); hasResourcePermissions[i] = (count > 0); } } } else { hasResourcePermissions = ResourcePermissionLocalServiceUtil.hasResourcePermissions( companyId, className, ResourceConstants.SCOPE_INDIVIDUAL, classPK, roleIdsArray, ActionKeys.VIEW); } List<Long> roleIds = new ArrayList<Long>(); List<String> groupRoleIds = new ArrayList<String>(); for (int i = 0; i < hasResourcePermissions.length; i++) { if (!hasResourcePermissions[i]) { continue; } Role role = roles.get(i); if ((role.getType() == RoleConstants.TYPE_ORGANIZATION) || (role.getType() == RoleConstants.TYPE_SITE)) { groupRoleIds.add(groupId + StringPool.DASH + role.getRoleId()); } else { roleIds.add(role.getRoleId()); } } doc.addKeyword(Field.ROLE_ID, roleIds.toArray(new Long[roleIds.size()])); doc.addKeyword(Field.GROUP_ROLE_ID, groupRoleIds.toArray(new String[groupRoleIds.size()])); }
public void updateStatuses(User user, List<Object> dlFileEntriesAndDLFolders, int status) throws PortalException, SystemException { for (Object object : dlFileEntriesAndDLFolders) { if (object instanceof DLFileEntry) { DLFileEntry dlFileEntry = (DLFileEntry) object; List<DLFileVersion> dlFileVersions = dlFileVersionLocalService.getFileVersions( dlFileEntry.getFileEntryId(), WorkflowConstants.STATUS_ANY); dlFileVersions = ListUtil.copy(dlFileVersions); Collections.sort(dlFileVersions, new FileVersionVersionComparator()); DLFileVersion latestDlFileVersion = dlFileVersions.get(0); if ((status == WorkflowConstants.STATUS_APPROVED) && (latestDlFileVersion.getStatus() == WorkflowConstants.STATUS_IN_TRASH)) { continue; } // Asset if (status == WorkflowConstants.STATUS_APPROVED) { if (latestDlFileVersion.isApproved()) { assetEntryLocalService.updateVisible( DLFileEntryConstants.getClassName(), dlFileEntry.getFileEntryId(), true); } } else { assetEntryLocalService.moveEntryToTrash( DLFileEntryConstants.getClassName(), dlFileEntry.getFileEntryId()); } // Social if (status == WorkflowConstants.STATUS_APPROVED) { socialActivityCounterLocalService.enableActivityCounters( DLFileEntryConstants.getClassName(), dlFileEntry.getFileEntryId()); socialActivityLocalService.addActivity( user.getUserId(), dlFileEntry.getGroupId(), DLFileEntryConstants.getClassName(), dlFileEntry.getFileEntryId(), SocialActivityConstants.TYPE_RESTORE_FROM_TRASH, StringPool.BLANK, 0); } else if (latestDlFileVersion.getStatus() == WorkflowConstants.STATUS_APPROVED) { socialActivityLocalService.addActivity( user.getUserId(), dlFileEntry.getGroupId(), DLFileEntryConstants.getClassName(), dlFileEntry.getFileEntryId(), SocialActivityConstants.TYPE_MOVE_TO_TRASH, StringPool.BLANK, 0); } // Index Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(DLFileEntry.class); if (status == WorkflowConstants.STATUS_APPROVED) { indexer.reindex(dlFileEntry); } else { indexer.delete(dlFileEntry); } // Workflow if (status != WorkflowConstants.STATUS_APPROVED) { for (DLFileVersion dlFileVersion : dlFileVersions) { if (!dlFileVersion.isPending()) { continue; } dlFileVersion.setStatus(WorkflowConstants.STATUS_DRAFT); dlFileVersionPersistence.update(dlFileVersion, false); workflowInstanceLinkLocalService.deleteWorkflowInstanceLink( dlFileVersion.getCompanyId(), dlFileVersion.getGroupId(), DLFileEntryConstants.getClassName(), dlFileVersion.getFileVersionId()); } } } else if (object instanceof DLFolder) { DLFolder dlFolder = (DLFolder) object; if (dlFolder.isInTrash()) { continue; } QueryDefinition queryDefinition = new QueryDefinition(WorkflowConstants.STATUS_ANY); List<Object> foldersAndFileEntriesAndFileShortcuts = dlFolderLocalService.getFoldersAndFileEntriesAndFileShortcuts( dlFolder.getGroupId(), dlFolder.getFolderId(), null, false, queryDefinition); updateStatuses(user, foldersAndFileEntriesAndFileShortcuts, status); } } }