Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

utils/ruby.sh: search PATH for Ruby on Linux. update.sh: keep HOMEBREW_RUBY_PATH set. #7545

Merged
merged 14 commits into from May 27, 2020

Conversation

maxim-belkin
Copy link
Member

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes? Here's an example.
  • Have you successfully run brew style with your changes locally?
  • Have you successfully run brew tests with your changes locally?

Unsetting HOMEBREW_RUBY_PATH on platforms where system Ruby is too old breaks Homebrew. I see that it was added on purpose (bcca2a7) but I think the logic behind unsetting it has to be more complex.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see that it was added on purpose (bcca2a7) but I think the logic behind unsetting it has to be more complex.

I agree with this but the logic should be made more complex rather than just removed.

@maxim-belkin
Copy link
Member Author

Since bcca2a7 was authored by you, do you remember under what conditions HOMEBREW_RUBY_PATH causes issues for update-report ?

@maxim-belkin
Copy link
Member Author

I think I got it: update-report is a Ruby script and you want to use portable Ruby once it is installed to call it rather than the one pointed to by HOMEBREW_RUBY_PATH.

@maxim-belkin maxim-belkin changed the title cmd/update.sh: keep HOMEBREW_RUBY_PATH set when updating cmd/update.sh: keep HOMEBREW_RUBY_PATH set when necessary May 12, 2020
@maxim-belkin
Copy link
Member Author

maxim-belkin commented May 12, 2020

I implemented the following logic:

  1. if HOMEBREW_FORCE_VENDOR_RUBY is set and vendored Ruby is installed -- point HOMEBREW_RUBY_PATH to that executable.
  2. Otherwise, if HOMEBREW_DEVELOPER is not set -- unset HOMEBREW_RUBY_PATH.

This will keep HOMEBREW_RUBY_PATH set for developers that didn't set HOMEBREW_FORCE_VENDOR_RUBY.

Is that close to what you were thinking?

@MikeMcQuaid
Copy link
Member

Since bcca2a7 was authored by you, do you remember under what conditions HOMEBREW_RUBY_PATH causes issues for update-report ?

I think I got it: update-report is a Ruby script and you want to use portable Ruby once it is installed to call it rather than the one pointed to by HOMEBREW_RUBY_PATH.

The issue was/is:

  • if brew update updates the version of Ruby that's required it may need to install a new portable Ruby
  • if installing a new portable Ruby it cannot differentiate between an old HOMEBREW_RUBY_PATH set by utils/ruby.sh or set by a user manually so it unsets it
  • when brew update-report is run it runs utils/ruby.sh again which may install a new Ruby

HOMEBREW_RUBY_PATH is already unset unconditionally unless HOMEBREW_DEVELOPER is set. It's also an undocumented variable. It should never need to be set my end-users. I'd probably favour just unsetting it unconditionally and not allowing it to be set.

Unsetting HOMEBREW_RUBY_PATH on platforms where system Ruby is too old breaks Homebrew.

This should never be the case. utils/ruby.sh should be finding the relevant Ruby from the PATH or installing portable Ruby or erroring out. Can you describe the exact situation you're seeing here and why/when/how it's a problem?

if [[ -n $HOMEBREW_FORCE_VENDOR_RUBY &&
-x $HOMEBREW_LIBRARY/Homebrew/vendor/portable-ruby/current/bin/ruby ]]
then
export HOMEBREW_RUBY_PATH="$HOMEBREW_LIBRARY/Homebrew/vendor/portable-ruby/current/bin/ruby"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already done by utils/ruby.sh when brew update-report is called.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should never be the case. utils/ruby.sh should be finding the relevant Ruby from the PATH

echo $PATH right next to HOMEBREW_RUBY_PATH="$(type -P ruby)" in utils/ruby.sh -- shows that PATH is /usr/bin:/bin:/usr/sbin:/sbin so it finds system Ruby only.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ruby.sh is being run again so I don't see a reason to duplicate the logic here. It could do something with HOMEBREW_PATH if needed. @sjackman also had thoughts about this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ruby.sh is being run again

Exactly. And in case of update command, HOMEBREW_RUBY_PATH is unset in two places: here (unconditionally for everyone) and then for non-developers in ruby.sh. Because of the unset here, brew update is the only command that fails on old systems where Ruby has to be bootstrapped and Homebrew pointed to it with HOMEBREW_RUBY_PATH...
Anyway, I'll move logic to ruby.sh

@sjackman
Copy link
Member

@rmNULL is working on a patch where on Linux before failing because it cannot find ruby it searches your personal PATH, which is cached in HOMEBREW_PATH, for Ruby 3.6.

@maxim-belkin
Copy link
Member Author

it searches your personal PATH

I've done exactly that, see the diff.

HOMEBREW_RUBY_PATH=$(PATH="$HOMEBREW_PATH" type -P ruby)

@sjackman
Copy link
Member

it searches your personal PATH

I've done exactly that, see the diff.

HOMEBREW_RUBY_PATH=$(PATH="$HOMEBREW_PATH" type -P ruby)

@rmNULL Could you please test this PR?

@rmNULL
Copy link
Contributor

rmNULL commented May 15, 2020

it searches your personal PATH

I've done exactly that, see the diff.

HOMEBREW_RUBY_PATH=$(PATH="$HOMEBREW_PATH" type -P ruby)

@rmNULL Could you please test this PR?

gladly.

Library/Homebrew/utils/ruby.sh Outdated Show resolved Hide resolved
old_ruby_path="$HOMEBREW_RUBY_PATH"
old_ruby_usable=$(test-ruby "$HOMEBREW_RUBY_PATH")
fi

if [[ -z "$HOMEBREW_DEVELOPER" ]]
then
unset HOMEBREW_RUBY_PATH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about just unsetting this unconditionally? It would allow simplifying the logic above and below

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, It should be OK to do it now.

Library/Homebrew/utils/ruby.sh Outdated Show resolved Hide resolved
if [[ $old_ruby_usable != true ]]
then
odie <<-EOS
Failed to find usable Ruby $required_ruby_version!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to move this new logic below so the messaging can be shared rather than repeated.

Co-authored-by: Mike McQuaid <mike@mikemcquaid.com>
@rmNULL
Copy link
Contributor

rmNULL commented May 15, 2020

Hi @maxim-belkin ,
did u by chance overwrite the code to download vendored ruby ?
it doesn't attempt a download when it fails to find suitable ruby.

can u please verify this?

I'm on x86_64

@maxim-belkin
Copy link
Member Author

Thanks, @rmNULL -- good catch. Should be fixed in f7e0705

@rmNULL
Copy link
Contributor

rmNULL commented May 15, 2020

Thanks, @rmNULL -- good catch. Should be fixed in f7e0705

looks swell, not sure why the CI tests are failing.

@maxim-belkin
Copy link
Member Author

looks swell, not sure why the CI tests are failing.

CI tests are overrated :trollface:

Thanks, @rmNULL!

@sjackman
Copy link
Member

Failures:

  1) Cask::Cmd::Uninstall can uninstall Casks when the uninstall script is missing, but only when using `--force`
     Failure/Error: Cask::Installer.new(cask).install

     Cask::CaskError:
       It seems the App source '/tmp/homebrew-tests-20200515-3987-10pjmxm/prefix/Caskroom/with-uninstall-script-app/1.2.3/MyFancyApp/MyFancyApp.app' is not there.
     # ./cask/artifact/moved.rb:41:in `move'

https://github.com/Homebrew/brew/pull/7545/checks?check_run_id=679406315#step:12:44
Hopefully that's a transient failure.

@@ -45,15 +56,29 @@ EOS
then
HOMEBREW_RUBY_PATH="/System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/ruby"
else
HOMEBREW_RUBY_PATH="$(type -P ruby)"
HOMEBREW_RUBY_PATH=$(type -P ruby)
if [[ $(test-ruby $HOMEBREW_RUBY_PATH) != "true" ]]
Copy link
Contributor

@rmNULL rmNULL May 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maxim-belkin L#60,
the test-ruby fn considers $1.
i suspect this will be problematic.
can i know the trick that handles spaced ruby path here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right -- here quotes are necessary. Will fix! Thanks again!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 083f56f.
I was considering using "$@" but then decided to proceed with $1. Thanks for catching it.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactoring here looking good. One more tweak and, given @sjackman is happy, I'm 👍

HOMEBREW_RUBY_PATH=$(PATH="$HOMEBREW_PATH" type -P ruby)
if [[ $(test-ruby "$HOMEBREW_RUBY_PATH") != "true" ]]
then
if [[ $old_ruby_usable != true ]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to avoid quite so much nesting here and instead use an intermediate variable(s) and multiple ifs at the same level?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted nested ifs to a single if/elif/else conditional block in b4267d8.
Had to add a line to test-ruby that checks that tested file exists and is executable.

Copy link
Member

@sjackman sjackman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Maxim!

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry! One last question about old_ruby_path (would love it removed it possible?) and then this is 👍. Great work here @maxim-belkin

then
unset HOMEBREW_RUBY_PATH
fi
[[ -n $HOMEBREW_RUBY_PATH ]] && old_ruby_path=$HOMEBREW_RUBY_PATH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm probably missing something but: why keep this around at all if we're checking PATH and HOMEBREW_PATH anyway?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part handles the cases when user sets HOMEBREW_RUBY_PATH directly. Ability to set HOMEBREW_RUBY_PATH directly instead of modifying PATH is congruent with how Homebrew allows to set HOMEBREW_CURL_PATH and HOMEBREW_GIT_PATH.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Homebrew allows to set HOMEBREW_CURL_PATH and HOMEBREW_GIT_PATH.

We don't allow that (intentionally at least) and don't document them as supported. HOMEBREW_FORCE_BREWED_CURL and HOMEBREW_FORCE_BREWED_GIT are the entry points for that. What's the use-case for not wanting to use the ruby in your HOMEBREW_PATH or PATH or the vendored Ruby.

Copy link
Contributor

@rmNULL rmNULL May 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this applicable in Mac(in my limited view) but in linux
i have a ruby 2.6 installed just to make homebrew work, the ruby version provided by the package manager is 2.7.

I wish to have ruby 2.7 earlier in PATH. As i don't want which to use ruby installed just to maintain homebrew.

Now this is not a strict requirement, i can chuck away the homebrew ruby somewhere behind in PATH.
but this implementation (type -P ruby) finds the first executable ruby, and it will fail and ask me to install ruby 2.6(or try to download) even though a ruby 2.6 is present.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I guess ideally we'd actually search through the HOMEBREW_PATH and PATH (which -a?) to find a ruby that passes our test and only give up if we don't find any?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't agree. brew update has code specifically to install curl and git if needed before doing anything else. If that doesn't work: let's fix it rather than relying on hacking undocumented functionality to make it work.

If the system curl is too old, and the user has a newer version of curl say in their Home directory, HOMEBREW_CURL_PATH is currently how you point Homebrew to that newer version of curl. Homebrew can't download the bottles or source code of curl without a recent version of curl, so HOMEBREW_FORCE_BREWED_CURL is not helpful in this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HOMEBREW_CURL_PATH are is the intentionally developer-exposed environment variable, and HOMEBREW_CURL is the not developer-exposed internal enivronment variable. HOMEBREW_CURL_PATH is active only when HOMEBREW_DEVELOPER is active. See

if [[ -n "$HOMEBREW_FORCE_BREWED_CURL" &&
-x "$HOMEBREW_PREFIX/opt/curl/bin/curl" ]] &&
"$HOMEBREW_PREFIX/opt/curl/bin/curl" --version >/dev/null
then
HOMEBREW_CURL="$HOMEBREW_PREFIX/opt/curl/bin/curl"
elif [[ -n "$HOMEBREW_DEVELOPER" && -x "$HOMEBREW_CURL_PATH" ]]
then
HOMEBREW_CURL="$HOMEBREW_CURL_PATH"
else
HOMEBREW_CURL="curl"
fi

Copy link
Contributor

@rmNULL rmNULL May 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to say that searching through the clean and user PATHs is likely to impact performance. That old_ruby_path was playing a role of cache, I guess.

I ran few tests,

master branch for reference

master-branch

ruby 2.6 is first in which -a ruby

first-in-path

ruby 2.6 is last in which -a ruby

last-in-path

ruby 2.6 set using HOMEBREW_RUBY_PATH(tested on previous commit)

hb-rb-path

once the 2.6 executable is found, may be we cache it somewhere. that should give a little speed bump in the next runs.
Searching through PATH for every brew call don't seem such a nice idea imo.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so HOMEBREW_FORCE_BREWED_CURL is not helpful in this case.

I thought curl had an HTTP mirror but I forgot it no longer does as I did not know this was required for Linux: Homebrew/homebrew-core@2f5aa14. There was also an audit to ensure that curl always had an HTTP mirror.

I'd suggest that if we want to be more accessible to older Linux versions we go down that route rather than requiring the user to manually find and download a suitable curl, set HOMEBREW_DEVELOPER and use an undocumented and unsupported environment variable.

Alternatively or additionally, we could take the same approach as here with curl and git where we look through all of those in the PATH.

once the 2.6 executable is found, may be we cache it somewhere.

This seems like a nice idea. Would be cool to have in this PR but I don't consider it blocking; this is already a fairly niche case (which we could warn users on?).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

once the 2.6 executable is found, may be we cache it somewhere.

This seems like a nice idea. Would be cool to have in this PR but I don't consider it blocking; this is already a fairly niche case (which we could warn users on?).

I can add it in this PR.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One suggested tweak but I'm happy with this as-is. Nice work, @maxim-belkin

break
fi
done
IFS=$' \t\n'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth setting this back to whatever it was before e.g. OLD_IFS or something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$' \t\n' is the default value for IFS:

IFS The Internal Field Separator that is used for word splitting after expansion and to split lines into words with the read builtin command. The default value is ``<space><tab><new-line>''.

I'm restoring it back to its normal value after setting it to $'\n' which causes word splitting to happen on new lines only.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup but now to understand the code I have to know that this is the default value whereas if you used OLD_IFS I'd know why it was being set back to this 😁

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to understand the code I have to know that this is the default value

I can add a comment explaining/reminding that $' \t\n' is the default value.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me 👍

@sjackman
Copy link
Member

Not for this PR, but a related comment. We have environment variables that are exposed to the user (or developer) and environment variables that are not settable by the user, completely ignored by Homebrew, and used for internal communication between Homebrew components. For example, HOMEBREW_CURL_PATH is settable by the developer, and HOMEBREW_CURL is used for internal communication. It would be awesome to have a naming scheme to distinguish one from the other. Here is my suggestion:

# an environment variable settable by the user starts with HOMEBREW_
export HOMEBREW_NO_AUTO_UPDATE=1
# an environment variable used for internal communication of Homebrew not settable by the user starts with homebrew_
export homebrew_curl=/usr/local/opt/curl/bin/curl
# an unexported shell variable has no prefix, and specifically does not start with homebrew_
local foo=bar

@maxim-belkin
Copy link
Member Author

It would be awesome to have a naming scheme to distinguish one from the other.

+1 for the idea in general but I have to admit that I like that Homebrew uses clear and easy to see HOMEBREW_ prefix for its variables. I would, therefore, propose to use HOMEBREW_INTERNAL_... prefix or something like that.

@MikeMcQuaid
Copy link
Member

MikeMcQuaid commented May 20, 2020

@sjackman @maxim-belkin yeh, I'd also like to see an internal variable distinction. I like HOMEBREW_INTERNAL_ as it's easy to filter for humans and machines.

Exit from the 'setup-ruby' function when user issued
`vendor-install` command.
We do so instead of wrapping everything in

```sh
if [[ "$HOMEBREW_COMMAND" != "vendor-install" ]]
```

`git diff` when whitespaces are ignored:

$ git diff -w
diff --git a/Library/Homebrew/utils/ruby.sh b/Library/Homebrew/utils/ruby.sh
index 7974e909c..4be204309 100644
--- a/Library/Homebrew/utils/ruby.sh
+++ b/Library/Homebrew/utils/ruby.sh
@@ -27,8 +27,11 @@ If there's no Homebrew Portable Ruby available for your processor:

   unset HOMEBREW_RUBY_PATH

-  if [[ "$HOMEBREW_COMMAND" != "vendor-install" ]]
+  if [[ "$HOMEBREW_COMMAND" == "vendor-install" ]]
   then
+    return 0
+  fi
+
   if [[ -x "$vendor_ruby_path" ]]
   then
     HOMEBREW_RUBY_PATH="$vendor_ruby_path"
@@ -85,7 +88,6 @@ If there's no Homebrew Portable Ruby available for your processor:
       HOMEBREW_RUBY_PATH="$vendor_ruby_path"
     fi
   fi
-  fi

   export HOMEBREW_RUBY_PATH
 }
