From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id TgHaCQy4umnu9C4AWB0awg (envelope-from ) for ; Wed, 18 Mar 2026 10:34:52 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=J1l1Uaob; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 1B1AC1E0BC; Wed, 18 Mar 2026 10:34:52 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 23B6F1E08C for ; Wed, 18 Mar 2026 10:34:51 -0400 (EDT) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id C2A264B196B6 for ; Wed, 18 Mar 2026 14:34:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C2A264B196B6 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=J1l1Uaob Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 554544BA2E15 for ; Wed, 18 Mar 2026 14:34:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 554544BA2E15 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 554544BA2E15 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773844461; cv=none; b=q60lO1vNKgCYehFmqQ2aDH4aRoa9IN1fKP4TGAiFelsUQ18RRoEiyC4araW5prSKC+60rWUg+KiZTkZT4vmYmjbfnW08tFCPy6S5kKOM2+oJDdaMCI5QoH3uEpr7Ck12mocqqEM20SM4qRh6XiWQGQIChTPLBu/gx3Kvb829a64= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773844461; c=relaxed/simple; bh=gRaZHzwgCJ7tNf4cSNVgNebC3lXDP3mTu3i1A4fa7UE=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=KIJfegEDbHo+kdPZr5N/qzeYFVs3JpENUPBPVf0rSawQpsDwtIScqlgX6kyIj5WMdks+5NdM5g4fT9tWuz0rh9zKXmWTR3r8+4oLQtB6HrVUlTniKF0pt4m+IzW6mnSMJtLJnhjKzspP1i5pYq5EuCKpavUdu8G/Z32HjG9Ys2U= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 554544BA2E15 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1773844460; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=hGMiAhBOpvbSAULQc4KEmNaiEmGD59XZWFdTEYVzVis=; b=J1l1UaobOMdlYO8K1iQyjMA9C2eudPI/oBoui0WbfeFptN0APQinexRUQjTnQm0y7ouyqK WDHmoQO2YsPcuJ45YQqNXpOYrj6mtznxIUAsTcfd9ucMTNVBwlOpJ3KrETQksOttZN4JY3 /DbXVLJGnzOsEs7gKt1gjK4w25iXTnA= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-114-UYz0ngCqOaiq6oavahcXhQ-1; Wed, 18 Mar 2026 10:34:19 -0400 X-MC-Unique: UYz0ngCqOaiq6oavahcXhQ-1 X-Mimecast-MFC-AGG-ID: UYz0ngCqOaiq6oavahcXhQ_1773844458 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-439ca4b3d0bso663688f8f.3 for ; Wed, 18 Mar 2026 07:34:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773844458; x=1774449258; h=mime-version:message-id:date:references:in-reply-to:subject:to:from :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=hGMiAhBOpvbSAULQc4KEmNaiEmGD59XZWFdTEYVzVis=; b=lvuH/wr0Q3TJ8c0ZolqwbRaJbkRFUUZR/9NYMZ+fh4Qw/Xn1Rg/o5ykRt/o+EQmjgt sbT3nd/+kIR+rqlMtWsUYG2AfBwbHnsTKiSnkeq7DPSzM7Gede233xoKNWEWlMLr9+CD jesX9wyzqeWtWG813OxnJD5szred73PV1rkIZf6URMc4ArO6JkC09/ag4AVrzLTtnAj3 GoVmwN6IFC/6Qfg8grJvfZvTsUMlIq/0fVrgbvS19eHtLR0bn+Simb/axzDca3sfFX+R sptSCi8+COtxHeML2UnYDiihCEaz/6KMh6x+P+/AcONVL8DTQvwLnZyApwccIFmzyX1L HQBg== X-Forwarded-Encrypted: i=1; AJvYcCVTVH7WihXzsQPZ7xxy6f3lCuuMIYWw+dW5XnxtFTOtvfFFOrNkJarUpdRXKpSpHmzYOgOUp1Wztew5Uw==@sourceware.org X-Gm-Message-State: AOJu0Yxn1ohV3XeqyooR+GprmL/E8Y3QuKg7Qvh+X173BItyeQcqm+F8 OC7o6sMNHazolZyqeZp/luLSVhO8KNYQAod4LlesMs1KR3AdLEjiP/QxuVnLGVepbPUWnwAULVr KSlpdA8j0y8BwkH/mVv3pB3gicuUz/2fG5OxpN04SgwMqF64mSEQRMXT+dMLUXC8= X-Gm-Gg: ATEYQzwIfafRdyPXRQ7aRD7JqxTKXrEtZdm8XvqFim9YveIpJ7LGlm19AZuEFl7fzAJ OS0APFeYRlNZOPkH1/IHBZ9nZ623i/EcFeoEhGynbXn57aeyINjef78YjViALWyBbqT91KmbbVK BqTcoxOshBV+QceV7kD4pHteSinNQI5nZlRjSMAcdtVIjKerRsV5fh0B1Y2+pF7XemnYVK8Kx+T cva7mFHqOtqPPCi0uKeZt8XrjPF3N8JAbU7CfgzhiSW2nqRFFvyYfJUqkYpHE39976q0/UJ3XGF Pss7JEX3NNA/3VUQBr4zB8Ff65+8ds2/NCAKPjymF5DBLWinIakxyb+Af5LDXrvHBLINf2g5kaj wC3gB9ThGNE8wkJfo X-Received: by 2002:a05:6000:2502:b0:439:b652:af26 with SMTP id ffacd0b85a97d-43b527ccd14mr6156183f8f.55.1773844457869; Wed, 18 Mar 2026 07:34:17 -0700 (PDT) X-Received: by 2002:a05:6000:2502:b0:439:b652:af26 with SMTP id ffacd0b85a97d-43b527ccd14mr6156125f8f.55.1773844457200; Wed, 18 Mar 2026 07:34:17 -0700 (PDT) Received: from localhost ([31.111.84.232]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b51849636sm8471931f8f.8.2026.03.18.07.34.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Mar 2026 07:34:16 -0700 (PDT) From: Andrew Burgess To: Guinevere Larsen , gdb-patches@sourceware.org, Pedro Alves Subject: Re: [PATCHv2] gdb: notify of inferior switch when needed from 'thread' command In-Reply-To: <93ef9c09-1269-43ae-aa3f-28aff7aadaa1@redhat.com> References: <106ee09a80eac0dcc72d134dbf02f567de7163ce.1769435821.git.aburgess@redhat.com> <93ef9c09-1269-43ae-aa3f-28aff7aadaa1@redhat.com> Date: Wed, 18 Mar 2026 14:34:15 +0000 Message-ID: <87y0jp5hqw.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: OS_yuj5ckygUXvgGWLQtylL_OxXhh3ybsIuaWqGsJxo_1773844458 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Guinevere Larsen writes: > On 1/26/26 10:58 AM, Andrew Burgess wrote: >> In v2: >> >> - Rebased and retested. >> >> - Reworked commit message to try and address Pedro's concerns. >> >> Thanks, >> Andrew >> >> --- > > Hi Andrew! > > I've taken a look at this patch and it looks pretty good, and I think it > is a good change. > > I know you're waiting for Pedro's feedback, but hopefully this message > acts as a ping for him as well as a review for you > > Reviewed-By: Guinevere Larsen Thanks Guinevere, I appreciate the feedback. I've been wondering what to do about this patch. Usually I would have self-approved it and applied it by now, but I'm very reluctant to do that given Pedro's previous comments. I've added Pedro to the 'To:' list, I should have done that with the original v2 patch. I'll give this a little longer yet, my hope is to land this for GDB 18. Thanks, Andrew > >> >> While working on the commit: >> >> commit 9959019545d8d6d71d927f20f088efba944b1e9c >> Date: Sun Sep 28 16:16:53 2025 +0100 >> >> gdb: fix for 'set suppress-cli-notifications on' missed case >> >> I spotted this message in the gdb.mi/user-selected-context-sync.exp >> test script: >> >> # Idea for the future: selecting a thread in a different inferior. For now, >> # GDB doesn't show an inferior switch, but if it did, it would be a nice >> # place to test it. >> >> What this message is talking about is this behaviour: >> >> (gdb) info threads >> Id Target Id Frame >> 1.1 Thread 0xf7dbc700 (LWP 818430) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6 >> 1.2 Thread 0xf7dbbb40 (LWP 818433) "thr" 0xf7fd0579 in __kernel_vsyscall () >> 1.3 Thread 0xf73ffb40 (LWP 818434) "thr" breakpt () at thr.c:19 >> 2.1 Thread 0xf7dbc700 (LWP 818456) "thr" 0xf7eb2888 in clone () from /lib/libc.so.6 >> 2.2 Thread 0xf7dbbb40 (LWP 818457) "thr" breakpt () at thr.c:19 >> * 2.3 Thread 0xf73ffb40 (LWP 818458) "thr" breakpt () at thr.c:19 >> (gdb) inferior 1 >> [Switching to inferior 1 [process 818430] (/home/andrew/tmp/thr)] >> [Switching to thread 1.1 (Thread 0xf7dbc700 (LWP 818430))] >> #0 0xf7eb2888 in clone () from /lib/libc.so.6 >> (gdb) thread 2.2 >> [Switching to thread 2.2 (Thread 0xf7dbbb40 (LWP 818457))] >> #0 breakpt () at thr.c:19 >> 19 while (stop) >> (gdb) >> >> Notice that when we switch from thread 2.3 to 1.1 using the 'inferior >> 1' command, GDB tells us that the inferior has changed, and that the >> thread has changed (and also that the frame has changed). >> >> But, when we switch from 1.1 to 2.2 using the 'thread 2.2' command, we >> are only told about the thread change. >> >> The 'Switching to inferior ...' line includes some useful information, >> the process PID and the executable name, and I think it is a shame >> that these are not presented when using the 'thread' command to switch >> inferior. >> >> So, this commit addresses this issue. >> >> A question that came up during review, and which I'm clarifying here: >> this change only effects the output of GDB when the thread command is >> also used to switch inferiors. I am (in effect) arguing that the >> command 'thread 2.2' should be treated as a shorthand for 'inferior 2; >> thread 2', and should display all of the associated output. If the >> user is only switching threads within a single inferior then it is not >> necessary to re-display the inferior information. >> >> I acknowledge that this does mean the output of the 'thread' command >> will now be different depending on whether the user changes inferior >> or not. However, I think this is better than the alternative, having >> the 'thread' command always re-print the inferior information. I >> think this would introduce excess noise that is not useful. >> >> There are changes in basically two areas. The easy part is in >> thread_command (thread.c). Here we spot when the inferior has changed >> as a result of the 'thread' command, and included >> USER_SELECTED_INFERIOR in the set of state passed to the >> notify_user_selected_context_changed function. >> >> The change in mi/mi-main.c is a little more involved. In the >> mi_cmd_execute function we use an instance of user_selected_context to >> spot if any inferior state (frame, thread, or inferior) changes after >> an MI command, this is then used to decide if there should be a call >> to notify_user_selected_context_changed. >> >> Currently, in mi_cmd_execute, notify_user_selected_context_changed is >> always passed 'USER_SELECTED_THREAD | USER_SELECTED_FRAME'. This >> makes sense, the MI doesn't allow "switching inferiors" as a command, >> instead, an MI frontend must switch threads, and the inferior is >> switched as a consequence. But this does mean that if a user has a >> CLI and MI interpreter running, and the MI switches threads, the CLI >> will only receive the thread switch style notifications, that is, >> there will be no "Switching to inferior ..." line. >> >> What I've done is rename user_selected_context::has_changed to >> user_selected_context::what_changed, this function is now responsible >> for returning the set of USER_SELECTED_* flags that indicate what >> changed. >> >> If anything has changed then we always return USER_SELECTED_THREAD | >> USER_SELECTED_FRAME as a minimum. This retains the existing >> behaviour, but is possibly more aggressive that we need to be; the >> -stack-select-frame command can only change the frame, so maybe in >> this case we should only return USER_SELECTED_FRAME? I've left that >> for the future though. >> >> However, the important change is that in ::what_changed, I now spot >> when the inferior has changed and include USER_SELECTED_INFERIOR in >> the set of flags that are returned. >> >> In mi_cmd_execute we now call the new what_changed function, and use >> the set of flags returned when calling >> notify_user_selected_context_changed. This means that the CLI will >> now receive inferior changed notifications when appropriate. >> >> The gdb.mi/user-selected-context-sync.exp script has been updated, >> replacing the comment I quoted above with an actual test that the >> inferior change is announced correctly. >> --- >> gdb/mi/mi-main.c | 44 ++++++++++++--- >> .../gdb.mi/user-selected-context-sync.exp | 56 ++++++++++++++++--- >> gdb/thread.c | 13 ++++- >> 3 files changed, 93 insertions(+), 20 deletions(-) >> >> diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c >> index 77e56bc9fc8..a18209366ff 100644 >> --- a/gdb/mi/mi-main.c >> +++ b/gdb/mi/mi-main.c >> @@ -538,6 +538,11 @@ mi_cmd_thread_select (const char *command, const char *const *argv, int argc) >> >> thread_select (argv[0], thr); >> >> + /* We don't call print_selected_inferior here as this never prints >> + anything when the output is MI like (as it is now). MI consumers are >> + expected to derive the inferior change from the global thread-id >> + included in the print_selected_thread_frame output. */ >> + >> print_selected_thread_frame (current_uiout, >> USER_SELECTED_THREAD | USER_SELECTED_FRAME); >> } >> @@ -1968,12 +1973,30 @@ struct user_selected_context >> >> /* Return true if the user selected context has changed since this object >> was created. */ >> - bool has_changed () const >> + user_selected_what what_changed () const >> { >> + /* If anything changed then we report both the thread and frame at a >> + minimum. We optionally add the inferior if we know that it >> + changed. >> + >> + This means that for pure frame changes, e.g. -stack-select-frame, we >> + still report both a thread and a frame, which isn't ideal, but >> + there's also the cases where -thread-select is used to re-select the >> + current thread, in this case we'd still like to see the thread >> + reported, at least, that's what we have historically done. */ >> + user_selected_what state >> + = USER_SELECTED_THREAD | USER_SELECTED_FRAME; >> + >> /* Did the selected thread change? */ >> if (m_previous_ptid != null_ptid && inferior_ptid != null_ptid >> && m_previous_ptid != inferior_ptid) >> - return true; >> + { >> + /* Did the inferior change too? */ >> + if (m_previous_ptid.pid () != inferior_ptid.pid ()) >> + state |= USER_SELECTED_INFERIOR; >> + >> + return state; >> + } >> >> /* Grab details of the currently selected frame, for comparison. */ >> frame_id current_frame_id; >> @@ -1982,7 +2005,7 @@ struct user_selected_context >> >> /* Did the selected frame level change? */ >> if (current_frame_level != m_previous_frame_level) >> - return true; >> + return state; >> >> /* Did the selected frame id change? If the innermost frame is >> selected then the level will be -1, and the frame-id will be >> @@ -1991,10 +2014,10 @@ struct user_selected_context >> other than the innermost frame selected. */ >> if (current_frame_level != -1 >> && current_frame_id != m_previous_frame_id) >> - return true; >> + return state; >> >> /* Nothing changed! */ >> - return false; >> + return 0; >> } >> private: >> /* The previously selected thread. This might be null_ptid if there was >> @@ -2098,10 +2121,13 @@ mi_cmd_execute (struct mi_parse *parse) >> >> parse->cmd->invoke (parse); >> >> - if (!parse->cmd->preserve_user_selected_context () >> - && current_user_selected_context.has_changed ()) >> - interps_notify_user_selected_context_changed >> - (USER_SELECTED_THREAD | USER_SELECTED_FRAME); >> + if (!parse->cmd->preserve_user_selected_context ()) >> + { >> + user_selected_what what >> + = current_user_selected_context.what_changed (); >> + if (what != 0) >> + notify_user_selected_context_changed (what); >> + } >> } >> >> /* See mi-main.h. */ >> diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp >> index 3434ffa2a46..4f02b950f6e 100644 >> --- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp >> +++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp >> @@ -698,9 +698,21 @@ proc_with_prefix test_cli_thread { mode } { >> } >> } >> >> - # Idea for the future: selecting a thread in a different inferior. For now, >> - # GDB doesn't show an inferior switch, but if it did, it would be a nice >> - # place to test it. >> + with_test_prefix "thread 2.2" { >> + # Select a thread in a different inferior. This should trigger an >> + # 'inferior changed' and 'thread changed' notification on the CLI, >> + # and a single MI async notification. >> + set mi_re [make_mi_re $mode 5 0 event] >> + set cli_re [make_cli_re $mode 2 2.2 0] >> + >> + with_spawn_id $gdb_main_spawn_id { >> + gdb_test "thread 2.2" $cli_re "select thread" >> + } >> + >> + with_spawn_id $mi_spawn_id { >> + match_re_or_ensure_no_output $mi_re "select thread, event on MI" >> + } >> + } >> } >> >> # Test frame selection from CLI. >> @@ -995,9 +1007,22 @@ proc_with_prefix test_mi_thread_select { mode } { >> } >> } >> >> - # Idea for the future: selecting a thread in a different inferior. For now, >> - # GDB doesn't show an inferior switch, but if it did, it would be a nice >> - # place to test it. >> + with_test_prefix "thread 2.2" { >> + # Select a thread in a different inferior. This should trigger an >> + # 'inferior changed' and 'thread changed' notification on the CLI, >> + # and a single MI async notification. >> + set mi_re [make_mi_re $mode 5 0 response] >> + set cli_re [make_cli_re $mode 2 2.2 0] >> + >> + with_spawn_id $mi_spawn_id { >> + mi_gdb_test "-thread-select 5" $mi_re "-thread-select" >> + } >> + >> + with_spawn_id $gdb_main_spawn_id { >> + match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on CLI" >> + } >> + >> + } >> } >> >> proc_with_prefix test_mi_stack_select_frame { mode } { >> @@ -1290,9 +1315,22 @@ proc_with_prefix test_cli_in_mi_thread { mode cli_in_mi_mode } { >> } >> } >> >> - # Idea for the future: selecting a thread in a different inferior. For now, >> - # GDB doesn't show an inferior switch, but if it did, it would be a nice >> - # place to test it. >> + with_test_prefix "thread 2.2" { >> + # Select a thread in a different inferior. This should trigger an >> + # 'inferior changed' and 'thread changed' notification on the CLI, >> + # and a single MI async notification. >> + set command [make_cli_in_mi_command $cli_in_mi_mode "thread 2.2"] >> + set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 2 2.2 5 0] >> + set cli_re [make_cli_re $mode 2 2.2 0] >> + >> + with_spawn_id $mi_spawn_id { >> + mi_gdb_test $command $mi_re "select thread" >> + } >> + >> + with_spawn_id $gdb_main_spawn_id { >> + match_re_or_ensure_no_output "$cli_re\r\n" "select thread, event on CLI" >> + } >> + } >> } >> >> # Test selecting the frame using a CLI command in the MI channel. >> diff --git a/gdb/thread.c b/gdb/thread.c >> index 0788bea235a..9ca1a8d973a 100644 >> --- a/gdb/thread.c >> +++ b/gdb/thread.c >> @@ -1983,10 +1983,19 @@ thread_command (const char *tidstr, int from_tty) >> } >> else >> { >> + inferior *previous_inferior = current_inferior (); >> + >> thread_select (tidstr, parse_thread_id (tidstr, NULL)); >> >> - notify_user_selected_context_changed >> - (USER_SELECTED_THREAD | USER_SELECTED_FRAME); >> + user_selected_what selection = (USER_SELECTED_THREAD >> + | USER_SELECTED_FRAME); >> + >> + /* If the inferior changed as a consequence of the thread change, >> + then let the user know. */ >> + if (previous_inferior != current_inferior ()) >> + selection |= USER_SELECTED_INFERIOR; >> + >> + notify_user_selected_context_changed (selection); >> } >> } >> >> >> base-commit: 449035c35f2169e0c690d83f28306275ab7f7463 > > > -- > Cheers, > Guinevere Larsen > It/she