Open umask before creating release packages
[exim.git] / doc / doc-txt / experimental-spec.txt
index f0f1035ea003850cc93df0f21782b3e698570789..2a1901ade14cde281670bc4c28081c4954646eb2 100644 (file)
@@ -6,7 +6,7 @@ about experimental  features, all  of which  are unstable and
 liable to incompatible change.
 
 
 liable to incompatible change.
 
 
-Brightmail AntiSpam (BMI) suppport
+Brightmail AntiSpam (BMI) support
 --------------------------------------------------------------
 
 Brightmail  AntiSpam  is  a  commercial  package.  Please  see
 --------------------------------------------------------------
 
 Brightmail  AntiSpam  is  a  commercial  package.  Please  see
@@ -42,7 +42,7 @@ These four steps are explained in more details below.
 1) Adding support for BMI at compile time
 
   To compile with BMI support,  you need to link Exim  against
 1) Adding support for BMI at compile time
 
   To compile with BMI support,  you need to link Exim  against
-  the   Brighmail  client   SDK,  consisting   of  a   library
+  the  Brightmail  client   SDK,  consisting   of  a   library
   (libbmiclient_single.so)  and  a  header  file  (bmi_api.h).
   You'll also need to explicitly set a flag in the Makefile to
   include BMI support in the Exim binary. Both can be achieved
   (libbmiclient_single.so)  and  a  header  file  (bmi_api.h).
   You'll also need to explicitly set a flag in the Makefile to
   include BMI support in the Exim binary. Both can be achieved
@@ -550,7 +550,7 @@ Then set something like
 mout-xforward.gmx.net           82.165.159.12
 mout.gmx.net                    212.227.15.16
 
 mout-xforward.gmx.net           82.165.159.12
 mout.gmx.net                    212.227.15.16
 
-Use a reasonable IP. eg. one the sending cluster acutally uses.
+Use a reasonable IP. eg. one the sending cluster actually uses.
 
 DMARC Support
 --------------------------------------------------------------
 
 DMARC Support
 --------------------------------------------------------------