1. Repurpose 'vendor_ruby_current_version' variable:
   now this is not a pointer to a file but actual version number
2. Introduce 'vendor_ruby_latest_version' variable:
   it holds the value of the latest version of portable Ruby
Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Shout when you consider this ready to merge @maxim-belkin.

@maxim-belkin
Copy link
Member Author

This is still in progress.

Question: if "vendor Ruby" is not up-to-date (that is, current version != latest version) but is usable (e.g., installed version is 2.6.3, latest is 2.6.6) -- shall Homebrew upgrade it? If so, shall Homebrew fail upon failing to upgrade it?

@sjackman
Copy link
Member

Question: if "vendor Ruby" is not up-to-date (that is, current version != latest version) but is usable (e.g., installed version is 2.6.3, latest is 2.6.6) -- shall Homebrew upgrade it? If so, shall Homebrew fail upon failing to upgrade it?

Short answer: yes and yes

@maxim-belkin
Copy link
Member Author

Short answer: yes and yes

I wonder if the second "yes" is reasonable / user-friendly. Instead of failing, we could search for a usable Ruby in PATH or /System folder (on a Mac).

@sjackman
Copy link
Member

I wonder if the second "yes" is reasonable / user-friendly. Instead of failing, we could search for a usable Ruby in PATH or /System folder (on a Mac).

I suppose, but I wouldn't want to overly complicate the code to handle this (hopefully uncommon) edge case.

@MikeMcQuaid
Copy link
Member

FYI if interested: the logic to remove an unnecessary vendored-ruby is in brew cleanup.

Short answer: yes and yes
I suppose, but I wouldn't want to overly complicate the code to handle this (hopefully uncommon) edge case.

Agreed.

@maxim-belkin maxim-belkin changed the title cmd/update.sh: keep HOMEBREW_RUBY_PATH set when necessary utils/ruby.sh: search PATH for Ruby on Linux. update.sh: keep HOMEBREW_RUBY_PATH set. May 27, 2020
@maxim-belkin
Copy link
Member Author

I suppose, but I wouldn't want to overly complicate the code to handle this (hopefully uncommon) edge case.

The difference is onoe vs odie in a single line of code. The solution I'm working on right now stops as soon as it finds Ruby that we need. So, if I odie -- the function that looks for Ruby would just stop, whereas if I onoe -- the function would continue its execution.

FYI if interested: the logic to remove an unnecessary vendored-ruby is in brew cleanup.

Thank you for the pointer!

@MikeMcQuaid, changes that I'm working on are probably out of scope of this PR and I think it makes sense to merge this one now and discuss the other changes in a separate issue/PR. Apologies for delaying this.

@MikeMcQuaid MikeMcQuaid merged commit 0b6ae53 into Homebrew:master May 27, 2020
@MikeMcQuaid
Copy link
Member

Thanks again @maxim-belkin!

@sjackman
Copy link
Member

Yes, thank you, Maxim!

@maxim-belkin
Copy link
Member Author

Thank you for the reviews and patience, @MikeMcQuaid, @sjackman, and @rmNULL!

@maxim-belkin maxim-belkin deleted the keep_ruby_path_set branch May 27, 2020 17:37
@rmNULL
Copy link
Contributor

rmNULL commented May 27, 2020

Thank you for the reviews and patience, @MikeMcQuaid, @sjackman, and @rmNULL!

Thanks for the effort :)

@BrewTestBot BrewTestBot added the outdated PR was locked due to age label Dec 29, 2020
@Homebrew Homebrew locked as resolved and limited conversation to collaborators Dec 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement outdated PR was locked due to age
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants