unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* Notmuch-side support for git send-email --notmuch id:<MESSAGE-ID>
@ 2009-11-25  1:35 Jed Brown
  2009-11-25  1:35 ` [PATCH 1/2] notmuch-reply.c: accept the --format=default default option Jed Brown
  2009-11-28  1:00 ` Notmuch-side support for git send-email --notmuch id:<MESSAGE-ID> Carl Worth
  0 siblings, 2 replies; 9+ messages in thread
From: Jed Brown @ 2009-11-25  1:35 UTC (permalink / raw)
  To: notmuch

These two patches provide support for features like the one in the
subject line.  Along with these two patches, I have one for git
format-patch (which I will submit upstream soon) that uses the output
from notmuch reply --format=headers-only to build a reply with proper
referencing, To, and Cc fields.

Since options for git send-email are passed to git format-patch,

  git send-email --notmuch id:<ID>

is a substitute for

  git send-email --in-reply-to <ID> --to <TO> --cc <CC> --add-header 'References: ...'

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/2] notmuch-reply.c: accept the --format=default default option.
  2009-11-25  1:35 Notmuch-side support for git send-email --notmuch id:<MESSAGE-ID> Jed Brown
@ 2009-11-25  1:35 ` Jed Brown
  2009-11-25  1:35   ` [PATCH 2/2] notmuch-reply.c: implement notmuch_reply_format_headers_only Jed Brown
  2009-11-25 18:02   ` [PATCH 1/2] reply --format=headers-only: set In-Reply-To header, with ID *last* in References Jed Brown
  2009-11-28  1:00 ` Notmuch-side support for git send-email --notmuch id:<MESSAGE-ID> Carl Worth
  1 sibling, 2 replies; 9+ messages in thread
From: Jed Brown @ 2009-11-25  1:35 UTC (permalink / raw)
  To: notmuch

This factors actual generation of the reply out of notmuch_reply_command
into notmuch_reply_format_default(), in preparation for other --format=
options.

Signed-off-by: Jed Brown <jed@59A2.org>
---
 notmuch-reply.c |  121 +++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 78 insertions(+), 43 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 65bd356..17eb38d 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -23,6 +23,17 @@
 #include "notmuch-client.h"
 #include "gmime-filter-reply.h"
 