@@ -771,353 +771,6 @@ b. Configure, somewhere before the DATA ACL, the control option to
 
 
 
 
 
 
-Event Actions
---------------------------------------------------------------
-
-(Renamed from TPDA, Transport post-delivery actions)
-
-An arbitrary per-transport string can be expanded upon various transport events.
-Additionally a main-section configuration option can be expanded on some
-per-message events.
-This feature may be used, for example, to write exim internal log information
-(not available otherwise) into a database.
-
-In order to use the feature, you must compile with
-
-EXPERIMENTAL_EVENT=yes
-
-in your Local/Makefile
-
-and define one or both of
-- the event_action option in the transport
-- the event_action main option
-to be expanded when the event fires.
-
-A new variable, $event_name, is set to the event type when the
-expansion is done.  The current list of events is:
-
- msg:complete          after  main       per message
- msg:delivery          after  transport  per recipient
- msg:rcpt:host:defer   after  transport  per recipient per host
- msg:rcpt:defer        after  transport  per recipient
- msg:host:defer                after  transport  per attempt
- msg:fail:delivery     after  main       per recipient
- msg:fail:internal     after  main       per recipient
- tcp:connect           before transport  per connection
- tcp:close             after  transport  per connection
- tls:cert              before both       per certificate in verification chain
- smtp:connect          after  transport  per connection
-
-The expansion is called for all event types, and should use the $event_name
-variable to decide when to act.  The value of the variable is a colon-separated
-list, defining a position in the tree of possible events; it may be used as
-a list or just matched on as a whole.  There will be no whitespace.
-
-New event types may be added in the future.
-
-
-There is an auxilary variable, $event_data, for which the
-content is event_dependent:
-
-       msg:delivery            smtp confirmation mssage
-       msg:rcpt:host:defer     error string
-       msg:rcpt:defer          error string
-       msg:host:defer          error string
-       tls:cert                verification chain depth
-       smtp:connect            smtp banner
-
-The :defer events populate one extra variable, $event_defer_errno.
-
-The following variables are likely to be useful depending on the event type:
-
-       router_name, transport_name
-       local_part, domain
-       host, host_address, host_port
-       tls_out_peercert
-       lookup_dnssec_authenticated, tls_out_dane
-       sending_ip_address, sending_port
-       message_exim_id, verify_mode
-
-
-An example might look like:
-
-event_action = ${if eq {msg:delivery}{$event_name} \
-{${lookup pgsql {SELECT * FROM record_Delivery( \
-    '${quote_pgsql:$sender_address_domain}',\
-    '${quote_pgsql:${lc:$sender_address_local_part}}', \
-    '${quote_pgsql:$domain}', \
-    '${quote_pgsql:${lc:$local_part}}', \
-    '${quote_pgsql:$host_address}', \
-    '${quote_pgsql:${lc:$host}}', \
-    '${quote_pgsql:$message_exim_id}')}} \
-} {}}
-
-The string is expanded when each of the supported events occur
-and any side-effects of the expansion will happen.
-
-Note that for complex operations an ACL expansion can be used,
-however due to the multiple contexts the Exim operates in
-a) variables set in events raised from transports will not
-   be visible outside that transport call.
-b) acl_m variables in a server context are lost on a new connection,
-   and after helo/ehlo/mail/starttls/rset commands
-Using an ACL expansion with the logwrite modifier can be a
-useful way of writing to the main log.
-
-
-
-The expansion of the event_action option should normally
-return an empty string.  Should it return anything else the
-following will be forced:
-
-       msg:delivery    (ignored)
-       msg:host:defer  (ignored)
-       msg:fail:delivery (ignored)
-       tcp:connect     do not connect
-       tcp:close       (ignored)
-       tls:cert        refuse verification
-       smtp:connect    close connection
-
-No other use is made of the result string.
-
-If transport proxying is used, the remote IP/port during a
-tcp:connect event will be that of the proxy.
-
-
-Known issues:
-- the tls:cert event is only called for the cert chain elements
-  received over the wire, with GnuTLS.  OpenSSL gives the entire
-  chain including those loaded locally.
-
-
-Redis Lookup
---------------------------------------------------------------
-
-Redis is open source advanced key-value data store. This document
-does not explain the fundamentals, you should read and understand how
-it works by visiting the website at http://www.redis.io/.
-
-Redis lookup support is added via the hiredis library.  Visit:
-
-  https://github.com/redis/hiredis
-
-to obtain a copy, or find it in your operating systems package repository.
-If building from source, this description assumes that headers will be in
-/usr/local/include, and that the libraries are in /usr/local/lib.
-
-1. In order to build exim with Redis lookup support add
-
-EXPERIMENTAL_REDIS=yes
-
-to your Local/Makefile. (Re-)build/install exim. exim -d should show
-Experimental_Redis in the line "Support for:".
-
-EXPERIMENTAL_REDIS=yes
-LDFLAGS += -lhiredis
-# CFLAGS += -I/usr/local/include
-# LDFLAGS += -L/usr/local/lib
-
-The first line sets the feature to include the correct code, and
-the second line says to link the hiredis libraries into the
-exim binary.  The commented out lines should be uncommented if you
-built hiredis from source and installed in the default location.
-Adjust the paths if you installed them elsewhere, but you do not
-need to uncomment them if an rpm (or you) installed them in the
-package controlled locations (/usr/include and /usr/lib).
-
-
-2. Use the following global settings to configure Redis lookup support:
-
-Required:
-redis_servers       This option provides a list of Redis servers
-                    and associated connection data, to be used in
-                    conjunction with redis lookups. The option is
-                    only available if Exim is configured with Redis
-                    support.
-
-For example:
-
-redis_servers = 127.0.0.1/10/ - using database 10 with no password
-redis_servers = 127.0.0.1//password - to make use of the default database of 0 with a password
-redis_servers = 127.0.0.1// - for default database of 0 with no password
-
-3. Once you have the Redis servers defined you can then make use of the
-experimental Redis lookup by specifying ${lookup redis{}} in a lookup query.
-
-4. Example usage:
-
-(Host List)
-hostlist relay_from_ips = <\n ${lookup redis{SMEMBERS relay_from_ips}}
-
-Where relay_from_ips is a Redis set which contains entries such as "192.168.0.0/24" "10.0.0.0/8" and so on.
-The result set is returned as
-192.168.0.0/24
-10.0.0.0/8
-..
-.
-
-(Domain list)
-domainlist virtual_domains = ${lookup redis {HGET $domain domain}}
-
-Where $domain is a hash which includes the key 'domain' and the value '$domain'.
-
-(Adding or updating an existing key)
-set acl_c_spammer = ${if eq{${lookup redis{SPAMMER_SET}}}{OK}}
-
-Where SPAMMER_SET is a macro and it is defined as
-
-"SET SPAMMER <some_value>"
-
-(Getting a value from Redis)
-
-set acl_c_spam_host = ${lookup redis{GET...}}
-
-
-Proxy Protocol Support
---------------------------------------------------------------
-
-Exim now has Experimental "Proxy Protocol" support.  It was built on
-specifications from:
-http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
-Above URL revised May 2014 to change version 2 spec:
-http://git.1wt.eu/web?p=haproxy.git;a=commitdiff;h=afb768340c9d7e50d8e
-
-The purpose of this function is so that an application load balancer,
-such as HAProxy, can sit in front of several Exim servers and Exim
-will log the IP that is connecting to the proxy server instead of
-the IP of the proxy server when it connects to Exim.  It resets the
-$sender_address_host and $sender_address_port to the IP:port of the
-connection to the proxy.  It also re-queries the DNS information for
-this new IP address so that the original sender's hostname and IP
-get logged in the Exim logfile.  There is no logging if a host passes or
-fails Proxy Protocol negotiation, but it can easily be determined and
-recorded in an ACL (example is below).
-
-1. To compile Exim with Proxy Protocol support, put this in
-Local/Makefile:
-
-EXPERIMENTAL_PROXY=yes
-
-2. Global configuration settings:
-
-proxy_required_hosts = HOSTLIST
-
-The proxy_required_hosts option will require any IP in that hostlist
-to use Proxy Protocol. The specification of Proxy Protocol is very
-strict, and if proxy negotiation fails, Exim will not allow any SMTP
-command other than QUIT. (See end of this section for an example.)
-The option is expanded when used, so it can be a hostlist as well as
-string of IP addresses.  Since it is expanded, specifying an alternate
-separator is supported for ease of use with IPv6 addresses.
-
-To log the IP of the proxy in the incoming logline, add:
-  log_selector = +proxy
-
-A default incoming logline (wrapped for appearance) will look like this:
-
-  2013-11-04 09:25:06 1VdNti-0001OY-1V <= me@example.net
-  H=mail.example.net [1.2.3.4] P=esmtp S=433
-
-With the log selector enabled, an email that was proxied through a
-Proxy Protocol server at 192.168.1.2 will look like this:
-
-  2013-11-04 09:25:06 1VdNti-0001OY-1V <= me@example.net
-  H=mail.example.net [1.2.3.4] P=esmtp PRX=192.168.1.2 S=433
-
-3. In the ACL's the following expansion variables are available.
-
-proxy_host_address   The (internal) src IP of the proxy server
-                     making the connection to the Exim server.
-proxy_host_port      The (internal) src port the proxy server is
-                     using to connect to the Exim server.
-proxy_target_address The dest (public) IP of the remote host to
-                     the proxy server.
-proxy_target_port    The dest port the remote host is using to
-                     connect to the proxy server.
-proxy_session        Boolean, yes/no, the connected host is required
-                     to use Proxy Protocol.
-
-There is no expansion for a failed proxy session, however you can detect
-it by checking if $proxy_session is true but $proxy_host is empty.  As
-an example, in my connect ACL, I have:
-
-  warn    condition      = ${if and{ {bool{$proxy_session}} \
-                                     {eq{$proxy_host_address}{}} } }
-          log_message    = Failed required proxy protocol negotiation \
-                           from $sender_host_name [$sender_host_address]
-
-  warn    condition      = ${if and{ {bool{$proxy_session}} \
-                                     {!eq{$proxy_host_address}{}} } }
-          # But don't log health probes from the proxy itself
-          condition      = ${if eq{$proxy_host_address}{$sender_host_address} \
-                                {false}{true}}
-          log_message    = Successfully proxied from $sender_host_name \
-                           [$sender_host_address] through proxy protocol \
-                           host $proxy_host_address
-
-  # Possibly more clear
-  warn logwrite = Remote Source Address: $sender_host_address:$sender_host_port
-       logwrite = Proxy Target Address: $proxy_target_address:$proxy_target_port
-       logwrite = Proxy Internal Address: $proxy_host_address:$proxy_host_port
-       logwrite = Internal Server Address: $received_ip_address:$received_port
-
-
-4. Recommended ACL additions:
-   - Since the real connections are all coming from your proxy, and the
-     per host connection tracking is done before Proxy Protocol is
-     evaluated, smtp_accept_max_per_host must be set high enough to
-     handle all of the parallel volume you expect per inbound proxy.
-   - With the smtp_accept_max_per_host set so high, you lose the ability
-     to protect your server from massive numbers of inbound connections
-     from one IP.  In order to prevent your server from being DOS'd, you
-     need to add a per connection ratelimit to your connect ACL.  I
-     suggest something like this:
-
-  # Set max number of connections per host
-  LIMIT   = 5
-  # Or do some kind of IP lookup in a flat file or database
-  # LIMIT = ${lookup{$sender_host_address}iplsearch{/etc/exim/proxy_limits}}
-
-  defer   message        = Too many connections from this IP right now
-          ratelimit      = LIMIT / 5s / per_conn / strict
-
-
-5. Runtime issues to be aware of:
-   - The proxy has 3 seconds (hard-coded in the source code) to send the
-     required Proxy Protocol header after it connects.  If it does not,
-     the response to any commands will be:
-     "503 Command refused, required Proxy negotiation failed"
-   - If the incoming connection is configured in Exim to be a Proxy
-     Protocol host, but the proxy is not sending the header, the banner
-     does not get sent until the timeout occurs.  If the sending host
-     sent any input (before the banner), this causes a standard Exim
-     synchronization error (i.e. trying to pipeline before PIPELINING
-     was advertised).
-   - This is not advised, but is mentioned for completeness if you have
-     a specific internal configuration that you want this:  If the Exim
-     server only has an internal IP address and no other machines in your
-     organization will connect to it to try to send email, you may
-     simply set the hostlist to "*", however, this will prevent local
-     mail programs from working because that would require mail from
-     localhost to use Proxy Protocol.  Again, not advised!
-
-6. Example of a refused connection because the Proxy Protocol header was
-not sent from a host configured to use Proxy Protocol.  In the example,
-the 3 second timeout occurred (when a Proxy Protocol banner should have
-been sent), the banner was displayed to the user, but all commands are
-rejected except for QUIT:
-
-# nc mail.example.net 25
-220-mail.example.net, ESMTP Exim 4.82+proxy, Mon, 04 Nov 2013 10:45:59
-220 -0800 RFC's enforced
-EHLO localhost
-503 Command refused, required Proxy negotiation failed
-QUIT
-221 mail.example.net closing connection
-
-
-
-
 DANE
 ------------------------------------------------------------
 DNS-based Authentication of Named Entities, as applied
 DANE
 ------------------------------------------------------------
 DNS-based Authentication of Named Entities, as applied
@@ -1231,18 +884,20 @@ with DANE in their OCSP settings.
 
 
 For client-side DANE there are two new smtp transport options,
 
 
 For client-side DANE there are two new smtp transport options,
-hosts_try_dane and hosts_require_dane.  They do the obvious thing.
+hosts_try_dane and hosts_require_dane.
 [ should they be domain-based rather than host-based? ]
 
 [ should they be domain-based rather than host-based? ]
 
+Hosts_require_dane will result in failure if the target host
+is not DNSSEC-secured.
+
 DANE will only be usable if the target host has DNSSEC-secured
 MX, A and TLSA records.
 
 A TLSA lookup will be done if either of the above options match
 DANE will only be usable if the target host has DNSSEC-secured
 MX, A and TLSA records.
 
 A TLSA lookup will be done if either of the above options match
-and the host-lookup succeded using dnssec.
+and the host-lookup succeeded using dnssec.
 If a TLSA lookup is done and succeeds, a DANE-verified TLS connection
 If a TLSA lookup is done and succeeds, a DANE-verified TLS connection
-will be required for the host.
-
-(TODO: specify when fallback happens vs. when the host is not used)
+will be required for the host.  If it does not, the host will not
+be used; there is no fallback to non-DANE or non-TLS.
 
 If DANE is requested and useable (see above) the following transport
 options are ignored:
 
 If DANE is requested and useable (see above) the following transport
 options are ignored:
@@ -1270,102 +925,6 @@ $tls_out_tlsa_usage (detailed above).
 
 
 
 
 
 
-INTERNATIONAL
-------------------------------------------------------------
-SMTPUTF8
-Internationalised mail name handling.
-RFCs 6530, 6533, 5890
-
-Compile with EXPERIMENTAL_INTERNATIONAL and libidn.
-
-New main config option smtputf8_advertise_hosts, default '*',
-a host list.  If this matches the sending host and
-accept_8bitmime is true (the default) then the ESMTP option
-SMTPUTF8 will be advertised.
-
-If the sender specifies the SMTPUTF8 option on a MAIL command
-international handling for the message is enabled and
-the expansion variable $message_smtputf8 will have value TRUE.
-
-The option allow_utf8_domains is set to true for this
-message. All DNS lookups are converted to a-label form
-whatever the setting of allow_utf8_domains.
-
-Both localparts and domain are maintained as the original
-utf8 form internally; any matching or regex use will
-require appropriate care.  Filenames created, eg. by
-the appendfile transport, will have utf8 name.
-
-Helo names sent by the smtp transport will have any utf8
-components expanded to a-label form.
-
-Any certificate name checks will be done using the a-label
-form of the name.
-
-Log lines and Received-by: header lines will aquire a "utf8"
-prefix on the protocol element, eg. utf8esmtp.
-
-New expansion operators:
-       ${utf8_domain_to_alabel:str}
-       ${utf8_domain_from_alabel:str}
-       ${utf8_localpart_to_alabel:str}
-       ${utf8_localpart_from_alabel:str}
-
-New "control = utf8_downconvert" ACL modifier,
-sets a flag requiring that addresses are converted to
-a-label form before smtp delivery, for use in a
-Message Submission Agent context.  Can also be
-phrased as "control = utf8_downconvert/1" and is
-mandatory.  The flag defaults to zero and can be cleared
-by "control = utf8_downconvert/0".  The value "-1"
-may also be used, to use a-label for only if the
-destination host does not support SMTPUTF8.
-
-If mua_wrapper is set, the utf8_downconvert control
-defaults to -1 (convert if needed).
-
-
-There is no explicit support for VRFY and EXPN.
-Configurations supporting these should inspect
-$smtp_command_argument for an SMTPUTF8 argument.
-
-There is no support for LMTP on Unix sockets.
-Using the "lmtp" protocol option on an smtp transport,
-for LMTP over TCP, should work as expected.
-
-Known issues:
- - DSN unitext handling is not present
- - no provision for converting logging from or to UTF-8
-
-----
-IMAP folder names
-
-New expansion operator:
-
-${imapfolder {<string>} {<sep>} {<specials>}}
-
-The string is converted from the charset specified by the headers charset 
-command (in a filter file) or headers_charset global option, to the
-modified UTF-7 encoding specified by RFC 2060, with the following
-exception: All occurences of <sep> (which has to be a single character)
-are replaced with periods ("."), and all periods and slashes that aren't
-<sep> and are not in the <specials> string are BASE64 encoded.
-
-The third argument can be omitted, defaulting to an empty string.
-The second argument can be omitted, defaulting to "/".
-
-This is the encoding used by Courier for Maildir names on disk, and followed
-by many other IMAP servers.
-
-   Example 1: ${imapfolder {Foo/Bar}}       yields "Foo.Bar".
-   Example 2: ${imapfolder {Foo/Bar}{.}{/}} yields "Foo&AC8-Bar".
-   Example 3: ${imapfolder {Räksmörgås}}    yields "R&AOQ-ksm&APY-rg&AOU-s".
-
-Note that the source charset setting is vital, and also that characters
-must be representable in UTF-16.
-
-
-
 DSN extra information
 ---------------------
 If compiled with EXPERIMENTAL_DSN_INFO extra information will be added
 DSN extra information
 ---------------------
 If compiled with EXPERIMENTAL_DSN_INFO extra information will be added
@@ -1401,13 +960,114 @@ The reporting MTA detailed diagnostic.
 Example:
   X-Exim-Diagnostic: X-str; SMTP error from remote mail server after RCPT TO:<d3@myhost.test.ex>: 550 hard error
 Rationale:
 Example:
   X-Exim-Diagnostic: X-str; SMTP error from remote mail server after RCPT TO:<d3@myhost.test.ex>: 550 hard error
 Rationale:
-  This string somtimes give extra information over the
+  This string sometimes give extra information over the
   existing (already available) Diagnostic-Code field.
 
 
 Note that non-RFC-documented field names and data types are used.
 
 
   existing (already available) Diagnostic-Code field.
 
 
 Note that non-RFC-documented field names and data types are used.
 
 
+LMDB Lookup support
+-------------------
+LMDB is an ultra-fast, ultra-compact, crash-proof key-value embedded data store.
+It is modeled loosely on the BerkeleyDB API. You should read about the feature
+set as well as operation modes at https://symas.com/products/lightning-memory-mapped-database/
+
+LMDB single key lookup support is provided by linking to the LMDB C library.
+The current implementation does not support writing to the LMDB database.
+
+Visit https://github.com/LMDB/lmdb to download the library or find it in your
+operating systems package repository.
+
+If building from source, this description assumes that headers will be in
+/usr/local/include, and that the libraries are in /usr/local/lib.
+
+1. In order to build exim with LMDB lookup support add or uncomment
+
+EXPERIMENTAL_LMDB=yes
+
+to your Local/Makefile. (Re-)build/install exim. exim -d should show
+Experimental_LMDB in the line "Support for:".
+
+EXPERIMENTAL_LMDB=yes
+LDFLAGS += -llmdb
+# CFLAGS += -I/usr/local/include
+# LDFLAGS += -L/usr/local/lib
+
+The first line sets the feature to include the correct code, and
+the second line says to link the LMDB libraries into the
+exim binary.  The commented out lines should be uncommented if you
+built LMDB from source and installed in the default location.
+Adjust the paths if you installed them elsewhere, but you do not
+need to uncomment them if an rpm (or you) installed them in the
+package controlled locations (/usr/include and /usr/lib).
+
+2. Create your LMDB files, you can use the mdb_load utility which is
+part of the LMDB distribution our your favourite language bindings.
+
+3. Add the single key lookups to your exim.conf file, example lookups
+are below.
+
+${lookup{$sender_address_domain}lmdb{/var/lib/baruwa/data/db/relaydomains.mdb}{$value}}
+${lookup{$sender_address_domain}lmdb{/var/lib/baruwa/data/db/relaydomains.mdb}{$value}fail}
+${lookup{$sender_address_domain}lmdb{/var/lib/baruwa/data/db/relaydomains.mdb}}
+
+
+Queuefile transport
+-------------------
+Queuefile is a pseudo transport which does not perform final delivery.
+It simply copies the exim spool files out of the spool directory into
+an external directory retaining the exim spool format.
+
+The spool files can then be processed by external processes and then
+requeued into exim spool directories for final delivery.
+
+The motivation/inspiration for the transport is to allow external
+processes to access email queued by exim and have access to all the
+information which would not be available if the messages were delivered
+to the process in the standard email formats.
+
+The mailscanner package is one of the processes that can take advantage
+of this transport to filter email.
+
+The transport can be used in the same way as the other existing transports,
+i.e by configuring a router to route mail to a transport configured with
+the queuefile driver.
+
+The transport only takes one option:
+
+* directory - This is used to specify the directory messages should be
+copied to
+
+The generic transport options (body_only, current_directory, disable_logging,
+debug_print, delivery_date_add, envelope_to_add, event_action, group,
+headers_add, headers_only, headers_remove, headers_rewrite, home_directory,
+initgroups, max_parallel, message_size_limit, rcpt_include_affixes,
+retry_use_local_part, return_path, return_path_add, shadow_condition,
+shadow_transport, transport_filter, transport_filter_timeout, user) are
+ignored.
+
+Sample configuration:
+
+(Router)
+
+scan:
+   driver = accept
+   transport = scan
+
+(Transport)
+
+scan:
+  driver = queuefile
+  directory = /var/spool/baruwa-scanner/input
+
+
+In order to build exim with Queuefile transport support add or uncomment
+
+EXPERIMENTAL_QUEUEFILE=yes
+
+to your Local/Makefile. (Re-)build/install exim. exim -d should show
+Experimental_QUEUEFILE in the line "Support for:".
 
 
 --------------------------------------------------------------
 
 
 --------------------------------------------------------------