This project has retired. For details please refer to its Attic page.
org.apache.river.mercury (Apache River v3.0.0 API Documentation)
Skip navigation links

Package org.apache.river.mercury

Provides implementations of the EventMailbox service.

See: Description

Package org.apache.river.mercury Description

Provides implementations of the EventMailbox service. Three implementations are available for use with the org.apache.river.start package:

The JAR file mercury.jar, included in the lib subdirectory of the Apache River release installation, contains the classes for the three Mercury service implementations. The mercury-dl.jar and jsk-dl.jar files in the lib-dl subdirectory contain the classes needed in the codebase for its downloaded proxies. None of the JAR files include classes from jsk-platform.jar, which are included by the service starter's start.jar JAR file, and need to be included in the codebase of clients.

The object returned by the Administrable.getAdmin method on a Mercury service proxy implements JoinAdmin and DestroyAdmin.

This document provides the following information about Mercury:

Configuring Mercury

The Mercury service implementation obtains its configuration by calling ConfigurationProvider.getInstance with the specified configOptions and the class loader for the implementation class.

The implementation supports the following configuration entries, with component org.apache.river.mercury:

activationIdPreparer
  Type: ProxyPreparer
  Default: new BasicProxyPreparer()
  Description: The proxy preparer for the service's activation ID. The value should not be null. This entry is obtained at service start and restart. This entry is only used by the activatable implementation.

Clients call the activate method on instances of ActivationID when they need to reactivate the service.

activationSystemPreparer
  Type: ProxyPreparer
  Default: new BasicProxyPreparer()
  Description: The proxy preparer for the proxy for the activation system. The value should not be null. This entry is obtained at service start and restart. This entry is only used by the activatable implementation.

The service calls the unregisterObject method on the ActivationSystem when the service is destroyed.

discoveryManager
  Type: DiscoveryManagement
  Default:
new LookupDiscoveryManager(
    groups,   // current group set
    locators, // current locator set
    null,     // listener
    this)     // config
  Description: Supplies an object used to discover the lookup services with which this service should register. The value should not be null. The object returned must also implement DiscoveryGroupManagement and DiscoveryLocatorManagement, and should be configured initially to discover no groups or specific lookup services. This entry is obtained at service start and restart.
initialLookupAttributes
  Type: Entry[]
  Default: new Entry[0]
  Description: Entries to include in the set of attributes the service supplies when registering with lookup services, in addition to ServiceInfo and BasicServiceType instances provided by the service. An empty array or null specifies that only the service-provided attributes should be added. The array must not contain null elements. This entry is obtained and used when the service is first started. Following initial startup, the set of attributes is controlled though the service's JoinAdmin administrable interface.
initialLookupGroups
  Type: String[]
  Default: new String[] { "" } /* public group */
  Description: The names of the lookup groups that the service should discover and join. An empty array specifies that no groups should be joined. A null value specifies that all groups should be joined. Otherwise, the value specifies the names of the groups to join. The array must not contain null elements. This entry is obtained and used when the service is first started. Following initial startup, the set of lookup groups is controlled through the service's JoinAdmin administrable interface.
initialLookupLocators
  Type: LookupLocator[]
  Default: new LookupLocator[0]
  Description: The locations of specific lookup services that the service should discover and join. An empty array or null specifies that no specific lookup services should be joined. The array must not contain null elements. This entry is obtained and used when the service is first started. Following initial startup, the set of specific lookup services is controlled through the service's JoinAdmin administrable interface.

The LookupLocator instances specified in this entry will not be prepared by the proxy preparer specified in the locatorPreparer entry, and will only be prepared by the preparer in the recoveredLocatorPreparer entry when they are being recovered.

leasePeriodPolicy
  Type: LeasePeriodPolicy
  Default:
new FixedLeasePeriodPolicy(
    3 * 60 * 60 * 1000L,  // max = 3 hours
    60 * 60 * 1000L)      // default = 1 hour
  Description: The policy for calculating lease grants and renewals. The value should not be null. The default grants leases with a maximum duration of 3 hours and a default duration of 1 hour. This entry is obtained at service start and restart.
listenerPreparer
  Type: ProxyPreparer
  Default: new BasicProxyPreparer()
  Description: Preparer for RemoteEventListener proxies that have registered with this service via the enableDelivery method. This preparer is used to prepare proxies only when they initially join with this service. The value should not be null. The preparer must return a listener which is equal to the original listener as determined by Object.equals. This entry is obtained at service start and restart.

This preparer needs to perform all operations needed to use a newly received listener, typically including verifying trust in the participant proxy, granting permissions, and setting constraints. The prepared participant will be retained by the service in its persistent store.

The service (potentially) calls the notify method on these proxies.

locatorToJoinPreparer
  Type: ProxyPreparer
  Default: new BasicProxyPreparer()
  Description: Prepares LookupLocator instances passed to JoinAdmin methods. The value should not be null. When registering with lookup services, this service may call or use the constraints assigned to the getRegistrar methods of LookupLocator instances returned from this preparer. This entry is obtained at service start and restart.

This preparer needs to perform all operations needed to use a newly received lookup locator, typically including verifying trust in the lookup locator and setting constraints. The prepared lookup locator will be retained by the service in its persistent store.

The LookupLocator instances obtained from the initialLookupLocators configuration entry will not be prepared by this preparer.

loginContext
  Type: LoginContext
  Default: null
  Description: If not null, specifies the JAAS login context to use for performing a JAAS login and supplying the Subject to use when running the service. If null, no JAAS login is performed. This entry is obtained at service start and restart.
logToSnapshotThreshold
  Type: int
  Default: 50
  Description: The threshold used to determine whether or not to take a snapshot of the server's state. The value should not be negative. The service will delay making new snapshots until the number of log updates is greater than this value. This entry is obtained at service start and restart. This entry is only used by persistent implementations.
maxUnexportDelay
  Type: long
  Default: 120000 (2 minutes)
  Description: How long to retry “nice” unexport attempts before forcing the unexport. Part of destroying a Mercury server includes calling Exporter.unexport(boolean force) on the Exporter used to export the server (see serverExporter). The initial unexport call passes false for the value of the force parameter. This is done in order to allow the destroy call to return cleanly to the client. If the initial unexport call fails, Mercury will retry calling unexport(false) for up to maxUnexportDelay milliseconds before giving up and calling unexport(true). maxUnexportDelay must be a non-negative long value. If maxUnexportDelay is zero then the very first call to unexport passes true for the value of the force parameter, no nice unexport attempt is made. Obtained at service start and restart. Note, the delay between attempted unexport calls is controlled by the unexportRetryDelay configuration entry.
notificationsExecutorService
  Type: ExecutorService
  Default: new ThreadPoolExecutor( 10, 10, /* Ignored */ 15, TimeUnit.SECONDS, new LinkedBlockingQueue(), /* Unbounded Queue */ new NamedThreadFactory("EventTypeGenerator", false) )
  Description: The pool of threads used to make event delivery attempts. The shutdown method of this object will be called when the service is destroyed. This entry is obtained at service start and restart.
persistenceDirectory
  Type: String
  Default: Required for persistent implementations: no default
  Description: The directory where the service's persistent state is recorded. The value should not be null. This entry is obtained at service start and restart. This entry is required for persistent implementations and is otherwise not used.
recoveredListenerPreparer
  Type: ProxyPreparer
  Default: new BasicProxyPreparer()
  Description: Preparer for recovered RemoteEventListener proxies that have been previously registered and prepared with this service (via the enableDelivery method).

This preparer needs to perform only those operations whose results are not retained in the participant itself, but need to be performed in the environment in which the participant is unmarshalled, typically just granting permissions.

The service (potentially) calls the notify method on these proxies.

recoveredLocatorToJoinPreparer
  Type: ProxyPreparer
  Default: new BasicProxyPreparer()
  Description: Prepares LookupLocator instances for use when they are recovered from persistent storage. The value should not be null. When registering with lookup services, this service may call or use the constraints assigned to the getRegistrar methods of LookupLocator instances returned from this preparer. This entry is obtained at service start and restart. This entry is only used by persistent implementations.

This preparer needs to perform only those operations whose results are not retained in the lookup locator itself, but need to be performed in the environment in which the lookup locator is unmarshalled. Typically no operations are needed.

The LookupLocator instances obtained from the initialLookupLocators configuration entry will not be prepared by this preparer until they are being recovered.

serverExporter
  Type: Exporter
  Default:
// Activatable implementation
new ActivationExporter(
    activationID,
    new BasicJeriExporter(
        TcpServerEndpoint.getInstance(0),
        new BasicILFactory(), false, true))
// Non-activatable implementations
new BasicJeriExporter(
    TcpServerEndpoint.getInstance(0),
    new BasicILFactory(),false, true)
  Description: The object to use for exporting the service. The value should not be null. In the activatable case, the call to getEntry will supply the activation ID in the data argument. This entry is obtained at service start and restart.
unexportRetryDelay
  Type: long
  Default: 1000 (1 second)
  Description: When destroying a Mercury server how long to wait between unexport attempts. unexportRetryDelay must be a positive long value. When destroying itself Mercury will sleep for unexportRetryDelay milliseconds between Exporter.unexport calls. Obtained at service start and restart. See maxUnexportDelay for additional details.

Access Control Permission Targets

The following table lists the remote methods on Mercury's proxy objects and the associated target names for enforcing access control using MercuryPermission:

Proxy Method Target Name
EventMailbox.register register
MailboxRegistration.enableDelivery enableDelivery
MailboxRegistration.disableDelivery disableDelivery
RemoteEventListener.notify notify
Lease.renew renew
Lease.cancel cancel
LeaseMap.renewAll renewAll
LeaseMap.cancelAll cancelAll
Administrable.getAdmin getAdmin
JoinAdmin.getLookupAttributes getLookupAttributes
JoinAdmin.addLookupAttributes addLookupAttributes
JoinAdmin.modifyLookupAttributes modifyLookupAttributes
JoinAdmin.getLookupGroups getLookupGroups
JoinAdmin.addLookupGroups addLookupGroups
JoinAdmin.removeLookupGroups removeLookupGroups
JoinAdmin.setLookupGroups setLookupGroups
JoinAdmin.getLookupLocators getLookupLocators
JoinAdmin.addLookupLocators addLookupLocators
JoinAdmin.removeLookupLocators removeLookupLocators
JoinAdmin.setLookupLocators setLookupLocators
DestroyAdmin.destroy destroy
ProxyTrust.getProxyVerifier getProxyVerifier
ServiceProxyAccessor.getServiceProxy getServiceProxy

Loggers and Logging Levels

The Mercury service implementation uses separate Loggers, prefixed by org.apache.river.mercury, for each type of information it logs. The following tables describe the type of information logged as well as the levels of information logged.

org.apache.river.mercury.admin
Level Description
FINEST for low level service destruction operation tracing

org.apache.river.mercury.delivery
Level Description
HANDLED for exceptions handled during failed event delivery attempts
FINEST for low level event delivery operation tracing

org.apache.river.mercury.expiration
Level Description
FINEST for low level lease expiration operation tracing

org.apache.river.mercury.init
Level Description
SEVERE for problems that prevent service startup
CONFIG for configuration access during service initialization
HANDLED for exceptions handled during service initialization
FINEST for low level operation tracing during service initialization

org.apache.river.mercury.lease
Level Description
FINEST for low level leasing operation tracing (creation, renewal, etc.)

org.apache.river.mercury.operations
Level Description
FINER for method level tracing during service operation

org.apache.river.mercury.persistence
Level Description
HANDLED for exceptions handled during service persistence attempts
FINEST for low level service persistence operation tracing

org.apache.river.mercury.receive
Level Description
FINEST for low level event reception tracing

org.apache.river.mercury.recovery
Level Description
HANDLED for exceptions handled during service recovery attempts
FINEST for low level service recovery operation tracing

org.apache.river.mercury.startup
Level Description
INFO for successful service creation message.

See the LogManager class for one way to use the HANDLED logging level in standard logging configuration files.

Examples for Running Mercury

This section provides examples of running Mercury in various configurations.

Assumptions for Running the Examples

The examples below make the following assumptions:

Throughout the example, items in bold need to be customized for your local environment.

Starting Transient Mercury using JRMP

To run a transient Mercury, which does not store any information persistently or use the activation system to restart itself, using JRMP for remote communication, run the following command.


java -Djava.security.policy=config_dir/jsk-all.policy \
     -jar install_dir/lib/start.jar \
     config_dir/start-transient-jrmp-mercury.config

This configuration uses the following files.

File config_dir/jsk-all.policy

Use this security policy file for starting and running all Mercury configurations. This file grants all permissions to local code included in the lib subdirectory of the Apache River release installation.


grant codebase "file:install_dir/lib/*" {
    permission java.security.AllPermission;
};

File config_dir/start-transient-jrmp-mercury.config

Use this configuration source file to start transient Mercury using JRMP.


import org.apache.river.start.NonActivatableServiceDescriptor;
import org.apache.river.start.ServiceDescriptor;

org.apache.river.start {
    private static codebase = "http://your_host:http_port/mercury-dl.jar"
       + " http://your_host:http_port/jsk-dl.jar";
    private static policy = "config_dir/jsk-all.policy";
    private static classpath = "install_dir/lib/mercury.jar";
    private static config = "config_dir/transient-jrmp-mercury.config";

    static serviceDescriptors = new ServiceDescriptor[] {
        new NonActivatableServiceDescriptor(
            codebase, policy, classpath,
            "org.apache.river.mercury.TransientMercuryImpl",
            new String[] { config })
    };
}

File config_dir/transient-jrmp-mercury.config

Use this configuration source file to run transient Mercury using JRMP.


import net.jini.jrmp.JrmpExporter;

org.apache.river.mercury {
    initialLookupGroups = new String[] { "your.group" };
    serverExporter = new JrmpExporter();
}

Starting Persistent Mercury using JRMP

To run a persistent Mercury, which stores information persistently but does not use the activation system to restart itself, using JRMP for remote communication, run the following command.


java -Djava.security.policy=config_dir/jsk-all.policy \
     -jar install_dir/lib/start.jar \
     config_dir/start-persistent-jrmp-mercury.config

Note: Because JRMP does not provide a convenient way to specify the same object ID each time a given object is exported, this configuration is only useful for debugging -- an existing service proxy cannot be used after the service is restarted.

This configuration uses the following additional files.

File config_dir/start-persistent-jrmp-mercury.config

Use this configuration source file to start persistent Mercury using JRMP.


import org.apache.river.start.NonActivatableServiceDescriptor;
import org.apache.river.start.ServiceDescriptor;

org.apache.river.start {
    private static codebase = "http://your_host:http_port/mercury-dl.jar"
       + " http://your_host:http_port/jsk-dl.jar";
    private static policy = "config_dir/jsk-all.policy";
    private static classpath = "install_dir/lib/mercury.jar";
    private static config = "config_dir/persistent-jrmp-mercury.config";

    static serviceDescriptors = new ServiceDescriptor[] {
        new NonActivatableServiceDescriptor(
            codebase, policy, classpath,
            "org.apache.river.mercury.NonActivatableMercuryImpl",
            new String[] { config })
    };
}

File config_dir/persistent-jrmp-mercury.config

Use this configuration source file to run persistent Mercury using JRMP.


import net.jini.jrmp.JrmpExporter;

org.apache.river.mercury {
    initialLookupGroups = new String[] { "your.group" };
    persistenceDirectory = "config_dir/mercury.log";
    serverExporter = new JrmpExporter();
}

Starting Activatable Mercury using JRMP

To run an activatable Mercury, which stores information persistently and uses the activation system to restart itself, using JRMP for remote communication, run the following command.


java -Djava.security.policy=config_dir/jsk-all.policy \
     -jar install_dir/lib/start.jar \
     config_dir/start-activatable-jrmp-mercury.config

You should remove the config_dir/group.log directory before running this command. Note that the activation system will restart the activatable Mercury service as needed until Mercury is shutdown.

Remember to remove the config_dir/mercury.log directory before running this command if you want Mercury to forget registrations and settings made in previous invocations.

This configuration uses the following additional files.

File config_dir/start-activatable-jrmp-mercury.config

Use this configuration source file to start activatable Mercury using JRMP.


import org.apache.river.start.ServiceDescriptor;
import org.apache.river.start.SharedActivatableServiceDescriptor;
import org.apache.river.start.SharedActivationGroupDescriptor;

org.apache.river.start {
    private static mercuryCodebase = "http://your_host:http_port/mercury-dl.jar"
       + " http://your_host:http_port/jsk-dl.jar";
    private static mercuryPolicy = "config_dir/jsk-all.policy";
    private static mercuryClasspath = "install_dir/lib/mercury.jar";
    private static mercuryConfig = "config_dir/activatable-jrmp-mercury.config";

    private static groupPolicy = "config_dir/jsk-all.policy";
    private static groupClasspath = "install_dir/lib/sharedvm.jar";
    private static groupPersistenceDirectory = "config_dir/group.log";

    static serviceDescriptors = new ServiceDescriptor[] {
        new SharedActivationGroupDescriptor(
            groupPolicy, groupClasspath, groupPersistenceDirectory,
            null /* serverCommand */,
            null /* serverOptions */,
            null /* serverProperties */),
        new SharedActivatableServiceDescriptor(
            mercuryCodebase, mercuryPolicy, mercuryClasspath,
            "org.apache.river.mercury.ActivatableMercuryImpl",
            groupPersistenceDirectory,
            new String[] { mercuryConfig },
            true /* restart */)
    };
}

File config_dir/activatable-jrmp-mercury.config

Use this configuration source file to run activatable Mercury using JRMP.


import java.rmi.activation.ActivationID;
import net.jini.jrmp.JrmpExporter;

org.apache.river.mercury {
    initialLookupGroups = new String[] { "your.group" };
    persistenceDirectory = "config_dir/mercury.log";
    serverExporter = new JrmpExporter((ActivationID) $data, 0);
}

Stopping Activatable Mercury

To destroy the activation group running an activatable Mercury, under a a JRMP or Jini ERI configuration, run the following command.


java -Djava.security.policy=config_dir/jsk-all.policy \
     -jar install_dir/lib/destroy.jar \
     config_dir/stop-activatable-mercury.config

Running this command will remove the config_dir/group.log directory.

Note that this command does not actually destroy the service itself, but just destroys the activation group the service is running in. You may want to first destroy the service using Mercury's administrable interface, or to remove the config_dir/mercury.log directory after destroying the activation group.

This command uses the following additional file.

File config_dir/stop-activatable-mercury.config

Use this configuration source file to destroy the activation group for an activatable Mercury.


import org.apache.river.start.ServiceDescriptor;
import org.apache.river.start.SharedActivatableServiceDescriptor;

org.apache.river.start {
    private static codebase = "http://your_host:http_port/group-dl.jar";
    private static policy = "config_dir/jsk-all.policy";
    private static classpath = "install_dir/lib/group.jar";
    private static persistenceDirectory = "config_dir/group.log";

    static serviceDestructors = new ServiceDescriptor[] {
        new SharedActivatableServiceDescriptor(
            codebase, policy, classpath,
            "org.apache.river.start.SharedGroupImpl",
            persistenceDirectory,
            null /* config */,
            false /* restart */)
    };
}

Starting Transient Mercury using Jini ERI

To run a transient Mercury, which does not store any information persistently or use the activation system to restart itself, using Jini ERI for remote communication, run the following command.


java -Djava.security.policy=config_dir/jsk-all.policy \
     -jar install_dir/lib/start.jar \
     config_dir/start-transient-mercury.config

This configuration uses the following additional files.

File config_dir/start-transient-mercury.config

Use this configuration source file to start transient Mercury using Jini ERI.


import org.apache.river.start.NonActivatableServiceDescriptor;
import org.apache.river.start.ServiceDescriptor;

org.apache.river.start {
    private static codebase = "http://your_host:http_port/mercury-dl.jar"
       + " http://your_host:http_port/jsk-dl.jar";
    private static policy = "config_dir/jsk-all.policy";
    private static classpath = "install_dir/lib/mercury.jar";
    private static config = "config_dir/transient-mercury.config";

    static serviceDescriptors = new ServiceDescriptor[] {
        new NonActivatableServiceDescriptor(
            codebase, policy, classpath,
            "org.apache.river.mercury.TransientMercuryImpl",
            new String[] { config })
    };
}

File config_dir/transient-mercury.config

Use this configuration source file to run transient Mercury using Jini ERI.


org.apache.river.mercury {
    initialLookupGroups = new String[] { "your.group" };
}

Starting Persistent Mercury using Jini ERI

To run a persistent Mercury, which stores information persistently but does not use the activation system to restart itself, using Jini ERI for remote communication, run the following command.


java -Djava.security.policy=config_dir/jsk-all.policy \
     -jar install_dir/lib/start.jar \
     config_dir/start-persistent-mercury.config

This configuration uses the following additional files.

File config_dir/start-persistent-mercury.config

Use this configuration source file to start persistent Mercury using Jini ERI.


import org.apache.river.start.NonActivatableServiceDescriptor;
import org.apache.river.start.ServiceDescriptor;

org.apache.river.start {
    private static codebase = "http://your_host:http_port/mercury-dl.jar"
       + " http://your_host:http_port/jsk-dl.jar";
    private static policy = "config_dir/jsk-all.policy";
    private static classpath = "install_dir/lib/mercury.jar";
    private static config = "config_dir/persistent-mercury.config";

    static serviceDescriptors = new ServiceDescriptor[] {
        new NonActivatableServiceDescriptor(
            codebase, policy, classpath,
            "org.apache.river.mercury.NonActivatableMercuryImpl",
            new String[] { config })
    };
}

File config_dir/persistent-mercury.config

Use this configuration source file to run persistent Mercury using Jini ERI.


import net.jini.id.UuidFactory;
import net.jini.jeri.BasicILFactory;
import net.jini.jeri.BasicJeriExporter;
import net.jini.jeri.tcp.TcpServerEndpoint;

org.apache.river.mercury {
    initialLookupGroups = new String[] { "your.group" };
    persistenceDirectory = "config_dir/mercury.log";
    serverExporter = new BasicJeriExporter(
        TcpServerEndpoint.getInstance(obj_port),
        new BasicILFactory(),
        false,
        true,
        UuidFactory.create("obj_UUID_string"));
}

The obj_port is the fixed TCP port to use for listening for requests for this object. The obj_UUID_string is the universally unique ID for the exported object. These IDs have the form "01234567-89ab-cdef-0123-456789abcdef".

Remember to remove the config_dir/mercury.log directory before restarting persistent Mercury if you want it to forget registrations and settings made in previous invocations.

Starting Activatable Mercury using Jini ERI

To run an activatable Mercury, which stores information persistently and uses the activation system to restart itself, using Jini ERI for remote communication, run the following command.


java -Djava.security.policy=config_dir/jsk-all.policy \
     -jar install_dir/lib/start.jar \
     config_dir/start-activatable-mercury.config

You should remove the config_dir/group.log directory before running this command. Note that the activation system will restart the activatable Mercury service as needed until Mercury is shutdown.

Remember to remove the config_dir/mercury.log directory before running this command if you want Mercury to forget registrations and settings made in previous invocations.

This configuration uses the following additional files.

File config_dir/start-activatable-mercury.config

Use this configuration source file to start activatable Mercury using Jini ERI.


import org.apache.river.start.ServiceDescriptor;
import org.apache.river.start.SharedActivatableServiceDescriptor;
import org.apache.river.start.SharedActivationGroupDescriptor;

org.apache.river.start {
    private static mercuryCodebase = "http://your_host:http_port/mercury-dl.jar"
       + " http://your_host:http_port/jsk-dl.jar";
    private static mercuryPolicy = "config_dir/jsk-all.policy";
    private static mercuryClasspath = "install_dir/lib/mercury.jar";
    private static mercuryConfig = "config_dir/activatable-mercury.config";

    private static groupPolicy = "config_dir/jsk-all.policy";
    private static groupClasspath = "install_dir/lib/sharedvm.jar";
    private static groupPersistenceDirectory = "config_dir/group.log";

    static serviceDescriptors = new ServiceDescriptor[] {
        new SharedActivationGroupDescriptor(
            groupPolicy, groupClasspath, groupPersistenceDirectory,
            null /* serverCommand */,
            null /* serverOptions */,
            null /* serverProperties */),
        new SharedActivatableServiceDescriptor(
            mercuryCodebase, mercuryPolicy, mercuryClasspath,
            "org.apache.river.mercury.ActivatableMercuryImpl",
            groupPersistenceDirectory,
            new String[] { mercuryConfig },
            true /* restart */)
    };
}

File config_dir/activatable-mercury.config

Use this configuration source file to run activatable Mercury using Jini ERI.


org.apache.river.mercury {
    initialLookupGroups = new String[] { "your.group" };
    persistenceDirectory = "config_dir/mercury.log";
}

See Also:
EventMailbox
Skip navigation links

Copyright 2007-2013, multiple authors.
Licensed under the Apache License, Version 2.0, see the NOTICE file for attributions.