update CONTRIBUTING.md (#4125)
This commit is contained in:
parent
48c6458766
commit
e33f802ae8
1 changed files with 180 additions and 55 deletions
235
.github/CONTRIBUTING.md
vendored
235
.github/CONTRIBUTING.md
vendored
|
@ -1,4 +1,6 @@
|
||||||
[Introduction](#contributing-to-cockatrice) | [Code Style Guide](#code-style-guide) | [Translations](#translations) | [Release Management](#release-management)
|
[Introduction](#contributing-to-cockatrice) | [Code Style Guide](
|
||||||
|
#code-style-guide) | [Translations](#translations) | [Release Management](
|
||||||
|
#release-management)
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -7,50 +9,83 @@
|
||||||
# Contributing to Cockatrice #
|
# Contributing to Cockatrice #
|
||||||
First off, thanks for taking the time to contribute to our project! 🎉 ❤ ️✨
|
First off, thanks for taking the time to contribute to our project! 🎉 ❤ ️✨
|
||||||
|
|
||||||
The following is a set of guidelines for contributing to Cockatrice. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
|
The following is a set of guidelines for contributing to Cockatrice. These are
|
||||||
|
mostly guidelines, not rules. Use your best judgment, and feel free to propose
|
||||||
|
changes to this document in a pull request.
|
||||||
|
|
||||||
|
|
||||||
# Recommended Setups #
|
# Recommended Setups #
|
||||||
|
|
||||||
For those developers who like the Linux or MacOS environment, many of our developers like working with a nifty program called [CLion](https://www.jetbrains.com/clion/). The program's a great asset and one of the best tools you'll find on these systems, but you're welcomed to use any IDE you most enjoy.
|
For those developers who like the Linux or MacOS environment, many of our
|
||||||
|
developers like working with a nifty program called [CLion](
|
||||||
|
https://www.jetbrains.com/clion/). The program's a great asset and one of the
|
||||||
|
best tools you'll find on these systems, but you're welcomed to use any IDE
|
||||||
|
you most enjoy.
|
||||||
|
|
||||||
Developers who like Windows development tend to find [Visual Studio](https://www.visualstudio.com/) the best tool for the job.
|
Developers who like Windows development tend to find [Visual Studio](
|
||||||
|
https://www.visualstudio.com/) the best tool for the job.
|
||||||
|
|
||||||
If you have any questions on IDEs, feel free to chat with us on [Gitter](https://gitter.im/Cockatrice/Cockatrice) and we would love to help answer your questions!
|
If you have any questions on IDEs, feel free to chat with us on [Gitter](
|
||||||
|
https://gitter.im/Cockatrice/Cockatrice) and we would love to help answer
|
||||||
|
your questions!
|
||||||
|
|
||||||
|
|
||||||
# Code Style Guide #
|
# Code Style Guide #
|
||||||
|
|
||||||
### Formatting and continuous integration (ci) ###
|
### Formatting and continuous integration (ci) ###
|
||||||
|
|
||||||
We currently use Travis CI to check your code for formatting issues, if your pull request was rejected because of this it would show a message in the logs. Click on "Details" next to the failed Travis CI build and then click on the failed build (most likely the fastest one) to see the log.
|
We use a separate job on Travis CI to check your code for formatting issues, if
|
||||||
|
your pull request was rejected you can check the output on their website.
|
||||||
|
Click on "Details" next to the failed Travis CI build and then click on the
|
||||||
|
Linting build (the fastest one) to see the log.
|
||||||
|
|
||||||
The message will look somewhat similar to this:
|
The message will look like this:
|
||||||
```
|
```
|
||||||
************************************************************
|
***********************************************************
|
||||||
*** Your code does not meet our formatting guidelines. ***
|
*** ***
|
||||||
*** Please correct it then commit and push your changes. ***
|
*** Your code does not comply with our style guide. ***
|
||||||
*** See our CONTRIBUTING.md file for more information. ***
|
*** ***
|
||||||
************************************************************
|
*** Please correct it or run the "clangify.sh" script. ***
|
||||||
|
*** Then commit and push those changes to this branch. ***
|
||||||
|
*** Check our CONTRIBUTING.md file for more details. ***
|
||||||
|
*** ***
|
||||||
|
*** Thank you ❤️ ***
|
||||||
|
*** ***
|
||||||
|
***********************************************************
|
||||||
```
|
```
|
||||||
The CONTRIBUTING.md file mentioned is this file. Please read [this section](#Formatting) for full information on our formatting guidelines.
|
The CONTRIBUTING.md file mentioned is this file. Please read [this section](
|
||||||
|
#formatting) for full information on our formatting guidelines.
|
||||||
|
|
||||||
### Compatibility ###
|
### Compatibility ###
|
||||||
|
|
||||||
Cockatrice is currently compiled on all platforms using <kbd>C++11</kbd>. You'll notice <kbd>C++03</kbd> code throughout the codebase. Please feel free to help convert it over!
|
Cockatrice is currently compiled on all platforms using <kbd>C++11</kbd>.
|
||||||
|
You'll notice <kbd>C++03</kbd> code throughout the codebase. Please feel free
|
||||||
|
to help convert it over!
|
||||||
|
|
||||||
For consistency, we use Qt data structures where possible. For example, `QString` over
|
For consistency, we use Qt data structures where possible. For example,
|
||||||
`std::string` and `QList` over `std::vector`.
|
`QString` over `std::string` and `QList` over `std::vector`.
|
||||||
|
|
||||||
|
Do not use old c style casts in new code, instead use a [`static_cast<>`](
|
||||||
|
https://en.cppreference.com/w/cpp/language/static_cast)
|
||||||
|
or other appropriate conversion.
|
||||||
|
|
||||||
### Formatting ###
|
### Formatting ###
|
||||||
|
|
||||||
The handy tool `clang-format` can format your code for you, it is available for almost any environment. A special `.clang-format` configuration file is included in the project and is used to format your code.
|
The handy tool `clang-format` can format your code for you, it is available for
|
||||||
|
almost any environment. A special `.clang-format` configuration file is
|
||||||
|
included in the project and is used to format your code.
|
||||||
|
|
||||||
We've also included a bash script, `clangify.sh`, that will use clang-format to format all files in one go. Use `./clangify.sh --help` to show a full help page.
|
We've also included a bash script, `clangify.sh`, that will use clang-format to
|
||||||
|
format all files in your pr in one go. Use `./clangify.sh --help` to show a
|
||||||
|
full help page.
|
||||||
|
|
||||||
To run clang-format on a single source file simply use the command `clang-format -i <filename>` to format it in place. (some systems install clang-format with a specific version number appended, `find /usr/bin -name clang-format*` should find it for you)
|
To run clang-format on a single source file simply use the command
|
||||||
|
`clang-format -i <filename>` to format it in place. (some systems install
|
||||||
|
clang-format with a specific version number appended,
|
||||||
|
`find /usr/bin -name clang-format*` should find it for you)
|
||||||
|
|
||||||
See [the clang-format documentation](https://clang.llvm.org/docs/ClangFormat.html) for more information about the tool.
|
See [the clang-format documentation](
|
||||||
|
https://clang.llvm.org/docs/ClangFormat.html) for more information about the tool.
|
||||||
|
|
||||||
#### Header files ####
|
#### Header files ####
|
||||||
|
|
||||||
|
@ -88,9 +123,15 @@ Group library includes after project includes, and in alphabetic order. Like thi
|
||||||
Use `UpperCamelCase` for classes, structs, enums, etc. and `lowerCamelCase` for
|
Use `UpperCamelCase` for classes, structs, enums, etc. and `lowerCamelCase` for
|
||||||
function and variable names.
|
function and variable names.
|
||||||
|
|
||||||
Member variables aren't decorated in any way. Don't prefix or suffix with
|
Don't use [Hungarian Notation](
|
||||||
|
https://en.wikipedia.org/wiki/Hungarian_notation).
|
||||||
|
|
||||||
|
Member variables aren't decorated in any way. Don't prefix or suffix them with
|
||||||
underscores, etc.
|
underscores, etc.
|
||||||
|
|
||||||
|
Use a separate line for each declaration, don't use a single line like this
|
||||||
|
`int one = 1, two = 2` and instead split them into two lines.
|
||||||
|
|
||||||
For arguments to constructors which have the same names as member variables,
|
For arguments to constructors which have the same names as member variables,
|
||||||
prefix those arguments with underscores:
|
prefix those arguments with underscores:
|
||||||
```c++
|
```c++
|
||||||
|
@ -115,7 +156,8 @@ If you find any usage of the old keywords, we encourage you to fix it.
|
||||||
|
|
||||||
#### Braces ####
|
#### Braces ####
|
||||||
|
|
||||||
Braces should go on their own line except for control statements, the use of braces around single line statements is preferred.
|
Braces should go on their own line except for control statements, the use of
|
||||||
|
braces around single line statements is preferred.
|
||||||
See the following example:
|
See the following example:
|
||||||
```c++
|
```c++
|
||||||
int main()
|
int main()
|
||||||
|
@ -136,17 +178,25 @@ int main()
|
||||||
|
|
||||||
#### Indentation and Spacing ####
|
#### Indentation and Spacing ####
|
||||||
|
|
||||||
Always indent using 4 spaces, do not use tabs. Opening and closing braces should be on the same indentation layer, member access specifiers in classes or structs should not be indented.
|
Always indent using 4 spaces, do not use tabs. Opening and closing braces
|
||||||
|
should be on the same indentation layer, member access specifiers in classes or
|
||||||
|
structs should not be indented.
|
||||||
|
|
||||||
All operators and braces should be separated by spaces, do not add a space next to the inside of a brace.
|
All operators and braces should be separated by spaces, do not add a space next
|
||||||
|
to the inside of a brace.
|
||||||
|
|
||||||
If multiple lines of code that follow eachother have single line comments behind them, place all of them on the same indentation level. This indentation level should be equal to the longest line of code for each of these comments, without added spacing.
|
If multiple lines of code that follow eachother have single line comments
|
||||||
|
behind them, place all of them on the same indentation level. This indentation
|
||||||
|
level should be equal to the longest line of code for each of these comments,
|
||||||
|
without added spacing.
|
||||||
|
|
||||||
#### Lines ####
|
#### Lines ####
|
||||||
|
|
||||||
Do not have trailing whitespace in your lines. Most IDEs check for this nowadays and clean it up for you.
|
Do not leave trailing whitespace on any line. Most IDEs check for this
|
||||||
|
nowadays and clean it up for you.
|
||||||
|
|
||||||
Lines should be 120 characters or less. Please break up lines that are too long into smaller parts, for example at spaces or after opening a brace.
|
Lines should be 120 characters or less. Please break up lines that are too long
|
||||||
|
into smaller parts, for example at spaces or after opening a brace.
|
||||||
|
|
||||||
### Memory Management ###
|
### Memory Management ###
|
||||||
|
|
||||||
|
@ -182,21 +232,52 @@ as `QScopedPointer`, or, less preferably, `QSharedPointer`.
|
||||||
The servatrice database's schema can be found at `servatrice/servatrice.sql`.
|
The servatrice database's schema can be found at `servatrice/servatrice.sql`.
|
||||||
Everytime the schema gets modified, some other steps are due:
|
Everytime the schema gets modified, some other steps are due:
|
||||||
1. Increment the value of `cockatrice_schema_version` in `servatrice.sql`;
|
1. Increment the value of `cockatrice_schema_version` in `servatrice.sql`;
|
||||||
2. Increment the value of `DATABASE_SCHEMA_VERSION` in `servatrice_database_interface.h` accordingly;
|
2. Increment the value of `DATABASE_SCHEMA_VERSION` in
|
||||||
3. Create a new migration file inside the `servatrice/migrations` directory named after the new schema version.
|
`servatrice_database_interface.h` accordingly;
|
||||||
4. Run the `servatrice/check_schema_version.sh` script to ensure everything is fine.
|
3. Create a new migration file inside the `servatrice/migrations` directory
|
||||||
|
named after the new schema version.
|
||||||
|
4. Run the `servatrice/check_schema_version.sh` script to ensure everything is
|
||||||
|
fine.
|
||||||
|
|
||||||
The migration file should include the sql statements needed to migrate the database schema and data from the previous to the new version, and an additional statement that updates `cockatrice_schema_version` to the correct value.
|
The migration file should include the sql statements needed to migrate the
|
||||||
|
database schema and data from the previous to the new version, and an
|
||||||
|
additional statement that updates `cockatrice_schema_version` to the correct
|
||||||
|
value.
|
||||||
|
|
||||||
Ensure that the migration produces the expected effects; e.g. if you add a new column, make sure the migration places it in the same order as servatrice.sql.
|
Ensure that the migration produces the expected effects; e.g. if you add a
|
||||||
|
new column, make sure the migration places it in the same order as
|
||||||
|
servatrice.sql.
|
||||||
|
|
||||||
### Protocol buffer ###
|
### Protocol buffer ###
|
||||||
|
|
||||||
Cockatrice and Servatrice exchange data using binary messages. The syntax of these messages is defined in the `proto` files in the `common/pb` folder. These files defines the way data contained in each message is serialized using Google's [protocol buffer](https://developers.google.com/protocol-buffers/).
|
Cockatrice and Servatrice exchange data using binary messages. The syntax of
|
||||||
Any change to the `proto` file should be taken with caution and tested intensively before being merged, becaus a change to the protocol could make new clients incompatible to the old server and vice versa.
|
these messages is defined in the `proto` files in the `common/pb` folder. These
|
||||||
|
files define the way data contained in each message is serialized using
|
||||||
|
Google's [protocol buffers](https://developers.google.com/protocol-buffers/).
|
||||||
|
Any change to the `proto` files should be taken with caution and tested
|
||||||
|
intensively before being merged, because a change to the protocol could make
|
||||||
|
new clients incompatible to the old server and vice versa.
|
||||||
|
|
||||||
You can find more information on how we use Protobuf on [our wiki!](https://github.com/Cockatrice/Cockatrice/wiki/Client-server-protocol)
|
You can find more information on how we use Protobuf on [our wiki!](
|
||||||
|
https://github.com/Cockatrice/Cockatrice/wiki/Client-server-protocol)
|
||||||
|
|
||||||
|
# Reviewing Pull Requests #
|
||||||
|
|
||||||
|
After you have finished your changes to the project you should put them on a
|
||||||
|
separate branch of your fork on github and open a [pull request](
|
||||||
|
https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/creating-an-issue-or-pull-request
|
||||||
|
).
|
||||||
|
Your code will then be automatically compiled by Travis CI for Linux and macOS,
|
||||||
|
and by Appveyor for Windows. Additionally Travis CI will perform a [Linting
|
||||||
|
check](#formatting-and-continuous-integration-ci). If any issues come up you
|
||||||
|
can check their status at the bottom of the pull request page, click on details
|
||||||
|
to go to the CI website and see the different build logs.
|
||||||
|
|
||||||
|
If your pull request passes our tests and has no merge conflicts, it will be
|
||||||
|
reviewed by our team members. You can then address any requested changes. When
|
||||||
|
all changes have been approved your pull request will be squashed into a single
|
||||||
|
commit and merged into the master branch by a team member. Your change will then
|
||||||
|
be included in the next release 👍
|
||||||
|
|
||||||
# Translations #
|
# Translations #
|
||||||
|
|
||||||
|
@ -209,17 +290,35 @@ Basic workflow for translations:
|
||||||
|
|
||||||
### Using Translations (for developers) ###
|
### Using Translations (for developers) ###
|
||||||
|
|
||||||
All the user-interface strings inside Cockatrice's source code must be written in english.
|
All the user-interface strings inside Cockatrice's source code must be written
|
||||||
Translations to other languages are managed using [Transifex](https://www.transifex.com/projects/p/cockatrice/).
|
in English(US).
|
||||||
|
Translations to other languages are managed using [Transifex](
|
||||||
|
https://www.transifex.com/projects/p/cockatrice/).
|
||||||
|
|
||||||
Adding a new string to translate is as easy as adding the string in the 'tr("")' function, the string will be picked up as translatable automatically and translated as needed.
|
Adding a new string to translate is as easy as adding the string in the
|
||||||
For example setting the text of this label in a way that the string "My name is:" can be translated:
|
'tr("")' function, the string will be picked up as translatable automatically
|
||||||
|
and translated as needed.
|
||||||
|
For example, setting the text of a label in the way that the string
|
||||||
|
`"My name is:"` can be translated:
|
||||||
```c++
|
```c++
|
||||||
nameLabel.setText(tr("My name is:"));
|
nameLabel.setText(tr("My name is:"));
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're about to propose a change that adds or modifies any translatable string in the code, you don't need to take care of adding the new strings to the translation files.
|
To translate a string that would have plural forms you can add the amount to
|
||||||
Every few days, or when a lot of new strings have been added, someone from the development team will take care of extracting all the new strings and adding them to the english translation files and making them available to translators on Transifex.
|
the tr call, also you can add an extra string as a hint for translators:
|
||||||
|
```c++
|
||||||
|
QString message = tr("Everyone draws %n cards", "pop up message", amount);
|
||||||
|
```
|
||||||
|
See [QT's wiki on translations](
|
||||||
|
https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals)
|
||||||
|
|
||||||
|
If you're about to propose a change that adds or modifies any translatable
|
||||||
|
string in the code, you don't need to take care of adding the new strings to
|
||||||
|
the translation files.
|
||||||
|
Every few days, or when a lot of new strings have been added, someone from the
|
||||||
|
development team will take care of extracting all the new strings and adding
|
||||||
|
them to the english translation files and making them available to translators
|
||||||
|
on Transifex.
|
||||||
|
|
||||||
### Maintaining Translations (for maintainers) ###
|
### Maintaining Translations (for maintainers) ###
|
||||||
|
|
||||||
|
@ -253,8 +352,9 @@ cmake .. -DUPDATE_TRANSLATIONS=OFF
|
||||||
```
|
```
|
||||||
Now you are ready to propose your change.
|
Now you are ready to propose your change.
|
||||||
|
|
||||||
Once your change gets merged, Transifex will pick up the modified files automatically (checked every 24 hours)
|
Once your change gets merged, Transifex will pick up the modified files
|
||||||
and update the interface where translators will be able to translate the new strings.
|
automatically (checked every 24 hours) and update the interface where
|
||||||
|
translators will be able to translate the new strings.
|
||||||
|
|
||||||
### Releasing Translations (for maintainers) ###
|
### Releasing Translations (for maintainers) ###
|
||||||
|
|
||||||
|
@ -272,16 +372,20 @@ from Transifex to the source code and vice versa.
|
||||||
|
|
||||||
### Adding Translations (for translators) ###
|
### Adding Translations (for translators) ###
|
||||||
|
|
||||||
As a translator you can help translate the new strings on [Transifex](https://www.transifex.com/projects/p/cockatrice/).
|
As a translator you can help translate the new strings on [Transifex](
|
||||||
Please have a look at the specific [FAQ for translators](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
|
https://www.transifex.com/projects/p/cockatrice/).
|
||||||
|
Please have a look at the specific [FAQ for translators](
|
||||||
|
https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
|
||||||
|
|
||||||
|
|
||||||
# Release Management #
|
# Release Management #
|
||||||
|
|
||||||
### Publishing A New Beta Release ###
|
### Publishing A New Beta Release ###
|
||||||
|
|
||||||
Travis and AppVeyor have been configured to upload files to GitHub Releases whenever a <kbd>tag</kbd> is pushed.<br>
|
Travis and AppVeyor have been configured to upload files to GitHub Releases
|
||||||
Usually, tags are created through publishing a (pre-)release, but there's a way around that.
|
whenever a <kbd>tag</kbd> is pushed.<br>
|
||||||
|
Usually, tags are created through publishing a (pre-)release, but there's a way
|
||||||
|
around that.
|
||||||
|
|
||||||
To trigger Travis and AppVeyor, simply do the following:
|
To trigger Travis and AppVeyor, simply do the following:
|
||||||
```bash
|
```bash
|
||||||
|
@ -302,21 +406,42 @@ $COCKATRICE_REPO - /Location/of/repository/cockatrice.git
|
||||||
With *MAJ.MIN.PATCH* being the NEXT release version!
|
With *MAJ.MIN.PATCH* being the NEXT release version!
|
||||||
```
|
```
|
||||||
|
|
||||||
This will cause a tagged release to be established on the GitHub repository, which will then lead to the upload of binaries. If you use this method, the tags (releases) that you create will be marked as a "Pre-release". The `/latest` URL will not be impacted (for stable release downloads) so that's good.
|
This will cause a tagged release to be established on the GitHub repository,
|
||||||
|
which will then lead to the upload of binaries. If you use this method, the
|
||||||
|
tags (releases) that you create will be marked as a "Pre-release". The
|
||||||
|
`/latest` URL will not be impacted (for stable release downloads) so that's
|
||||||
|
good.
|
||||||
|
|
||||||
If you accidentally push a tag incorrectly (the tag is outdated, you didn't pull in the latest branch accidentally, you named the tag wrong, etc.) you can revoke the tag by doing the following:
|
If you accidentally push a tag incorrectly (the tag is outdated, you didn't
|
||||||
|
pull in the latest branch accidentally, you named the tag wrong, etc.) you can
|
||||||
|
revoke the tag by doing the following:
|
||||||
```bash
|
```bash
|
||||||
git push --delete upstream $TAG_NAME
|
git push --delete upstream $TAG_NAME
|
||||||
git tag -d $TAG_NAME
|
git tag -d $TAG_NAME
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE:** Unfortunately, due to the method of how Travis and AppVeyor work, to publish a stable release you will need to make a copy of the release notes locally and then paste them into the GitHub GUI once the binaries have been uploaded by them. These CI services will automatically overwrite the name of the release (to "Cockatrice $TAG_NAME"), the status of the release (to "Pre-release"), and the release body (to "Beta build of Cockatrice").
|
**NOTE:** Unfortunately, due to the method of how Travis and AppVeyor work, to
|
||||||
|
publish a stable release you will need to make a copy of the release notes
|
||||||
|
locally and then paste them into the GitHub GUI once the binaries have been
|
||||||
|
uploaded by them. These CI services will automatically overwrite the name of
|
||||||
|
the release (to "Cockatrice $TAG_NAME"), the status of the release (to
|
||||||
|
"Pre-release"), and the release body (to "Beta build of Cockatrice").
|
||||||
|
|
||||||
**NOTE 2:** In the first lines of https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt there's an hardcoded version number used when compiling custom (not tagged) versions. While on tagged versions these numbers are overridden by the version numbers coming from the tag title, it's good practice to keep them aligned with the real ones.
|
**NOTE 2:** In the first lines of [CMakeLists.txt](
|
||||||
|
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
|
||||||
|
there's an hardcoded version number used when compiling custom (not tagged)
|
||||||
|
versions. While on tagged versions these numbers are overridden by the version
|
||||||
|
numbers coming from the tag title, it's good practice to keep them aligned with
|
||||||
|
the real ones.
|
||||||
The preferred flow of operation is:
|
The preferred flow of operation is:
|
||||||
* just before a release, update the version number in CMakeLists.txt to "next release version";
|
* just before a release, update the version number in CMakeLists.txt to "next
|
||||||
* tag the release following the previously described syntax in order to get it built by CI;
|
release version";
|
||||||
|
* tag the release following the previously described syntax in order to get it
|
||||||
|
built by CI;
|
||||||
* wait for CI to upload the binaries, double check if everything is in order
|
* wait for CI to upload the binaries, double check if everything is in order
|
||||||
* after the release is complete, update the version number again to "next targeted beta version", typically increasing `PROJECT_VERSION_PATCH` by one.
|
* after the release is complete, update the version number again to "next
|
||||||
|
targeted beta version", typically increasing `PROJECT_VERSION_PATCH` by one.
|
||||||
|
|
||||||
**NOTE 3:** When releasing a new stable version, all the previous beta versions should be deleted. This is needed for Cockatrice to update users of the "beta" release channel to the latest version like other users.
|
**NOTE 3:** When releasing a new stable version, all the previous beta versions
|
||||||
|
should be deleted. This is needed for Cockatrice to update users of the "beta"
|
||||||
|
release channel to the latest version like other users.
|
||||||
|
|
Loading…
Reference in a new issue