Merged V2.0 to HEAD

5297: PostgreSQL upgrade support
   5347: (From 1.4) EHCache configuration fixes and sample
   5380, 5381: AWC-1143
   5398: AWC-966


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5479 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2007-04-11 19:05:40 +00:00
parent 296c55c548
commit 529c4840e9
11 changed files with 636 additions and 48 deletions

View File

@@ -4,6 +4,7 @@
<!-- references to XML configurations -->
<beans >
<import resource="classpath:alfresco/cache-context.xml" />
<import resource="classpath:alfresco/core-services-context.xml" />
<import resource="classpath:alfresco/public-services-context.xml" />
<import resource="classpath:alfresco/model-specific-services-context.xml" />

View File

@@ -46,6 +46,7 @@
<list>
<ref bean="patch.schemaUpdateScript-V1.4-1" />
<ref bean="patch.schemaUpdateScript-V1.4-2" />
<ref bean="patch.db-V1.4-PostgresFKIndexes" />
</list>
</property>
<property name="postUpdateScriptPatches">

View File

@@ -11,6 +11,7 @@
<!-- ==================================================== -->
<!-- EH Cache Manager to produce in-transaction EH Caches -->
<!-- Do not override or cluster -->
<!-- ==================================================== -->
<bean name="transactionalEHCacheManager" class="org.alfresco.repo.cache.EhCacheManagerFactoryBean" >
@@ -39,16 +40,7 @@
<ref bean="internalEHCacheManager" />
</property>
<property name="cacheName">
<value>org.alfresco.userToAuthorityCache</value>
</property>
<property name="maxElementsInMemory">
<value>10000</value> <!-- approx 2MB memory required -->
</property>
<property name="eternal">
<value>true</value>
</property>
<property name="overflowToDisk">
<value>false</value>
<value>org.alfresco.cache.userToAuthorityCache</value>
</property>
</bean>
</property>
@@ -84,16 +76,7 @@
<ref bean="internalEHCacheManager" />
</property>
<property name="cacheName">
<value>org.alfresco.permissionsAccessCache</value>
</property>
<property name="maxElementsInMemory">
<value>50000</value> <!-- approx 20MB memory required -->
</property>
<property name="eternal">
<value>true</value>
</property>
<property name="overflowToDisk">
<value>false</value>
<value>org.alfresco.cache.permissionsAccessCache</value>
</property>
</bean>
</property>
@@ -130,16 +113,7 @@
<ref bean="internalEHCacheManager" />
</property>
<property name="cacheName">
<value>org.alfresco.nodeOwnerCache</value>
</property>
<property name="maxElementsInMemory">
<value>20000</value> <!-- approx 20MB memory required -->
</property>
<property name="eternal">
<value>true</value>
</property>
<property name="overflowToDisk">
<value>false</value>
<value>org.alfresco.cache.nodeOwnerCache</value>
</property>
</bean>
</property>
@@ -175,16 +149,7 @@
<ref bean="internalEHCacheManager" />
</property>
<property name="cacheName">
<value>org.alfresco.ticketsCache</value>
</property>
<property name="maxElementsInMemory">
<value>1000</value>
</property>
<property name="eternal">
<value>true</value>
</property>
<property name="overflowToDisk">
<value>false</value>
<value>org.alfresco.cache.ticketsCache</value>
</property>
</bean>
</property>

View File

@@ -0,0 +1,15 @@
--
-- Foreign Key Indexes for PostgreSQL databases. (Generic Schema 1.4)
--
--
-- Record script finish
--
delete from alf_applied_patch where id = 'patch.db-V1.4-PostgresFKIndexes';
insert into alf_applied_patch
(id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report)
values
(
'patch.db-V1.4-PostgresFKIndexes', 'Manually execute script AlfrescoSchemaUpdate-1.4-PostgresFKIndexes.sql',
21, 24, -1, 25, null, 'UNKOWN', 1, 1, 'Script completed'
);

View File

@@ -0,0 +1,42 @@
--
-- Foreign Key Indexes for PostgreSQL databases. (PostgreSQL Schema 1.4)
--
CREATE INDEX FKFFF41F9960601995 ON alf_access_control_entry (permission_id);
CREATE INDEX FKFFF41F99B25A50BF ON alf_access_control_entry (authority_id);
CREATE INDEX FKFFF41F99B9553F6C ON alf_access_control_entry (acl_id);
CREATE INDEX FK8A749A657B7FDE43 ON alf_auth_ext_keys (id);
CREATE INDEX FKFFC5468E74173FF4 ON alf_child_assoc (child_node_id);
CREATE INDEX FKFFC5468E8E50E582 ON alf_child_assoc (parent_node_id);
CREATE INDEX FK60EFB626B9553F6C ON alf_node (acl_id);
CREATE INDEX FK60EFB626D24ADD25 ON alf_node (protocol, identifier);
CREATE INDEX FK7D4CF8EC7F2C8017 ON alf_node_properties (node_id);
CREATE INDEX FKD654E027F2C8017 ON alf_node_aspects (node_id);
CREATE INDEX FKE1A550BCB69C43F3 ON alf_node_assoc (source_node_id);
CREATE INDEX FKE1A550BCA8FC7769 ON alf_node_assoc (target_node_id);
CREATE INDEX FK71C2002B7F2C8017 ON alf_node_status (node_id);
CREATE INDEX FKBD4FF53D22DBA5BA ON alf_store (root_node_id);
--
-- Transaction tables
--
CREATE INDEX FK71C2002B9E57C13D ON alf_node_status (transaction_id);
CREATE INDEX FKB8761A3A9AE340B7 ON alf_transaction (server_id);
--
-- New audit tables
--
CREATE INDEX FKEAD1817484342E39 ON alf_audit_fact (audit_date_id);
CREATE INDEX FKEAD18174A0F9B8D9 ON alf_audit_fact (audit_source_id);
CREATE INDEX FKEAD18174F524CFD7 ON alf_audit_fact (audit_conf_id);
--
-- Record script finish
--
delete from alf_applied_patch where id = 'patch.db-V1.4-PostgresFKIndexes';
insert into alf_applied_patch
(id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report)
values
(
'patch.db-V1.4-PostgresFKIndexes', 'Manually execute script AlfrescoSchemaUpdate-1.4-PostgresFKIndexes.sql',
21, 24, -1, 25, null, 'UNKOWN', TRUE, TRUE, 'Script completed'
);

View File

@@ -162,24 +162,25 @@
overflowToDisk="false"
/>
<!-- Audit caches -->
<cache
<cache
name="org.alfresco.repo.audit.hibernate.AuditConfigImpl"
maxElementsInMemory="2"
eternal="true"
overflowToDisk="false"
/>
<cache
<cache
name="org.alfresco.repo.audit.hibernate.AuditDateImpl"
maxElementsInMemory="2"
eternal="true"
overflowToDisk="false"
/>
<cache
<cache
name="org.alfresco.repo.audit.hibernate.AuditSourceImpl"
maxElementsInMemory="2000"
eternal="true"
overflowToDisk="false"
/>
<!-- AVM caches -->
<cache
name="org.alfresco.repo.avm.AVMNodeImpl"
@@ -235,4 +236,31 @@
eternal="true"
overflowToDisk="false"
/>
<!-- Internally used caches -->
<cache
name="org.alfresco.cache.userToAuthorityCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="false"
/>
<cache
name="org.alfresco.cache.permissionsAccessCache"
maxElementsInMemory="50000"
eternal="true"
overflowToDisk="false"
/>
<cache
name="org.alfresco.cache.nodeOwnerCache"
maxElementsInMemory="20000"
eternal="true"
overflowToDisk="false"
/>
<cache
name="org.alfresco.cache.ticketsCache"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="false"
/>
</ehcache>

View File

@@ -1,5 +1,6 @@
<!--
This configures the cache properties for Alfresco's in-transaction caches.
Do not cluster this.
-->
<ehcache>
<diskStore

View File

@@ -0,0 +1,507 @@
<ehcache>
<diskStore
path="java.io.tmpdir"/>
<!-- ================================================================= -->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446"/>
<!--
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40000/sampleCache1|//server2:40000/sampleCache1|
//server1:40000/sampleCache2|//server2:40000/sampleCache2"/>
-->
<!-- ================================================================= -->
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
<!--
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="port=40001, socketTimeoutMillis=2000"/>
-->
<!-- ================================================================= -->
<defaultCache
maxElementsInMemory="5000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</defaultCache>
<cache
name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50"
eternal="true"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="2000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.NodeImpl"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.QNameEntityImpl"
maxElementsInMemory="100"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.NodeStatusImpl"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.NodeImpl.aspects"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.NodeImpl.properties"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.NodeImpl.parentAssocs"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.ChildAssocImpl"
maxElementsInMemory="200000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.NodeImpl.sourceNodeAssocs"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.NodeImpl.targetNodeAssocs"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.NodeAssocImpl"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.StoreImpl"
maxElementsInMemory="100"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.VersionCountImpl"
maxElementsInMemory="100"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.AppliedPatchImpl"
maxElementsInMemory="100"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="60"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.DbAccessControlListImpl"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.DbAccessControlListImpl.entries"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl"
maxElementsInMemory="5000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.DbPermissionImpl"
maxElementsInMemory="500"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.DbAuthorityImpl"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.repo.domain.hibernate.DbAuthorityImpl.externalKeys"
maxElementsInMemory="5000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<!-- Non-Hibernate -->
<cache
name="org.alfresco.cache.userToAuthorityCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.cache.permissionsAccessCache"
maxElementsInMemory="50000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.cache.nodeOwnerCache"
maxElementsInMemory="20000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
<cache
name="org.alfresco.cache.ticketsCache"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicatePuts = false,
replicateUpdates = true,
replicateRemovals = true,
replicateUpdatesViaCopy = false,
replicateAsynchronously = false"/>
</cache>
</ehcache>

View File

@@ -527,6 +527,22 @@
<ref bean="VersionService" />
</property>
</bean>
<bean id="patch.db-V1.4-PostgresFKIndexes" class="org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch" parent="basePatch">
<property name="id"><value>patch.db-V1.4-PostgresFKIndexes</value></property>
<property name="description"><value>patch.schemaUpgradeScript.description</value></property>
<property name="fixesFromSchema"><value>21</value></property>
<property name="fixesToSchema"><value>24</value></property>
<property name="targetSchema"><value>25</value></property>
<property name="scriptUrl">
<value>classpath:alfresco/dbscripts/upgrade/1.4/${db.script.dialect}/AlfrescoSchemaUpdate-1.4-PostgresFKIndexes.sql</value>
</property>
<!-- dependent on upgrade script 1.4-2 having being run -->
<property name="dependsOn" >
<list>
<ref bean="patch.schemaUpdateScript-V1.4-2" />
</list>
</property>
</bean>
<bean id="patch.multilingualBootstrap" class="org.alfresco.repo.admin.patch.impl.GenericBootstrapPatch" parent="basePatch" >
<property name="id"><value>patch.multilingualBootstrap</value></property>
<property name="description"><value>patch.multilingualBootstrap.description</value></property>

View File

@@ -14,10 +14,6 @@
<beans>
<!-- Because of the way hibernate works, we need to cache when permissions are not -->
<!-- set. -->
<import resource="classpath:alfresco/cache-context.xml" />
<!-- ======================= -->
<!-- Support for permissions -->
<!-- ========================-->

View File

@@ -34,6 +34,7 @@ import java.util.Set;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ParameterDefinitionImpl;
import org.alfresco.repo.template.DateCompareMethod;
@@ -225,6 +226,11 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
public void prepare(MimeMessage mimeMessage) throws MessagingException
{
if (logger.isDebugEnabled())
{
logger.debug(ruleAction.getParameterValues());
}
MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
// set header encoding if one has been supplied
@@ -332,7 +338,17 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
catch (Throwable e)
{
// don't stop the action but let admins know email is not getting sent
logger.error("Failed to send email to " + (String)ruleAction.getParameterValue(PARAM_TO), e);
String to = (String)ruleAction.getParameterValue(PARAM_TO);
if (to == null)
{
Object obj = ruleAction.getParameterValue(PARAM_TO_MANY);
if (obj != null)
{
to = obj.toString();
}
}
logger.error("Failed to send email to " + to, e);
}
}