+static const struct {
+    const char *header;
+    const char *fallback;
+    GMimeRecipientType recipient_type;
+} reply_to_map[] = {
+    { "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
+    { "to",         NULL, GMIME_RECIPIENT_TYPE_TO  },
+    { "cc",         NULL, GMIME_RECIPIENT_TYPE_CC  },
+    { "bcc",        NULL, GMIME_RECIPIENT_TYPE_BCC }
+};
+
 static void
 reply_part_content (GMimeObject *part)
 {
@@ -182,58 +193,17 @@ add_recipients_for_string (GMimeMessage *message,
     return add_recipients_for_address_list (message, config, type, list);
 }
 
-int
-notmuch_reply_command (void *ctx, int argc, char *argv[])
+static int
+notmuch_reply_format_default(void *ctx, notmuch_config_t *config, notmuch_query_t *query)
 {
-    notmuch_config_t *config;
-    notmuch_database_t *notmuch;
-    notmuch_query_t *query;
     GMimeMessage *reply;
-    char *query_string;
     notmuch_messages_t *messages;
     notmuch_message_t *message;
-    int ret = 0;
     const char *subject, *recipients, *from_addr = NULL;
     const char *in_reply_to, *orig_references, *references;
     char *reply_headers;
-    struct {
-	const char *header;
-	const char *fallback;
-	GMimeRecipientType recipient_type;
-    } reply_to_map[] = {
-	{ "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
-	{ "to",         NULL, GMIME_RECIPIENT_TYPE_TO  },
-	{ "cc",         NULL, GMIME_RECIPIENT_TYPE_CC  },
-	{ "bcc",        NULL, GMIME_RECIPIENT_TYPE_BCC }
-    };
     unsigned int i;
 
-    config = notmuch_config_open (ctx, NULL, NULL);
-    if (config == NULL)
-	return 1;
-
-    query_string = query_string_from_args (ctx, argc, argv);
-    if (query_string == NULL) {
-	fprintf (stderr, "Out of memory\n");
-	return 1;
-    }
-
-    if (*query_string == '\0') {
-	fprintf (stderr, "Error: notmuch reply requires at least one search term.\n");
-	return 1;
-    }
-
-    notmuch = notmuch_database_open (notmuch_config_get_database_path (config),
-				     NOTMUCH_DATABASE_MODE_READ_ONLY);
-    if (notmuch == NULL)
-	return 1;
-
-    query = notmuch_query_create (notmuch, query_string);
-    if (query == NULL) {
-	fprintf (stderr, "Out of memory\n");
-	return 1;
-    }
-
     for (messages = notmuch_query_search_messages (query);
 	 notmuch_messages_has_more (messages);
 	 notmuch_messages_advance (messages))
@@ -310,6 +280,71 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 
 	notmuch_message_destroy (message);
     }
+    return 0;
+}
+
+int
+notmuch_reply_command (void *ctx, int argc, char *argv[])
+{
+    notmuch_config_t *config;
+    notmuch_database_t *notmuch;
+    notmuch_query_t *query;
+    char *opt, *query_string;
+    int i, ret = 0;
+    int (*reply_format_func)(void *ctx, notmuch_config_t *config, notmuch_query_t *query);
+
+    reply_format_func = notmuch_reply_format_default;
+
+    for (i = 0; i < argc && argv[i][0] == '-'; i++) {
+	if (strcmp (argv[i], "--") == 0) {
+	    i++;
+	    break;
+	}
+        if (STRNCMP_LITERAL (argv[i], "--format=") == 0) {
+	    opt = argv[i] + sizeof ("--format=") - 1;
+	    if (strcmp (opt, "default") == 0) {
+		reply_format_func = notmuch_reply_format_default;
+	    } else {
+		fprintf (stderr, "Invalid value for --format: %s\n", opt);
+		return 1;
+	    }
+	} else {
+	    fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
+	    return 1;
+	}
+    }
+
+    argc -= i;
+    argv += i;
+
+    config = notmuch_config_open (ctx, NULL, NULL);
+    if (config == NULL)
+	return 1;
+
+    query_string = query_string_from_args (ctx, argc, argv);
+    if (query_string == NULL) {
+	fprintf (stderr, "Out of memory\n");
+	return 1;
+    }
+
+    if (*query_string == '\0') {
+	fprintf (stderr, "Error: notmuch reply requires at least one search term.\n");
+	return 1;
+    }
+
+    notmuch = notmuch_database_open (notmuch_config_get_database_path (config),
+				     NOTMUCH_DATABASE_MODE_READ_ONLY);
+    if (notmuch == NULL)
+	return 1;
+
+    query = notmuch_query_create (notmuch, query_string);
+    if (query == NULL) {
+	fprintf (stderr, "Out of memory\n");
+	return 1;
+    }
+
+    if (reply_format_func (ctx, config, query) != 0)
+	return 1;
 
     notmuch_query_destroy (query);
     notmuch_database_close (notmuch);
-- 
1.6.5.3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] notmuch-reply.c: implement notmuch_reply_format_headers_only
  2009-11-25  1:35 ` [PATCH 1/2] notmuch-reply.c: accept the --format=default default option Jed Brown
@ 2009-11-25  1:35   ` Jed Brown
  2009-11-25 18:02   ` [PATCH 1/2] reply --format=headers-only: set In-Reply-To header, with ID *last* in References Jed Brown
  1 sibling, 0 replies; 9+ messages in thread
From: Jed Brown @ 2009-11-25  1:35 UTC (permalink / raw)
  To: notmuch

This command only generates References, To, and Cc headers.
The purpose is primarily for use in

  git send-email --notmuch id:<MESSAGE-ID>

to get proper threading and address the relevant parties.  Hooks for
other SCMs may come later.

Signed-off-by: Jed Brown <jed@59A2.org>
---
 notmuch-reply.c |   70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 17eb38d..e85568c 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -283,6 +283,74 @@ notmuch_reply_format_default(void *ctx, notmuch_config_t *config, notmuch_query_
     return 0;
 }
 
+/* This format is currently tuned for a git send-email --notmuch hook */
+static int
+notmuch_reply_format_headers_only(void *ctx, notmuch_config_t *config, notmuch_query_t *query)
+{
+    GMimeMessage *reply;
+    notmuch_messages_t *messages;
+    notmuch_message_t *message;
+    const char *recipients, *in_reply_to, *orig_references, *references;
+    char *reply_headers;
+    unsigned int i;
+
+    for (messages = notmuch_query_search_messages (query);
+	 notmuch_messages_has_more (messages);
+	 notmuch_messages_advance (messages))
+    {
+	message = notmuch_messages_get (messages);
+
+	/* The 0 means we do not want headers in a "pretty" order. */
+	reply = g_mime_message_new (0);
+	if (reply == NULL) {
+	    fprintf (stderr, "Out of memory\n");
+	    return 1;
+	}
+
+	in_reply_to = talloc_asprintf (ctx, "<%s>",
+			     notmuch_message_get_message_id (message));
+
+	orig_references = notmuch_message_get_header (message, "references");
+
+	/* We print References first because git format-patch treats it specially.
+	 * Git uses the first entry of References to create In-Reply-To.
+	 */
+	references = talloc_asprintf (ctx, "%s%s%s",
+				      in_reply_to,
+				      orig_references ? orig_references : "",
+				      orig_references ? " " : "");
+	g_mime_object_set_header (GMIME_OBJECT (reply),
+				  "References", references);
+
+	for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) {
+	    const char *addr;
+
+	    recipients = notmuch_message_get_header (message,
+						     reply_to_map[i].header);
+	    if ((recipients == NULL || recipients[0] == '\0') && reply_to_map[i].fallback)
+		recipients = notmuch_message_get_header (message,
+							 reply_to_map[i].fallback);
+
+	    addr = add_recipients_for_string (reply, config,
+					      reply_to_map[i].recipient_type,
+					      recipients);
+	}
+
+	g_mime_object_set_header (GMIME_OBJECT (reply), "Bcc",
+			   notmuch_config_get_user_primary_email (config));
+
+	reply_headers = g_mime_object_to_string (GMIME_OBJECT (reply));
+	printf ("%s", reply_headers);
+	free (reply_headers);
+
+	g_object_unref (G_OBJECT (reply));
+	reply = NULL;
+
+	notmuch_message_destroy (message);
+    }
+    return 0;
+}
+
 int
 notmuch_reply_command (void *ctx, int argc, char *argv[])
 {
@@ -304,6 +372,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 	    opt = argv[i] + sizeof ("--format=") - 1;
 	    if (strcmp (opt, "default") == 0) {
 		reply_format_func = notmuch_reply_format_default;
+	    } else if (strcmp (opt, "headers-only") == 0) {
+		reply_format_func = notmuch_reply_format_headers_only;
 	    } else {
 		fprintf (stderr, "Invalid value for --format: %s\n", opt);
 		return 1;
-- 
1.6.5.3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 1/2] reply --format=headers-only: set In-Reply-To header, with ID *last* in References
  2009-11-25  1:35 ` [PATCH 1/2] notmuch-reply.c: accept the --format=default default option Jed Brown
  2009-11-25  1:35   ` [PATCH 2/2] notmuch-reply.c: implement notmuch_reply_format_headers_only Jed Brown
@ 2009-11-25 18:02   ` Jed Brown
  2009-11-25 18:02     ` [PATCH 2/2] Recognize reply --format=headers-only-git Jed Brown
  1 sibling, 1 reply; 9+ messages in thread
From: Jed Brown @ 2009-11-25 18:02 UTC (permalink / raw)
  To: notmuch

Apparently this is actually the correct way to do it, it's silly to do
it wrong just to conform to one of git's internal data structures.
---
 notmuch-reply.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index e85568c..9ca1236 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -310,15 +310,19 @@ notmuch_reply_format_headers_only(void *ctx, notmuch_config_t *config, notmuch_q
 	in_reply_to = talloc_asprintf (ctx, "<%s>",
 			     notmuch_message_get_message_id (message));
 
+        g_mime_object_set_header (GMIME_OBJECT (reply),
+				  "In-Reply-To", in_reply_to);
+
+
 	orig_references = notmuch_message_get_header (message, "references");
 
-	/* We print References first because git format-patch treats it specially.
-	 * Git uses the first entry of References to create In-Reply-To.
+	/* We print In-Reply-To followed by References because git format-patch treats them
+         * specially.  Git does not interpret the other headers specially
 	 */
 	references = talloc_asprintf (ctx, "%s%s%s",
-				      in_reply_to,
 				      orig_references ? orig_references : "",
-				      orig_references ? " " : "");
+				      orig_references ? " " : "",
+				      in_reply_to);
 	g_mime_object_set_header (GMIME_OBJECT (reply),
 				  "References", references);
 
-- 
1.6.5.3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] Recognize reply --format=headers-only-git
  2009-11-25 18:02   ` [PATCH 1/2] reply --format=headers-only: set In-Reply-To header, with ID *last* in References Jed Brown
@ 2009-11-25 18:02     ` Jed Brown
  2009-11-28  1:01       ` Carl Worth
  0 siblings, 1 reply; 9+ messages in thread
From: Jed Brown @ 2009-11-25 18:02 UTC (permalink / raw)
  To: notmuch

This currently means the same thing as --format=headers-only, but this
name gives more freedom to change --format=headers-only without breaking
existing versions of git.
---
 notmuch-reply.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/notmuch-reply.c b/notmuch-reply.c
index 9ca1236..2b16dae 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -376,7 +376,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 	    opt = argv[i] + sizeof ("--format=") - 1;
 	    if (strcmp (opt, "default") == 0) {
 		reply_format_func = notmuch_reply_format_default;
-	    } else if (strcmp (opt, "headers-only") == 0) {
+	    } else if (strcmp (opt, "headers-only") == 0 ||
+		       strcmp (opt, "headers-only-git") == 0) {
 		reply_format_func = notmuch_reply_format_headers_only;
 	    } else {
 		fprintf (stderr, "Invalid value for --format: %s\n", opt);
-- 
1.6.5.3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: Notmuch-side support for git send-email --notmuch id:<MESSAGE-ID>
  2009-11-25  1:35 Notmuch-side support for git send-email --notmuch id:<MESSAGE-ID> Jed Brown
  2009-11-25  1:35 ` [PATCH 1/2] notmuch-reply.c: accept the --format=default default option Jed Brown
@ 2009-11-28  1:00 ` Carl Worth
  2009-11-28 17:56   ` [PATCH] Documentation for notmuch reply --format=(default|headers-only) Jed Brown
  1 sibling, 1 reply; 9+ messages in thread
From: Carl Worth @ 2009-11-28  1:00 UTC (permalink / raw)
  To: Jed Brown, notmuch

On Wed, 25 Nov 2009 02:35:12 +0100, Jed Brown <jed@59A2.org> wrote:
> These two patches provide support for features like the one in the
> subject line.  Along with these two patches, I have one for git
> format-patch (which I will submit upstream soon) that uses the output
> from notmuch reply --format=headers-only to build a reply with proper
> referencing, To, and Cc fields.
> 
> Since options for git send-email are passed to git format-patch,
> 
>   git send-email --notmuch id:<ID>
> 
> is a substitute for
> 
>   git send-email --in-reply-to <ID> --to <TO> --cc <CC> --add-header 'References: ...'

Having "notmuch reply --format=headers-only" seems just great. Thanks
for submitting this.

I've pushed it all out except for the last --format=headers-only-git
piece, for which I'll comment on the patch.

Oh, and the documentation for "notmuch reply" needs to be updated, (in
notmuch.1 and notmuch.c). Could you take a whack at that?

Thanks,

-Carl

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] Recognize reply --format=headers-only-git
  2009-11-25 18:02     ` [PATCH 2/2] Recognize reply --format=headers-only-git Jed Brown
@ 2009-11-28  1:01       ` Carl Worth
  0 siblings, 0 replies; 9+ messages in thread
From: Carl Worth @ 2009-11-28  1:01 UTC (permalink / raw)
  To: Jed Brown, notmuch

On Wed, 25 Nov 2009 19:02:19 +0100, Jed Brown <jed@59A2.org> wrote:
> This currently means the same thing as --format=headers-only, but this
> name gives more freedom to change --format=headers-only without breaking
> existing versions of git.

While it may make sense in the future to put something git-specific
here, I'd rather wait on creating the additional option until we
actually have something.

Otherwise, our documentation is more complicated, and callers will feel
the need to call the longer option "just in case", and all for possibly
no reason at all.

-Carl

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH] Documentation for notmuch reply --format=(default|headers-only)
  2009-11-28  1:00 ` Notmuch-side support for git send-email --notmuch id:<MESSAGE-ID> Carl Worth
@ 2009-11-28 17:56   ` Jed Brown
  2009-11-28 20:14     ` Carl Worth
  0 siblings, 1 reply; 9+ messages in thread
From: Jed Brown @ 2009-11-28 17:56 UTC (permalink / raw)
  To: cworth; +Cc: notmuch

Signed-off-by: Jed Brown <jed@59A2.org>
---
 notmuch.1 |   22 +++++++++++++++++++---
 notmuch.c |   16 ++++++++++++++--
 2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/notmuch.1 b/notmuch.1
index 2be77f9..04bd0cf 100644
--- a/notmuch.1
+++ b/notmuch.1
@@ -211,9 +211,9 @@ section below for details of the supported syntax for <search-terms>.
 The
 .B reply
 command is useful for preparing a template for an email reply.
-
-.TP
-.BR reply " <search-term>..."
+.RS 4
+.TP 4
+.BR reply " [options...] <search-term>..."
 
 Constructs a reply template for a set of messages.
 
@@ -236,6 +236,21 @@ each line with '> ' and included in the body.
 
 The resulting message template is output to stdout.
 
+Supported options for
+.B reply
+include
+.RS
+.TP 4
+.BR \-\-format= ( default | headers\-only )
+.RS
+.TP 4
+.BR default
+Includes subject and quoted message body.
+.TP
+.BR headers-only
+Only produces In-Reply-To, References, To, Cc, and Bcc headers.
+.RE
+
 See the
 .B "SEARCH SYNTAX"
 section below for details of the supported syntax for <search-terms>.
@@ -248,6 +263,7 @@ once. For example, when a series of patches are sent in a single
 thread, replying to the entire thread allows for the reply to comment
 on issue found in multiple patches.
 .RE
+.RE
 
 The
 .B tag
diff --git a/notmuch.c b/notmuch.c
index 5b0284c..d9846ce 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -204,7 +204,7 @@ command_t commands[] = {
       "\t\tSee \"notmuch help search-terms\" for details of the search\n"
       "\t\tterms syntax." },
     { "reply", notmuch_reply_command,
-      "<search-terms> [...]",
+      "[options...] <search-terms> [...]",
       "\t\tConstruct a reply template for a set of messages.",
       "\t\tConstructs a new message as a reply to a set of existing\n"
       "\t\tmessages. The Reply-To: header (if any, otherwise From:) is\n"
@@ -213,10 +213,22 @@ command_t commands[] = {
       "\n"
       "\t\tA suitable subject is constructed. The In-Reply-to: and\n"
       "\t\tReferences: headers are set appropriately, and the content\n"
-      "\t\tof the original messages is quoted and included in the body.\n"
+      "\t\tof the original messages is quoted and included in the body\n"
+      "\t\t(unless --format=headers-only is given).\n"
       "\n"
       "\t\tThe resulting message template is output to stdout.\n"
       "\n"
+      "\t\tSupported options for reply include:\n"
+      "\n"
+      "\t\t--format=(default|headers-only)\n"
+      "\n"
+      "\t\t\tdefault:\n"
+      "\t\t\t\tIncludes subject and quoted message body.\n"
+      "\n"
+      "\t\t\theaders-only:\n"
+      "\t\t\t\tOnly produces In-Reply-To, References, To\n"
+      "\t\t\t\tCc, and Bcc headers.\n"
+      "\n"
       "\t\tSee \"notmuch help search-terms\" for details of the search\n"
       "\t\tterms syntax." },
     { "tag", notmuch_tag_command,
-- 
1.6.5.3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH] Documentation for notmuch reply --format=(default|headers-only)
  2009-11-28 17:56   ` [PATCH] Documentation for notmuch reply --format=(default|headers-only) Jed Brown
@ 2009-11-28 20:14     ` Carl Worth
  0 siblings, 0 replies; 9+ messages in thread
From: Carl Worth @ 2009-11-28 20:14 UTC (permalink / raw)
  To: Jed Brown; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 300 bytes --]

On Sat, 28 Nov 2009 18:56:15 +0100, Jed Brown <jed@59A2.org> wrote:
> Signed-off-by: Jed Brown <jed@59A2.org>
> ---
>  notmuch.1 |   22 +++++++++++++++++++---
>  notmuch.c |   16 ++++++++++++++--
>  2 files changed, 33 insertions(+), 5 deletions(-)

Perfect, Jed. Thanks!

This is pushed now.

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2009-11-28 20:14 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-25  1:35 Notmuch-side support for git send-email --notmuch id:<MESSAGE-ID> Jed Brown
2009-11-25  1:35 ` [PATCH 1/2] notmuch-reply.c: accept the --format=default default option Jed Brown
2009-11-25  1:35   ` [PATCH 2/2] notmuch-reply.c: implement notmuch_reply_format_headers_only Jed Brown
2009-11-25 18:02   ` [PATCH 1/2] reply --format=headers-only: set In-Reply-To header, with ID *last* in References Jed Brown
2009-11-25 18:02     ` [PATCH 2/2] Recognize reply --format=headers-only-git Jed Brown
2009-11-28  1:01       ` Carl Worth
2009-11-28  1:00 ` Notmuch-side support for git send-email --notmuch id:<MESSAGE-ID> Carl Worth
2009-11-28 17:56   ` [PATCH] Documentation for notmuch reply --format=(default|headers-only) Jed Brown
2009-11-28 20:14     ` Carl Worth

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).