Skip to content

RLS "Failed to start language server" #95

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

Closed
mqudsi opened this issue Aug 15, 2017 · 2 comments
Closed

RLS "Failed to start language server" #95

mqudsi opened this issue Aug 15, 2017 · 2 comments

Comments

@mqudsi
Copy link

mqudsi commented Aug 15, 2017

I'm running master, LanguageClient-neovim, deoplete, and git

My minimal vim.rc:

"dein Scripts-----------------------------
if &compatible
	set nocompatible
endif

let g:python3_host_prog = systemlist("which python3")[0]
let g:loaded_python_provider = 1

set runtimepath+=$HOME/.config/nvim/dein/repos/github.com/Shougo/dein.vim
filetype off

if dein#load_state('$HOME/.config/nvim/dein/')
	call dein#begin('$HOME/.config/nvim/dein/')
	call dein#add('Shougo/dein.vim')

	call dein#add('Shougo/deoplete.nvim')
	call dein#add('autozimu/LanguageClient-neovim',
		\{'on_ft': ['rust']})
	call dein#add('rust-lang/rust.vim',
		\{'on_ft': ['rust']})

	" Required:
	call dein#end()
	call dein#save_state()
endif

" Required:
filetype plugin indent on

let $RUST_SRC_PATH = glob("$HOME/.rustup/toolchains/nightly*/lib/rustlib/src/rust/src")

let g:LanguageClient_serverCommands = {
    \ 'rust': ['rustup', 'run', 'nightly', 'rls'],
	\ 'javascript': ['/usr/local/lib/node_modules/javascript-typescript-langserver/lib/language-server-stdio.js'],
	\ 'typescript': ['/usr/local/lib/node_modules/javascript-typescript-langserver/lib/language-server-stdio.js'],
\ }

" Automatically start language servers.
let g:LanguageClient_autoStart = 1

Result of LanguageClient.log:

22:41:40 WARNING  no handler implemented for rustDocument_diagnosticsBegin
22:41:40 WARNING  register completion manager source failed. Error: NvimError(b'Error calling function.',)
22:41:41 WARNING  no handler implemented for rustDocument_diagnosticsEnd
22:41:55 INFO     textDocument/didChange
22:41:55 DEBUG     => {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"contentChanges":[{"text":"extern crate abstract_ns;\nextern crate futures;\nextern crate getopts;\nextern crate ns_dns_tokio;\nextern crate rand;\nextern crate tokio_core;\nextern crate tokio_io;\n\nuse abstract_ns::Resolver;\nuse futures::{Future, Stream};\nuse futures::future;\nuse getopts::Options;\nuse ns_dns_tokio::DnsResolver;\nuse std::collections:\nuse std::env;\nuse tokio_core::net::UdpSocket;\nuse tokio_core::reactor::Core;\nuse tokio_io::{AsyncRead, io};\n\nstatic mut DEBUG: bool = false;\n\nfn print_usage(program: &str, opts: Options) {\n    let program_path = std::path::PathBuf::from(program);\n    let program_name = program_path.file_stem().unwrap().to_str().unwrap();\n    let brief = format!(\"Usage: {} [-b BIND_ADDR] -l LOCAL_PORT -h REMOTE_ADDR -r REMOTE_PORT\",\n                        program_name);\n    print!(\"{}\", opts.usage(&brief));\n}\n\nfn main() {\n    let args: Vec<String> = env::args().collect();\n    let program = args[0].clone();\n\n    let mut opts = Options::new();\n    opts.reqopt(\"l\",\n                \"local-port\",\n                \"The local port to which udpproxy should bind to\",\n                \"LOCAL_PORT\");\n    opts.reqopt(\"r\",\n                \"remote-port\",\n                \"The remote port to which UDP packets should be forwarded\",\n                \"REMOTE_PORT\");\n    opts.reqopt(\"h\",\n                \"host\",\n                \"The remote address to which packets will be forwarded\",\n                \"REMOTE_ADDR\");\n    opts.optopt(\"b\",\n                \"bind\",\n                \"The address on which to listen for incoming requests\",\n                \"BIND_ADDR\");\n    opts.optflag(\"d\", \"debug\", \"Enable debug mode\");\n\n    let matches = opts.parse(&args[1..])\n        .unwrap_or_else(|_| {\n            print_usage(&program, opts);\n            std::process::exit(-1);\n        });\n\n    unsafe {\n        DEBUG = matches.opt_present(\"d\");\n    }\n    let local_port: i32 = matches.opt_str(\"l\").unwrap().parse().unwrap();\n    let remote_port: i32 = matches.opt_str(\"r\").unwrap().parse().unwrap();\n    let remote_host = matches.opt_str(\"h\").unwrap();\n    let bind_addr = match matches.opt_str(\"b\") {\n        Some(addr) => addr,\n        None => \"127.0.0.1\".to_owned(),\n    };\n\n    forward(&bind_addr, local_port, &remote_host, remote_port);\n}\n\nfn debug(msg: String) {\n    let debug: bool;\n    unsafe {\n        debug = DEBUG;\n    }\n\n    if debug {\n        println!(\"{}\", msg);\n    }\n}\n\nfn forward(bind_ip: &str, local_port: i32, remote_host: &str, remote_port: i32) {\n    //this is the main event loop, powered by tokio core\n    let mut core = Core::new().unwrap();\n    let handle = core.handle();\n\n    //listen on the specified IP and port\n    let bind_addr = format!(\"{}:{}\", bind_ip, local_port);\n    let bind_sock = bind_addr.parse().unwrap();\n    let listener = UdpSocket::bind(&bind_sock, &handle)\n        .expect(&format!(\"Unable to bind to {}\", &bind_addr));\n    println!(\"Listening on {}\", listener.local_addr().unwrap());\n\n    //we have either been provided an IP address or a host name\n    //instead of trying to check its format, just trying creating a SocketAddr from it\n    let parse_result = format!(\"{}:{}\", remote_host, remote_port).parse::<std::net::SocketAddr>();\n    let server = future::result(parse_result)\n        .or_else(|_| {\n            //it's a hostname; we're going to need to resolve it\n            //create an async dns resolver\n            let resolver = DnsResolver::system_config(&handle).unwrap();\n\n            resolver.resolve(&format!(\"{}:{}\", remote_host, remote_port))\n                .map(move |resolved| {\n                    resolved.pick_one()\n                        .expect(&format!(\"No valid IP addresses for target {}\", remote_host))\n                })\n                .map_err(|err| println!(\"{:?}\", err))\n        })\n        .and_then(|remote_addr| {\n            println!(\"Resolved {}:{} to {}\",\n                     remote_host,\n                     remote_port,\n                     remote_addr);\n\n            let remote_addr = remote_addr.clone();\n            let handle = handle.clone();\n            listener.incoming()\n                .for_each(move |(client, client_addr)| {\n                    println!(\"New connection from {}\", client_addr);\n\n                    //establish connection to upstream for each incoming client connection\n                    let handle = handle.clone();\n                    TcpStream::connect(&remote_addr, &handle).and_then(move |remote| {\n                        let (client_recv, client_send) = client.split();\n                        let (remote_recv, remote_send) = remote.split();\n\n                        let remote_bytes_copied = io::copy(remote_recv, client_send);\n                        let client_bytes_copied = io::copy(client_recv, remote_send);\n\n                        fn error_handler<T, V>(err: T, client_addr: V)\n                            where T: std::fmt::Debug,\n                                  V: std::fmt::Display\n                        {\n                            println!(\"Error writing from upstream server to remote client {}!\",\n                                     client_addr);\n                            println!(\"{:?}\", err);\n                            ()\n                        };\n\n                        let client_addr_clone = client_addr.clone();\n                        let async1 = remote_bytes_copied.map(move |(count, _, _)| {\n                                debug(format!(\"Transferred {} bytes from upstream server to \\\n                                               remote client {}\",\n                                              count,\n                                              client_addr_clone))\n                            })\n                            .map_err(move |err| error_handler(err, client_addr_clone));\n\n                        let client_addr_clone = client_addr;\n                        let async2 = client_bytes_copied.map(move |(count, _, _)| {\n                                debug(format!(\"Transferred {} bytes from remote client {} to \\\n                                               upstream server\",\n                                              count,\n                                              client_addr_clone))\n                            })\n                            .map_err(move |err| error_handler(err, client_addr_clone));\n\n                        handle.spawn(async1);\n                        handle.spawn(async2);\n\n                        Ok(())\n                    })\n                })\n                .map_err(|err| println!(\"{:?}\", err))\n        });\n\n    core.run(server).unwrap();\n}\n"}],"textDocument":{"version":2,"uri":"file:///mnt/d/GIT/udpproxy/src/main.rs"}}}
22:41:55 DEBUG     <= {"jsonrpc":"2.0","method":"rustDocument/diagnosticsBegin","params":null}
22:41:55 WARNING  no handler implemented for rustDocument_diagnosticsBegin
22:41:56 INFO     textDocument/didChange
22:41:56 DEBUG     => {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"contentChanges":[{"text":"extern crate abstract_ns;\nextern crate futures;\nextern crate getopts;\nextern crate ns_dns_tokio;\nextern crate rand;\nextern crate tokio_core;\nextern crate tokio_io;\n\nuse abstract_ns::Resolver;\nuse futures::{Future, Stream};\nuse futures::future;\nuse getopts::Options;\nuse ns_dns_tokio::DnsResolver;\nuse std::collections::\nuse std::env;\nuse tokio_core::net::UdpSocket;\nuse tokio_core::reactor::Core;\nuse tokio_io::{AsyncRead, io};\n\nstatic mut DEBUG: bool = false;\n\nfn print_usage(program: &str, opts: Options) {\n    let program_path = std::path::PathBuf::from(program);\n    let program_name = program_path.file_stem().unwrap().to_str().unwrap();\n    let brief = format!(\"Usage: {} [-b BIND_ADDR] -l LOCAL_PORT -h REMOTE_ADDR -r REMOTE_PORT\",\n                        program_name);\n    print!(\"{}\", opts.usage(&brief));\n}\n\nfn main() {\n    let args: Vec<String> = env::args().collect();\n    let program = args[0].clone();\n\n    let mut opts = Options::new();\n    opts.reqopt(\"l\",\n                \"local-port\",\n                \"The local port to which udpproxy should bind to\",\n                \"LOCAL_PORT\");\n    opts.reqopt(\"r\",\n                \"remote-port\",\n                \"The remote port to which UDP packets should be forwarded\",\n                \"REMOTE_PORT\");\n    opts.reqopt(\"h\",\n                \"host\",\n                \"The remote address to which packets will be forwarded\",\n                \"REMOTE_ADDR\");\n    opts.optopt(\"b\",\n                \"bind\",\n                \"The address on which to listen for incoming requests\",\n                \"BIND_ADDR\");\n    opts.optflag(\"d\", \"debug\", \"Enable debug mode\");\n\n    let matches = opts.parse(&args[1..])\n        .unwrap_or_else(|_| {\n            print_usage(&program, opts);\n            std::process::exit(-1);\n        });\n\n    unsafe {\n        DEBUG = matches.opt_present(\"d\");\n    }\n    let local_port: i32 = matches.opt_str(\"l\").unwrap().parse().unwrap();\n    let remote_port: i32 = matches.opt_str(\"r\").unwrap().parse().unwrap();\n    let remote_host = matches.opt_str(\"h\").unwrap();\n    let bind_addr = match matches.opt_str(\"b\") {\n        Some(addr) => addr,\n        None => \"127.0.0.1\".to_owned(),\n    };\n\n    forward(&bind_addr, local_port, &remote_host, remote_port);\n}\n\nfn debug(msg: String) {\n    let debug: bool;\n    unsafe {\n        debug = DEBUG;\n    }\n\n    if debug {\n        println!(\"{}\", msg);\n    }\n}\n\nfn forward(bind_ip: &str, local_port: i32, remote_host: &str, remote_port: i32) {\n    //this is the main event loop, powered by tokio core\n    let mut core = Core::new().unwrap();\n    let handle = core.handle();\n\n    //listen on the specified IP and port\n    let bind_addr = format!(\"{}:{}\", bind_ip, local_port);\n    let bind_sock = bind_addr.parse().unwrap();\n    let listener = UdpSocket::bind(&bind_sock, &handle)\n        .expect(&format!(\"Unable to bind to {}\", &bind_addr));\n    println!(\"Listening on {}\", listener.local_addr().unwrap());\n\n    //we have either been provided an IP address or a host name\n    //instead of trying to check its format, just trying creating a SocketAddr from it\n    let parse_result = format!(\"{}:{}\", remote_host, remote_port).parse::<std::net::SocketAddr>();\n    let server = future::result(parse_result)\n        .or_else(|_| {\n            //it's a hostname; we're going to need to resolve it\n            //create an async dns resolver\n            let resolver = DnsResolver::system_config(&handle).unwrap();\n\n            resolver.resolve(&format!(\"{}:{}\", remote_host, remote_port))\n                .map(move |resolved| {\n                    resolved.pick_one()\n                        .expect(&format!(\"No valid IP addresses for target {}\", remote_host))\n                })\n                .map_err(|err| println!(\"{:?}\", err))\n        })\n        .and_then(|remote_addr| {\n            println!(\"Resolved {}:{} to {}\",\n                     remote_host,\n                     remote_port,\n                     remote_addr);\n\n            let remote_addr = remote_addr.clone();\n            let handle = handle.clone();\n            listener.incoming()\n                .for_each(move |(client, client_addr)| {\n                    println!(\"New connection from {}\", client_addr);\n\n                    //establish connection to upstream for each incoming client connection\n                    let handle = handle.clone();\n                    TcpStream::connect(&remote_addr, &handle).and_then(move |remote| {\n                        let (client_recv, client_send) = client.split();\n                        let (remote_recv, remote_send) = remote.split();\n\n                        let remote_bytes_copied = io::copy(remote_recv, client_send);\n                        let client_bytes_copied = io::copy(client_recv, remote_send);\n\n                        fn error_handler<T, V>(err: T, client_addr: V)\n                            where T: std::fmt::Debug,\n                                  V: std::fmt::Display\n                        {\n                            println!(\"Error writing from upstream server to remote client {}!\",\n                                     client_addr);\n                            println!(\"{:?}\", err);\n                            ()\n                        };\n\n                        let client_addr_clone = client_addr.clone();\n                        let async1 = remote_bytes_copied.map(move |(count, _, _)| {\n                                debug(format!(\"Transferred {} bytes from upstream server to \\\n                                               remote client {}\",\n                                              count,\n                                              client_addr_clone))\n                            })\n                            .map_err(move |err| error_handler(err, client_addr_clone));\n\n                        let client_addr_clone = client_addr;\n                        let async2 = client_bytes_copied.map(move |(count, _, _)| {\n                                debug(format!(\"Transferred {} bytes from remote client {} to \\\n                                               upstream server\",\n                                              count,\n                                              client_addr_clone))\n                            })\n                            .map_err(move |err| error_handler(err, client_addr_clone));\n\n                        handle.spawn(async1);\n                        handle.spawn(async2);\n\n                        Ok(())\n                    })\n                })\n                .map_err(|err| println!(\"{:?}\", err))\n        });\n\n    core.run(server).unwrap();\n}\n"}],"textDocument":{"version":3,"uri":"file:///mnt/d/GIT/udpproxy/src/main.rs"}}}
22:41:56 DEBUG     <= {"jsonrpc":"2.0","method":"rustDocument/diagnosticsBegin","params":null}
22:41:56 WARNING  no handler implemented for rustDocument_diagnosticsBegin
22:41:56 DEBUG     <= 
22:41:56 ERROR    Failed to start language server: [b'{"message":"expected identifier, found keyword `use`","code":null,"level":"error","spans":[{"file_name":"src/main.rs","byte_start":320,"byte_end":323,"line_start":15,"line_end":15,"column_start":1,"column_end":4,"is_primary":true,"text":[{"text":"use std::env;","highlight_start":1,"highlight_end":4}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null}\n', b'{"message":"expected one of `::`, `;`, or `as`, found `std`","code":null,"level":"error","spans":[{"file_name":"src/main.rs","byte_start":323,"byte_end":323,"line_start":15,"line_end":15,"column_start":4,"column_end":4,"is_primary":false,"text":[{"text":"use std::env;","highlight_start":4,"highlight_end":4}],"label":"expected one of `::`, `;`, or `as` here","suggested_replacement":null,"expansion":null},{"file_name":"src/main.rs","byte_start":324,"byte_end":327,"line_start":15,"line_end":15,"column_start":5,"column_end":8,"is_primary":true,"text":[{"text":"use std::env;","highlight_start":5,"highlight_end":8}],"label":"unexpected token","suggested_replacement":null,"expansion":null}],"children":[],"rendered":null}\n', b'{"message":"aborting due to 2 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":null}\n', b'thread \'<unnamed>\' panicked at \'could not run cargo: CargoError(Internal(Msg("failed to stat `/mnt/d/GIT/udpproxy/target/rls/debug/.fingerprint/udpproxy-9ca18b3406e94519/dep-bin-udpproxy-9ca18b3406e94519`")), State { next_error: Some(Error { repr: Os { code: 2, message: "No such file or directory" } }), backtrace: None })\', /checkout/src/libcore/result.rs:860:4\n', b'note: Run with `RUST_BACKTRACE=1` for a backtrace.\n', b'thread \'<unnamed>\' panicked at \'called `Result::unwrap()` on an `Err` value: "PoisonError { inner: .. }"\', /checkout/src/libcore/result.rs:860:4\n', b'thread \'main\' panicked at \'called `Result::unwrap()` on an `Err` value: "PoisonError { inner: .. }"\', /checkout/src/libcore/result.rs:860:4\n']
22:41:57 ERROR    Failed to start language server: []
22:41:57 ERROR    Failed to start language server: []
22:41:59 ERROR    Failed to start language server: []

:CheckHealth:


health#deoplete#check
========================================================================
## deoplete.nvim
  - SUCCESS: has("nvim") was successful
  - SUCCESS: has("python3") was successful
  - INFO: If you're still having problems, try the following commands:
    $ export NVIM_PYTHON_LOG_FILE=/tmp/log
    $ export NVIM_PYTHON_LOG_LEVEL=DEBUG
    $ nvim
    $ cat /tmp/log_{PID}
    and then create an issue on github

health#nvim#check
========================================================================
## Configuration
  - SUCCESS: no issues found

## Performance
  - SUCCESS: Build type: RelWithDebInfo

## Remote Plugins
  - SUCCESS: Up to date

## terminal
  - INFO: key_backspace (kbs) terminfo entry: key_backspace=\177
  - INFO: key_dc (kdch1) terminfo entry: key_dc=\E[3~

health#provider#check
========================================================================
## Clipboard (optional)
  - SUCCESS: Clipboard tool found: win32yank

## Python 2 provider (optional)
  - INFO: Disabled. g:loaded_python_provider=1

## Python 3 provider (optional)
  - INFO: Using: g:python3_host_prog = "/usr/bin/python3"
  - INFO: Executable: /usr/bin/python3
  - INFO: Python3 version: 3.5.2
  - INFO: python3-neovim version: 0.1.13
  - SUCCESS: Latest python3-neovim is installed: 0.1.13

## Ruby provider (optional)
  - WARNING: `ruby` and `gem` must be in $PATH.
    - SUGGESTIONS:
      - Install Ruby and verify that `ruby` and `gem` commands work.

rplugin.vim:

" python3 plugins
call remote#host#RegisterPlugin('python3', '/home/mqudsi/.config/nvim/dein/.cache/init.vim/.dein/rplugin/python3/deoplete', [
      \ {'sync': v:false, 'name': '_deoplete', 'type': 'function', 'opts': {}},
     \ ])
call remote#host#RegisterPlugin('python3', '/home/mqudsi/.config/nvim/dein/repos/github.com/autozimu/LanguageClient-neovim/rplugin/python3/LanguageClient', [
      \ {'sync': v:true, 'name': 'LanguageClient_alive', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_completionItem/resolve', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_completionManager_refresh', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_exit', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_FZFSinkTextDocumentDocumentSymbol', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_FZFSinkTextDocumentReferences', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_FZFSinkWorkspaceSymbol', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'BufReadPost', 'type': 'autocmd', 'opts': {'pattern': '*'}},
      \ {'sync': v:false, 'name': 'CursorMoved', 'type': 'autocmd', 'opts': {'pattern': '*', 'eval': 'line(''.'')'}},
      \ {'sync': v:false, 'name': 'TextChanged', 'type': 'autocmd', 'opts': {'pattern': '*', 'eval': 'fnamemodify(expand("<afile>"), ":p")'}},
      \ {'sync': v:false, 'name': 'TextChangedI', 'type': 'autocmd', 'opts': {'pattern': '*', 'eval': 'fnamemodify(expand("<afile>"), ":p")'}},
      \ {'sync': v:false, 'name': 'VimEnter', 'type': 'autocmd', 'opts': {'pattern': '*'}},
      \ {'sync': v:false, 'name': 'LanguageClient_initialize', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_registerServerCommands', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_setLoggingLevel', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClientStart', 'type': 'command', 'opts': {'nargs': '*', 'range': ''}},
      \ {'sync': v:false, 'name': 'LanguageClientStop', 'type': 'command', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_completion', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_completionOmnifunc', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_definition', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_didClose', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'BufWritePost', 'type': 'autocmd', 'opts': {'pattern': '*'}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_documentSymbol', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_formatting', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_hover', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_rangeFormatting', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_references', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_rename', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_textDocument_signatureHelp', 'type': 'function', 'opts': {}},
      \ {'sync': v:false, 'name': 'LanguageClient_workspace_symbol', 'type': 'function', 'opts': {}},
     \ ])


" ruby plugins


" python plugins
@autozimu
Copy link
Owner

I cannot help you much as the information doesn't make it clear what went wrong. But here is a few general trouble shooting tips:

  • Make sure rls is running properly outside this plugin. Could verify it with official vscode extension.
  • Use this project provided min vimrc. Follow this project provided trouble shooting steps.

@mqudsi
Copy link
Author

mqudsi commented Aug 15, 2017

I reported it upstream: rust-lang/rls#443

We'll see what happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants