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

Secrets #12

Closed
lmangani opened this issue Nov 8, 2024 · 41 comments
Closed

Secrets #12

lmangani opened this issue Nov 8, 2024 · 41 comments
Labels
enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed

Comments

@lmangani
Copy link
Collaborator

lmangani commented Nov 8, 2024

The extension should leverage Secrets as an option to safely store parameters across sessions.

@lmangani lmangani added enhancement New feature or request help wanted Extra attention is needed good first issue Good for newcomers labels Nov 8, 2024
@aborruso
Copy link

Ciao @lmangani , I have a related question: now is there no way to save default api_url, api_token and api_key?
Do I have to set them every time at startup?

Thank you for this great tool

@lmangani
Copy link
Collaborator Author

CIao @aborruso at this time the settings are indeed required, but if there's interest I'll get started on stored SECRETS 👍

@aborruso
Copy link

CIao @aborruso at this time the settings are indeed required, but if there's interest I'll get started on stored SECRETS 👍

Grazie @lmangani, my use case is very trivial: I would like to open duckdb cli and use this fantastic work of yours, as available by default (with automatic load in .rc file), and without every time writing these parameters.

And set these parameters only when I don't want to use the default ones. If you think this is helpful, and you can put time and head into it, thank you very much. I would like to help you, but I don't know how to do it.

@lmangani
Copy link
Collaborator Author

lmangani commented Dec 29, 2024

@aborruso here's an untested PR with SECRETS support and instructions. Would you able to build and validate it locally?

Instructions

Clone and build the PR branch locally:

cd /usr/src
git clone -b secret-manager --recurse-submodules https://github.com/quackscience/duckdb-extension-openprompt
cd duckdb-extension-openprompt
OVERRIDE_GIT_DESCRIBE="v1.1.3" GEN=ninja make

Run the local DuckDB build:

./build/release/duckdb

Add and test SECRETS

D CREATE SECRET IF NOT EXISTS open_prompt (
      TYPE open_prompt,
      PROVIDER config,
      api_token 'your-api-token',
      api_url 'http://localhost:11434/v1/chat/completions',
      model_name 'qwen2.5:0.5b',
      api_timeout '30'
  );

Testing

At this point the parameters should be derived from SECRETS instead of SET parameters.

@lmangani
Copy link
Collaborator Author

lmangani commented Dec 29, 2024

I also added ENV parameters to allow provisioning the process from the system at runtime

    OPEN_PROMPT_API_URL
    OPEN_PROMPT_API_TOKEN
    OPEN_PROMPT_MODEL_NAME
    OPEN_PROMPT_API_TIMEOUT

@aborruso
Copy link

Grazie @lmangani , I will try tomorrow.

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

ciao @aborruso did you get a chance to try this?

@aborruso
Copy link

aborruso commented Jan 7, 2025

ciao @aborruso did you get a chance to try this?

Ciao @lmangani I have a fatal error: Killed signal terminated program cc1plus. Now I try to solve :(

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

@aborruso i'm sorry about this! is the error at build time or run time?

@aborruso
Copy link

aborruso commented Jan 7, 2025

This one

mkdir -p build/release
cmake -G "Ninja" -DFORCE_COLORED_OUTPUT=1 -DEXTENSION_STATIC_BUILD=1 -DDUCKDB_EXTENSION_CONFIGS='/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/extension_config.cmake'   -DOSX_BUILD_ARCH=   -DDUCKDB_EXPLICIT_PLATFORM='' -DCUSTOM_LINKER=  -DCMAKE_BUILD_TYPE=Release -S "./duckdb/" -B build/release
-- git hash af39bd0dcf, version v1.1.1, extension folder v1.1.1
-- Extensions will be deployed to: /home/aborruso/lavagna/tmp/duckdb-extension-openprompt/build/release/repository
-- Load extension 'open_prompt' from '/home/aborruso/lavagna/tmp/duckdb-extension-openprompt' @ b86b137
-- Load extension 'parquet' from '/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/extensions' @ v1.1.1
-- Load extension 'jemalloc' from '/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/extensions' @ v1.1.1
CMake Warning at CMakeLists.txt:1240 (message):
  Extension 'open_prompt' has a vcpkg.json, but build was not run with VCPKG.
  If build fails, check out VCPKG build instructions in
  'duckdb/extension/README.md' or try manually installing the dependencies in
  /home/aborruso/lavagna/tmp/duckdb-extension-openpromptvcpkg.json


-- Extensions linked into DuckDB: [open_prompt, parquet, jemalloc]
-- Tests loaded for extensions: [open_prompt]
-- Configuring done
-- Generating done
-- Build files have been written to: /home/aborruso/lavagna/tmp/duckdb-extension-openprompt/build/release
cmake --build build/release --config Release
[15/511] Building CXX object src/parser/transform/statement/CMakeFi...kdb_transformer_statement.dir/ub_duckdb_transformer_statement.cpp.o
FAILED: src/parser/transform/statement/CMakeFiles/duckdb_transformer_statement.dir/ub_duckdb_transformer_statement.cpp.o
/usr/bin/ccache /usr/bin/c++ -DDUCKDB -DDUCKDB_BUILD_LIBRARY -DDUCKDB_EXTENSION_JEMALLOC_LINKED=1 -DDUCKDB_EXTENSION_OPEN_PROMPT_LINKED=1 -DDUCKDB_EXTENSION_PARQUET_LINKED=1 -DDUCKDB_MAIN_LIBRARY -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/src/include -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/fsst -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/fmt/include -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/hyperloglog -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/fastpforlib -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/skiplist -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/fast_float -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/re2 -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/miniz -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/utf8proc/include -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/concurrentqueue -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/pcg -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/tdigest -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/mbedtls/include -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/jaro_winkler -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/third_party/yyjson/include -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/extension -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/src/include -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/extension/parquet/include -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/extension/jemalloc/include -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/src/parser/../../third_party/libpg_query/include -I/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/duckdb/src/parser/../../third_party/libpg_query -O3 -DNDEBUG -ffunction-sections -fdata-sections -O3 -DNDEBUG   -fPIC -fdiagnostics-color=always -std=c++11 -MD -MT src/parser/transform/statement/CMakeFiles/duckdb_transformer_statement.dir/ub_duckdb_transformer_statement.cpp.o -MF src/parser/transform/statement/CMakeFiles/duckdb_transformer_statement.dir/ub_duckdb_transformer_statement.cpp.o.d -o src/parser/transform/statement/CMakeFiles/duckdb_transformer_statement.dir/ub_duckdb_transformer_statement.cpp.o -c src/parser/transform/statement/ub_duckdb_transformer_statement.cpp
c++: fatal error: Killed signal terminated program cc1plus

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

Looks like OOM to me. What's your OS/ARCH and how much memory does it have?

@aborruso
Copy link

aborruso commented Jan 7, 2025

Looks like OOM to me. What's your OS/ARCH and how much memory does it have?

It's my small Debian 12, with 8 GB ram :(
I have tried to set a 4 GB swap file, but I have the same error.

image

@aborruso
Copy link

aborruso commented Jan 7, 2025

I increased the memory, but now I have this

cmake --build build/release --config Release
[23/385] Building CXX object extension/open_prompt/CMakeFi...mpt_loadable_extension.dir/src/open_prompt_extension.cpp.o
FAILED: extension/open_prompt/CMakeFiles/open_prompt_loadable_extension.dir/src/open_prompt_extension.cpp.o
/usr/bin/ccache /usr/bin/c++ -DDUCKDB_BUILD_LIBRARY -DDUCKDB_BUILD_LOADABLE_EXTENSION -DEXT_VERSION_OPEN_PROMPT=\"b86b137\" -I../../duckdb/src/include -I../../duckdb/third_party/fsst -I../../duckdb/third_party/fmt/include -I../../duckdb/third_party/hyperloglog -I../../duckdb/third_party/fastpforlib -I../../duckdb/third_party/skiplist -I../../duckdb/third_party/fast_float -I../../duckdb/third_party/re2 -I../../duckdb/third_party/miniz -I../../duckdb/third_party/utf8proc/include -I../../duckdb/third_party/concurrentqueue -I../../duckdb/third_party/pcg -I../../duckdb/third_party/tdigest -I../../duckdb/third_party/mbedtls/include -I../../duckdb/third_party/jaro_winkler -I../../duckdb/third_party/yyjson/include -I../../src/include -I../../duckdb/third_party/httplib -I../../duckdb/third_party/libpg_query/include -O3 -DNDEBUG -ffunction-sections -fdata-sections -O3 -DNDEBUG   -fPIC -fvisibility=hidden -fdiagnostics-color=always -std=c++11 -MD -MT extension/open_prompt/CMakeFiles/open_prompt_loadable_extension.dir/src/open_prompt_extension.cpp.o -MF extension/open_prompt/CMakeFiles/open_prompt_loadable_extension.dir/src/open_prompt_extension.cpp.o.d -o extension/open_prompt/CMakeFiles/open_prompt_loadable_extension.dir/src/open_prompt_extension.cpp.o -c /home/aborruso/lavagna/tmp/duckdb-extension-openprompt/src/open_prompt_extension.cpp
/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/src/open_prompt_extension.cpp: In member function ‘virtual duckdb::unique_ptr<duckdb::FunctionData> duckdb::OpenPromptData::Copy() const’:
/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/src/open_prompt_extension.cpp:46:20: error: could not convert ‘res’ from ‘unique_ptr<duckdb::OpenPromptData,default_delete<duckdb::OpenPromptData>,[...]>’ to ‘unique_ptr<duckdb::FunctionData,default_delete<duckdb::FunctionData>,[...]>’
   46 |             return res;
      |                    ^~~
      |                    |
      |                    unique_ptr<duckdb::OpenPromptData,default_delete<duckdb::OpenPromptData>,[...]>
[24/385] Building CXX object extension/open_prompt/CMakeFiles/open_prompt_extension.dir/src/open_prompt_extension.cpp.o
FAILED: extension/open_prompt/CMakeFiles/open_prompt_extension.dir/src/open_prompt_extension.cpp.o
/usr/bin/ccache /usr/bin/c++ -DDUCKDB_BUILD_LIBRARY -DEXT_VERSION_OPEN_PROMPT=\"b86b137\" -I../../duckdb/src/include -I../../duckdb/third_party/fsst -I../../duckdb/third_party/fmt/include -I../../duckdb/third_party/hyperloglog -I../../duckdb/third_party/fastpforlib -I../../duckdb/third_party/skiplist -I../../duckdb/third_party/fast_float -I../../duckdb/third_party/re2 -I../../duckdb/third_party/miniz -I../../duckdb/third_party/utf8proc/include -I../../duckdb/third_party/concurrentqueue -I../../duckdb/third_party/pcg -I../../duckdb/third_party/tdigest -I../../duckdb/third_party/mbedtls/include -I../../duckdb/third_party/jaro_winkler -I../../duckdb/third_party/yyjson/include -I../../src/include -I../../duckdb/third_party/httplib -I../../duckdb/third_party/libpg_query/include -O3 -DNDEBUG -ffunction-sections -fdata-sections -O3 -DNDEBUG   -fPIC -fdiagnostics-color=always -std=c++11 -MD -MT extension/open_prompt/CMakeFiles/open_prompt_extension.dir/src/open_prompt_extension.cpp.o -MF extension/open_prompt/CMakeFiles/open_prompt_extension.dir/src/open_prompt_extension.cpp.o.d -o extension/open_prompt/CMakeFiles/open_prompt_extension.dir/src/open_prompt_extension.cpp.o -c /home/aborruso/lavagna/tmp/duckdb-extension-openprompt/src/open_prompt_extension.cpp
/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/src/open_prompt_extension.cpp: In member function ‘virtual duckdb::unique_ptr<duckdb::FunctionData> duckdb::OpenPromptData::Copy() const’:
/home/aborruso/lavagna/tmp/duckdb-extension-openprompt/src/open_prompt_extension.cpp:46:20: error: could not convert ‘res’ from ‘unique_ptr<duckdb::OpenPromptData,default_delete<duckdb::OpenPromptData>,[...]>’ to ‘unique_ptr<duckdb::FunctionData,default_delete<duckdb::FunctionData>,[...]>’
   46 |             return res;
      |                    ^~~
      |                    |
      |                    unique_ptr<duckdb::OpenPromptData,default_delete<duckdb::OpenPromptData>,[...]>
[28/385] Building CXX object src/main/CMakeFiles/duckdb_main.dir/ub_duckdb_main.cpp.o
ninja: build stopped: subcommand failed.
make: *** [extension-ci-tools/makefiles/duckdb_extension.Makefile:71: release] Error 1

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

It's alright - don't worry, I'll find some time to test it and merge it. Thanks for trying I appreciate it no less! Grazie Mille 👋

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

issue should be patched 🤞 waiting for builders to confirm (or punish me)

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

@aborruso the build should be fixed if you want to try again - it runs on my Linux/x86 and the action builder seems happy

@aborruso
Copy link

aborruso commented Jan 7, 2025

@aborruso the build should be fixed if you want to try again - it runs on my Linux/x86 and the action builder seems happy

Do I must restart from here?

git clone -b secret-manager --recurse-submodules https://github.com/quackscience/duckdb-extension-openprompt

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

If you have already clone, you can just do:

git pull
OVERRIDE_GIT_DESCRIBE="v1.1.3" GEN=ninja make

and it should pull the patch and continue where it left off. Once again thanks!

@aborruso
Copy link

aborruso commented Jan 7, 2025

If I can do the build, do I have to uninstall the previous one first?
Once I do, how do I install this local one?

Grazie

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

No need to overwrite the system installation, this will simply build a local version you can run for testing:

./build/release/duckdb

From within the test build shell you should be able to perform the validation without impacting anything else 🤞 if you have any questions ping me

@aborruso
Copy link

aborruso commented Jan 7, 2025

Ciao @lmangani , I am stupid :)

When I run

CREATE SECRET IF NOT EXISTS open_prompt (
      TYPE open_prompt,
      PROVIDER config,
      api_token 'xxxxx',
      api_url 'https://api.groq.com/openai/v1/chat/completions',
      model_name 'llama-3.3-70b-versatile',
      api_timeout '30'
  );

I have Invalid Input Error: Secret provider 'config' not found for type 'open_prompt'

Do I must insert groq?

Thank you

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

Interesting... I copy pasted the same in my local build and it seems to succeed on my Linux/x86 w/ Debian 12

D CREATE SECRET IF NOT EXISTS open_prompt (
        TYPE open_prompt,
        PROVIDER config,
        api_token 'xxxxx',
        api_url 'https://api.groq.com/openai/v1/chat/completions',
        model_name 'llama-3.3-70b-versatile',
        api_timeout '30'
    );
┌─────────┐
│ Success │
│ boolean │
├─────────┤
│ true    │
└─────────┘
D FROM duckdb_secrets();
┌─────────────┬─────────────┬──────────┬────────────┬─────────┬───────────┬──────────────────────────────────────────────────────────┐
│    name     │    type     │ provider │ persistent │ storage │   scope   │                      secret_string                       │
│   varcharvarcharvarcharbooleanvarcharvarchar[] │                         varchar                          │
├─────────────┼─────────────┼──────────┼────────────┼─────────┼───────────┼──────────────────────────────────────────────────────────┤
│ open_prompt │ open_prompt │ config   │ false      │ memory  │ []        │ name=open_prompt;type=open_prompt;provider=config;seri…  │
└─────────────┴─────────────┴──────────┴────────────┴─────────┴───────────┴──────────────────────────────────────────────────────────┘

also persistent seems to work here:

D CREATE PERSISTENT SECRET IF NOT EXISTS open_prompt (
        TYPE open_prompt,
        PROVIDER config,
        api_token 'xxxxx',
        api_url 'https://api.groq.com/openai/v1/chat/completions',
        model_name 'llama-3.3-70b-versatile',
        api_timeout '30'
    );
┌─────────┐
│ Success │
│ boolean │
├─────────┤
│ true    │
└─────────┘
D {exit}


D FROM duckdb_secrets();
┌─────────────┬─────────────┬──────────┬────────────┬────────────┬───────────┬───────────────────────────────────────────────────────┐
│    name     │    type     │ provider │ persistent │  storage   │   scope   │                     secret_string                     │
│   varcharvarcharvarcharbooleanvarcharvarchar[] │                        varchar                        │
├─────────────┼─────────────┼──────────┼────────────┼────────────┼───────────┼───────────────────────────────────────────────────────┤
│ open_prompt │ open_prompt │ config   │ true       │ local_file │ []        │ name=open_prompt;type=open_prompt;provider=config;s…  │
└─────────────┴─────────────┴──────────┴────────────┴────────────┴───────────┴───────────────────────────────────────────────────────┘

This is using duckdb in ./build/release/duckdb from the extension folder?

@aborruso
Copy link

aborruso commented Jan 7, 2025

This is using duckdb in ./build/release/duckdb from the extension folder?

I'm using the duckdb I have in my ./duckdb-extension-openprompt/build/release folder. The v1.1.1 af39bd0dcf version

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

I updated the submodules to point at the latest version of duckdb and ci tools - that's the only reason I see for getting v1.1.1

@aborruso
Copy link

aborruso commented Jan 7, 2025

It works!!!

Thank you very much

image

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

@aborruso fantastico! does it work with the actual open_prompt queries to replace the SET details?

@aborruso
Copy link

aborruso commented Jan 7, 2025

@aborruso fantastico! does it work with the actual open_prompt queries to replace the SET details?

If I run SELECT open_prompt('Write a one-line poem about ducks') AS response; I get

┌──────────────────────────────────┐
│             response             │
│             varchar              │
├──────────────────────────────────┤
│ Error: HTTP error 404: Not Found │
└──────────────────────────────────┘

I have used both https://api.groq.com/openai/v1 and https://api.groq.com/openai/v1/chat/completions

@aborruso
Copy link

aborruso commented Jan 7, 2025

In this way, it works

D SET VARIABLE openprompt_api_url = 'https://api.groq.com/openai/v1/chat/completions';
D SET VARIABLE openprompt_api_token = 'xxxx';
D SET VARIABLE openprompt_model_name = 'llama-3.3-70b-versatile';
D SELECT open_prompt('Write a one-line poem about ducks') AS response;

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

Ok that's useful let me recheck as soon as possible what the secrets mistake is - I assume you either used persistent secrets and/or tested in the same session you saved secrets within correct? secrets are not persistent unless specified.

Any chance you could try with ENVs on the process to see if those work?

export  OPEN_PROMPT_API_URL = ...
export  OPEN_PROMPT_API_TOKEN = ...
export  OPEN_PROMPT_MODEL_NAME = ...
export  OPEN_PROMPT_API_TIMEOUT = ...

Grazie this really helps!

@aborruso
Copy link

aborruso commented Jan 7, 2025

Hi @lmangani , after I export the variables in the shell, I run duckdb and this query SELECT open_prompt('Write a one-line poem about ducks') AS response;, and I have again Error: HTTP error 404: Not Found

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

@aborruso Andrea thank you this helped me locate the logical issue (and why it worked locally) so now I should be able to release a working version! I really appreciate your time 👍

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

@aborruso If you feel like trying, the latest patches to the branch correctly initializes ENV, SECRET, SET or DEFAULT (in this order) once again thanks for your kind assistance testing this!

If you have any suggestions as of the override order, feel free to share it and I'll include it

@aborruso
Copy link

aborruso commented Jan 7, 2025

@aborruso If you feel like trying, the latest patches to the branch correctly initializes ENV, SECRET, SET or DEFAULT (in this order) once again thanks for your kind assistance testing this!

how to update my cloned folder? git pull?

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

Yes, the branch is still there so you can git pull to get the diffs - I also merged it so you can also try with main in case you're starting over

@aborruso
Copy link

aborruso commented Jan 7, 2025

I'm probably tired. I launched git pull, and then after SELECT open_prompt('Write a one-line poem about ducks') AS response;, I have again Error: HTTP error 404: Not Found.
I am definitely doing something wrong :(

@lmangani
Copy link
Collaborator Author

lmangani commented Jan 7, 2025

Testing can indeed tedious. Sorry for the trouble and once again thanks! I've tested it locally usiong ENV variables and SECRET settings and it all seems to work. Did not test with remote services. Not the ENV settings takes precedence over SECRETS and SET variables. I'll try again tomorrow as well to be sure.

@aborruso
Copy link

Ciao @lmangani the "secret-manager" branch is no longer present. Do I start over by cloning the main branch?

Thank you

@lmangani
Copy link
Collaborator Author

Ciao @aborruso that's right, you can test using the current main branch 👋

@aborruso
Copy link

It works great, thank you very much @lmangani

@aborruso
Copy link

Ciao @lmangani to use it with my standard duckdb, do I now have to wait for the update to be installable?

@lmangani
Copy link
Collaborator Author

Grazie @aborruso glad we made this improvement and learned a few things along the way, too!

There's a PR open on the community repo: duckdb/community-extensions#255
Note on the 20th DuckDB 1.2.0 will come out so we'll have to rebuild every extension!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants