Commit bf14ab14 authored by Arnaud Billon's avatar Arnaud Billon 💬
Browse files

[doc] Rework Developper Guide

Update informations
Used a more compact
Focused on LidarView typical environment
Dropped miscs tips shadowing more important information
parent c6236e84
# LidarView Developer Guide
This documents gather all information needed to build LidarView-based Applications.
1. [LidarView Compilation Overview](#lv-compilation-overview)
1. [Superbuild Overview](#superbuild-overview)
2. [LidarView dependencies](#dependencies)
1. [PCAP library](#pcap-library)
2. [Boost library](#boost-library)
3. [Qt library](#qt-library)
4. [Python](#python)
5. [Python Qt library](#python-qt-library)
6. [Paraview and VTK](#paraview-vtk)
2. [Configure and build instructions](#configure-build)
1. [Windows Instructions](#windows-instructions)
1. [Windows dependencies](#windows-dependencies)
2. [Windows build instructions](#windows-build-instructions)
2. [Linux Instructions](#linux-instructions)
1. [Linux dependencies](#linux-dependencies)
2. [Linux build instructions](#linux-build-instructions)
3. [Apple Instructions](#apple-instructions)
3. [Enabling additional LidarView features](#enabling-additional-lidarview-features)
4. [Packaging instructions](#packaging)
5. [Troubleshooting](#troubleshooting)
1. [Superbuild failure with PCL enabled](#superbuild-failure-with-pcl-enabled)
2. [Using superbuild with system-wide Boost install](#using-superbuild-with-system-wide-boost-install)
This document mirrors some information from the [Installation Guide](Documentation/INSTALLATION.md).
1. [Overview](#lv-compilation-overview)
2. [Configure & Build instructions](#congfigure-build)
0. [Crossplatform](#crossplatform-instructions)
1. [Windows](#windows-instructions)
2. [Ubuntu](#linux-instructions)
3. [Enabling Additional Features](#enabling-additional-lidarview-features)
4. [Incremental Build Instructions](#incremental-build)
4. [Packaging Instructions](#packaging)
4. [Testing Instructions](#testing)
5. [Troubleshooting / FAQ ](#faq-instructions)
## LidarView Compilation Overview <a name="lv-compilation-overview"></a>
LidarView relies primarily on a CMake and the *superbuild* system, it handles the download and compilation of most, if not all, necessary dependencies.
### Superbuild Overview <a name="superbuild-overview"></a>
LidarView can use a cmake *superbuild* to download and compile third party projects that are dependencies of LidarView.
The superbuild is not mandatory but it is recommended as it eases dependency management and build workflow.
The superbuild will **give you the option to use system installations of third party projects instead of compiling them as a superbuild step**.
Some dependencies, on certain platforms, must be compiled by the superbuild, and for them there is no option to use a system version.
However some dependencies, may or may not be supplied by the superbuild for various reasons and must obtained externally on some platform,
see the following sections for per platform instructions.
### LidarView dependencies <a name="dependencies"></a>
The LidarView application and libraries have several external library dependencies. As explained in the [Superbuild Overview](#superbuild-overview), **most of the dependencies will be downloaded and compiled automatically** during the build step. See [Configure and build instructions](#configure-build).
Below is a non-comprehensive list of LidarView's main dependencies:
LidarView is actively Maintained on Windows, Ubuntu18.04, Ubuntu20.04 and OSX.
- **PCAP library** <a name="pcap-library"></a>
## Configure and build instructions <a name="configure-build"></a>
The required pcap version is 1.4.
Pcap is required to support saving captured packets to a file, and reading files containing saved packets.
On Mac/Linux, only *libpcap* is required.
On Windows, we use the *winpcap* project which includes *libpcap* but also includes Windows specific drivers. Since the winpcap project only provides Visual Studio project files, which may be out dated, the superbuild does not attempt to compile winpcap. Instead, a git repository containing headers and precompiled *.lib* and *.dll* files is used. The repository url is https://github.com/patmarion/winpcap.
### Crossplatform Instructions <a name="crossplatform-instructions"></a>
- **Boost library** <a name="boost-library"></a>
**Crossplatform Dependencies and Tools**
The required boost version is 1.66.
Boost is used for threading and synchronization, network communication and handling of the filesystem.
The specific version of the following tools may or may not be available in your OS package manager.
- **Qt library** <a name="qt-library"></a>
- **[Required] CMake 3.18 or 3.19** Get it at <https://cmake.org/>
- **[Recommended] Ninja 1.8.2+** Get it at <https://ninja-build.org/>
Using Ninja is strongly recommended on all platforms to speed up compilation, if you do not wish to use it, make sure to remove the `-GNinja` options from the configuration command.
The required Qt version is 5.12.8
Qt is a desktop widget library that is used to provide user interface elements like windows and menus across the supported platforms Windows, Mac, and Linux.
### Windows Instructions <a name="windows-instructions"></a>
- **Python** <a name="python"></a>
#### Windows specific dependencies <a name="windows-dependencies"></a>
The required Python version is 3.7.
LidarView uses libpython to embed a Python interpreter in the LidarView application.
The core LidarView features are implemented in C++ libraries, and the libraries are wrapped for Python using VTK's Python wrapping tools.
- **Microsoft Visual Studio 14 (2015) Express** Get it at <http://go.microsoft.com/fwlink/?LinkId=615464>
You may need to use the `/layout` option to generate an offline installer : <https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2015/install/create-an-offline-installation-of-visual-studio?view=vs-2015>
Alternatively, link to an ISO image: <https://go.microsoft.com/fwlink/?LinkId=615448>
- **PythonQt** <a name="python-qt-library"></a>
- **Qt 5.12.9** You can download the installer here: <https://download.qt.io/official_releases/qt/5.12/5.12.9/>
To alleviate the need for registration, disconnect your internet connection before starting the installer.
PythonQt version is "patch_8" (see Superbuild/version.txt).
PythonQt is used to build Qt applications using Python.
PythonQt has support for wrapping types derived from Qt objects and VTK objects.
- **[only for packaging]** **NSIS version 3.04 or higher** Get it at <https://nsis.sourceforge.io/Download>
- **Paraview (and VTK)** <a name="paraview-vtk"></a>
#### Windows Guidelines <a name="windows-guidelines"></a>
The required ParaView version is 5.6.1
The required VTK version is 8.2.
The ParaView repository includes VTK, so the superbuild only needs to checkout and build ParaView in order to satisfy both dependencies.
A specific git commit sha1 is used instead of a specific released version.
The commit sha1 is very similar to the release version but with a few commits from the ParaView master branch cherry-picked onto it.
The PythonQtPlugin is a small plugin that initializes the PythonQt library and makes it available in the ParaView Python console.
- **Must Use MSVC build environment Command Prompt (installed with MSVC)**
## Configure and build instructions <a name="configure-build"></a>
It is located at `Windows Start Menu > Visual Studio 2015 > "VS2015 x64 Native Tools Command Prompt"`
If you are unfamilliar with Windows Development, using this Prompt is mandatory for building as it sets appropriate build environement in contrast with a regular cmd.exe Prompt
### Windows Instructions <a name="windows-instructions"></a>
- **Work Directory, source and build paths must be short and close to the root Drive**
#### Windows dependencies <a name="windows-dependencies"></a>
- **CMake version 3.18.2** is confirmed to work, CMake is available at <https://cmake.org/>. Lower versions may not work (especially, avoid versions 3.17.4, 3.18.0 and 3.18.1 which may be incompatible with Paraview and thus LidarView, more info [here](https://gitlab.kitware.com/cmake/cmake/-/merge_requests/5094)), higher versions will work.
- **ninja version 1.8.2** or higher, available at <https://github.com/ninja-build/ninja/releases>. There is no installer for this tool. You must extract the binary *ninja.exe* from *ninja-win.zip* and place it inside a directory that is inside your `%PATH%` environnement variable, such as `C:\Windows`.
- **Microsoft Visual Studio** ***14*** (2015) **Express** ("Desktop"). You can use this link to download the installer: <http://go.microsoft.com/fwlink/?LinkId=615464> This installer is pretty simple (no special options).
- **git**: we recommand using "Git for Windows" available at <https://gitforwindows.org/>.
- **Qt 5.12.9** *(this dependency will be built automatically in the future)*. You can download the installer here: <https://download.qt.io/official_releases/qt/5.12/5.12.9/>. When installing you can keep the suggested installation path. Here is a walkthrough of the installer.
- [only for packaging] **NSIS version 3.04** is confirmed to work, NSIS is available at <https://nsis.sourceforge.io/Download>.
The path to those directories must be short because Windows has limitations on the maximum length of file paths and commands.
Those paths will appear numerous times in the build process, it can quickly reach the maximum limit.
- **The source directory must not be inside the LidarView source code directory**.
Prefer an Architecture like so :
| C:\ | work dir |
|----------|------------|
| C:\src | source dir |
| C:\build | build dir |
- **Moving these directories after configuration or compilation, will break all build environnements and require a full rebuild.**
#### Windows build instructions <a name="windows-build-instructions"></a>
1. Create or go to a work directory where you will save LidarView sources and build directories.
- Note that the configuration command mentions the subdirectory "*Superbuild*" dir inside the source directory and not the source directory itself.
- Note that the CMake `Qt5_DIR` path argument must use **forward slashes** on all platforms (Unix PATH format), MSVC would otherwise take `\\Q` as a build option.
- If you changed the default Qt installation path, you will have to adapt the configuration command.
- Building from scratch can take from 45 minutes to 2 hours depending on your hardware.
- By default `-j` will use all cores on your machine, but you can specify the number of cores to use with `-j N`.
`cd <work-directory>`
* **The path to this directory must be short** because Windows has limitations on the maximum length of file paths and commands. Since this directory name will appear lots of times, it can quickly reach the maximum limit. To overcome this issue, we strongly suggest that you use a directory close to the root of a drive, like `C:\` or `C:\LV\`.
2. Clone LidarView's source code repository to a directory of your chosing, for example:
`git clone <git url to LidarView repository> --recursive LV-src`
* Moving this directoy in the future will break all build environnements that were using it (you will have to redo steps 6. and 7.).
* **The path to this directory must be short** because Windows has limitations on the maximum length of file paths and commands. We strongly suggest that you clone the sources close to the root of a drive, like `C:\LV-src`.
3. Create a new directory to store the build.
`mkdir <work-directory>\LV-build`
* You can use the Windows file explorer to create this directory.
* **This directory must not be inside the LidarView source code directory**.
* **The path to this directory must be short** because Windows has limitations on the maximum length of file paths and commands. We strongly suggest that you use a directory close to the root of a drive, like `C:\LV-build`.
4. Open the appropriate command prompt:
`Windows Start Menu > Visual Studio 2015 > "VS2015 x86 x64 Cross Tools Command Prompt"`
* *Tip*: for the next steps it is possible to copy a command and then paste it inside the prompt with `shift+insert` or `right-click`.
* This command prompt has some environnement variables correctly set to allow building (compiler path, etc).
* Alternatively it is possible to use a standard *cmd.exe* windows prompt (in which Administrative priviledges should not be enabled for security) by entering the command: `"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64`.
5. Inside the command prompt, go to the build directory you created in step 3 by entering the command
`cd /d "<work-directory>\LV-build"`
* Adapt the path to your own build directory created in step 3.
* `/d` allows to `cd` to a directory that is not on the same drive as your current path.
6. Inside the command prompt configure the build by entering:
`cmake <work-directory>\LV-src\Superbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DUSE_SYSTEM_qt5=True -DQt5_DIR="C:/Qt/Qt5.12.9/5.12.9/msvc2015_64/lib/cmake/Qt5"`
* Note that this command mentions the subdirectory "*Superbuild*" inside the source directory and not the source directory itself.
* Note that the `Qt5_DIR` path must use **forward slashes** (like if it was an Unix PATH), because MSVC would otherwise take `\\Q` as a build option.
* If you changed the default Qt installation path, you will have to adapt this command.
* You can use absolute or relative path to point to the LidarView source directory, but be sure to adapt its path to the directory created step 2.
* Should you want to build in RelWithDebInfo mode (in order to attach a debugger for instance), replace "Release" by "RelWithDebInfo".
* This command should show no errors, else they must be fixed.
* To enable additional features, see section [Enabling additional LidarView features](#enabling-additional-lidarview-features).
7. Inside the command prompt, start building by entering:
`ninja`
* Building from scratch can take from 45 minutes to 3 hours depending on your hardware.
* By default ninja will use all cores on your machine, but you can restrict the number of cores used by using `ninja -jN` (replace N by the number of cores to use).
8. If you modified only LidarView and want to rebuild incrementally (incrementally = only modified files are rebuilt), enter the commands:
`cd <work-directory>\LV-build\common-superbuild\lidarview\build`
`ninja install`
* Incremental builds are much faster than the first build.
* It is also possible to run `ninja` from the top of the build directory like you did the first time, but that will take longer because all dependencies are checked for changes.
9. If you checkout a new branch you will need to update all submodules :
`git checkout <branch>`
`git submodule update --init --recursive`
`git clone <git url to LidarView-based app repository> --recursive src`
`mkdir <work-directory>\build`
`cd <work-directory>\build`
`cmake <work-directory>\src\Superbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DUSE_SYSTEM_qt5=True -DQt5_DIR="C:/Qt/Qt5.12.9/5.12.9/msvc2015_64/lib/cmake/Qt5"`
`cmake --build . -j`
`install\bin\<LidarView-based app name>`
---
### Linux build Instructions <a name="linux-instructions"></a>
#### Linux dependencies <a name="linux-dependencies"></a>
The following packages are needed to build on Ubuntu 16.04/18.04/20.04:
#### Linux specific dependencies <a name="linux-dependencies"></a>
- **CMake version 3.12 or higher** is needed. As the `cmake` package available from Ubuntu may not compatible, you need to get a supported version at <https://cmake.org/>.
- build-essential
- git
- flex byacc
- python3.7-dev
- libxext-dev libxt-dev
- libbz2-dev zlib1g-dev
- freeglut3-dev
- pkg-config
- libffi-dev
- patchelf
**Packages**
- The packages from the following one-liner are needed to build on Ubuntu 18.04 and higher:
The Ubuntu 18.04 one-liner is: `sudo apt-get install build-essential git flex byacc python3.7-dev libxext-dev libxt-dev libbz2-dev zlib1g-dev freeglut3-dev pkg-config libffi-dev patchelf`
`sudo apt-get install build-essential flex byacc python3.7-dev libxext-dev libxt-dev libbz2-dev zlib1g-dev freeglut3-dev pkg-config libffi-dev libnl-genl-3-dev libprotobuf-dev protobuf-compiler patchelf libopengl0 liblapack3`
**If using Ubuntu 20.04**
**If using Ubuntu 20.04**
Add this package: `sudo apt-get install libfreetype-dev` (will change in the future)
- libnl-gen1-3-dev
- libprotobuf-dev protobuf-compiler
- libfreetype-dev
**Qt5:**
The Ubuntu 18.04 one-liner is: `sudo apt-get install build-essential git flex byacc python3.7-dev libxext-dev libxt-dev libbz2-dev zlib1g-dev freeglut3-dev pkg-config libffi-dev patchelf libnl-gen1-3-dev libprotobuf-dev protobuf-compiler libfreetype-dev`
- If you system's package manager offers Qt5 with version 5.12.9 or higher (e.g Ubuntu20.04) use:
**Qt5:**
If you system's package manager offers Qt5 with version 5.12.8 or higher use:
- qtbase5-dev qtmultimedia5-dev qttools5-dev qtbase5-private-dev libqt5x11extras5-dev libqt5svg5-dev
On other systems, we recommend you use offline installers from:
- https://download.qt.io/official_releases/qt/5.12/5.12.9/
`qtbase5-dev qtmultimedia5-dev qttools5-dev qtbase5-private-dev libqt5x11extras5-dev libqt5svg5-dev`
**If opencv if enabled:**
- On other systems, we recommend you use offline installers from:
- libavformat-dev libavdevice-dev libavcodec-dev
<https://download.qt.io/official_releases/qt/5.12/5.12.9/>
**Python3.7.10**
#### Linux compiling instructions <a name="linux-build-instructions"></a>
- If you system's package manager offers Python3 with version 3.7 (e.g Ubuntu18.04) use:
1. Clone LidarView's source code repository to a directory of your chosing, for example:
`sudo apt-get install python3.7-dev`
- On other systems, you can get it from this unofficial repository:
`cd <work-directory>`
`sudo add-apt-repository ppa:deadsnakes/ppa && sudo apt-get install python3.7-dev`
`git clone <git url to LidarView repository> --recursive LidarView-source`
- Or build it from [Official Source](https://www.python.org/downloads/release/python-3710/)
Note: Moving this directoy in the future will break all build environnements that were using it (you will have to redo steps 3. and 4.).
`sudo apt-get install build-essentials zlib1g-dev`
`./configure --enable-shared && sudo make install`
2. Create a new directory to store the build.
#### Linux Guidelines <a name="linux-guidelines"></a>
`mkdir <work-directory>/LidarView-build`
- **The source directory must not be inside the LidarView source code directory**.
Prefer an Architecture like so :
| /home/username/lidarview | work dir |
|--------------------------------|------------|
| /home/username/lidarview/src | source dir |
| /home/username/lidarview/build | build dir |
- **Moving these directories after configuration or compilation, will break all build environnements and require a full rebuild.**
* **This directory must not be inside the LidarView-source code directory**
#### Linux compiling instructions <a name="linux-build-instructions"></a>
3. Configure the build by entering:
- Note that the configuration command mentions the subdirectory "*Superbuild*" dir inside the source directory and not the source directory itself.
- If you changed the default Qt installation path, you will have to adapt the configuration command.
- Building from scratch can take from 45 minutes to 2 hours depending on your hardware.
- By default `-j` will use all cores on your machine, but you can specify the number of cores to use with `-j N`.
`cd <work-directory>`
`cd <work-directory>/LidarView-build`
`git clone <git url to LidarView-based app repository> --recursive src`
`cmake <work-directory>/LidarView-source/Superbuild -DCMAKE_BUILD_TYPE=Release`
`mkdir <work-directory>/build`
* By default the generator used is **make**, if you prefer to use **ninja**, add the option `-GNinja`.
* Take note that this command mentions the subdirectory "*Superbuild*" inside the source directory and not the source directory itself.
* To enable additional features, see section [Enabling additional LidarView features](#enabling-additional-lidarview-features).
`cd <work-directory>/build`
4. Start building by entering:
- If you installed Qt5 through your package manager, simply use:
`cmake <work-directory>/src/Superbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DUSE_SYSTEM_qt5=True`
- Otherwise, also specify this path from the offline installer:
`cmake <work-directory>/src/Superbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DUSE_SYSTEM_qt5=True -DQt5_DIR="/opt/Qt/Qt5.12.9/5.12.9/msvc2015_64/lib/cmake/Qt5"`
`cmake --build . -j`
`./install/bin/<LidarView-based app name>`
`make -j<N>`
## Enabling additional LidarView features <a name="enabling-additional-lidarview-features"></a>
* Replace `<N>` by the number of cores you want to use.
**Enable SLAM features**
5. If you modified only LidarView and want to rebuild incrementally (incrementally = only modified files are rebuilt), enter the commands:
- Run or re-run CMake configuration command with these additional parameters:
`-DENABLE_ceres=True -DENABLE_nanoflann=True -DENABLE_pcl=True -DLIDARVIEW_BUILD_SLAM=True`
`cd lidarview-superbuild/common-superbuild/lidarview/build`
- Run or re-run CMake build command.
`cmake --build . -j`
`make install`
More info about SLAM is available at [How to SLAM with LidarView](https://gitlab.kitware.com/keu-computervision/slam/-/blob/master/paraview_wrapping/doc/How_to_SLAM_with_LidarView.md).
* Incremental builds are much faster than the first build.
* It is also possible to run `make` from the top of the build directory like you did the first time, but that will take longer because all dependencies are checked for changes.
6. If you checkout a new branch you will need to update all submodules :
**Enable OpenCV features**
`git checkout <branch>`
- Install OpenCV
Get it at <https://opencv.org/>
On UNIX you can use: `sudo apt-get install libavformat-dev libavdevice-dev libavcodec-dev`
`git submodule update --init --recursive`
- Run or re-run CMake configuration command with these additional parameters:
`-DENABLE_opencv=True`
---
- Run or re-run CMake build command.
`cmake --build . -j`
### Apple Instructions <a name="apple-instructions"></a>
## Incremental build instructions <a name="incremental-build"></a>
## Enabling additional LidarView features <a name="enabling-additional-lidarview-features"></a>
- If you modified only LidarView sources, you may want to build incrementally as it is much faster than the full build command:
The command presented in step Windows/6 or Linux/3 enables basic LidarView features, which use basic dependencies.
To enable more features that rely on additional external libraries, you can use the `ENABLE_<lib>=True` flags. This will download and install the required dependencies, and enable the corresponding LidarView features.
`cd <work-directory>\build\common-superbuild\lidarview\build`
For example, to build LidarView with SLAM support, use `-DENABLE_ceres=True -DENABLE_nanoflann=True -DENABLE_pcl=True -DLIDARVIEW_BUILD_SLAM=True` (more info in [How to SLAM with LidarView](https://gitlab.kitware.com/keu-computervision/slam/-/blob/master/paraview_wrapping/doc/How_to_SLAM_with_LidarView.md)).
`cmake --build . -j --target install`
## Packaging instructions <a name="packaging"></a>
1. Activate the build of tests in the cmake configuration:
- Activate the build of tests through a CMake configuration:
`cd <work-directory>/LidarView-build`
`cd <work-directory>/build`
`cmake . -DBUILD_TESTING=True`
2. Build with the new configuration:
* On Windows : `ninja`
* On Linux : `make`
* Or on all OS : `cmake --build .`
- Build with the new configuration:
3. Package using cpack:
`cmake --build . -j`
`ctest -R cpack`
- Package using cpack:
## Troubleshooting
`ctest`
### Superbuild failure with PCL enabled
## Testing instructions <a name="testing"></a>
Detailed Instructions to run LidarView-based app Tests: [LidarView Testing Guide](LidarPlugin/Testing/README.md).
It has been reported that if PCL is enabled in the superbuild (`-DENABLE_pcl=True`), the superbuild might fail during PCL compilation with a message such as *Internal compiler error*. This bug has been reported on Linux and Windows.
## Troubleshooting / FAQ <a name="faq-instructions"></a>
PCL is a large point cloud processing library. Some binaries are quite heavy, and need to build/link against many targets. Sometimes, depending on your machine, the build process of some of these binaries may reach the maximum allocatable memory limit. When this happens, the OS kills this process, resulting in the *internal compiler error*.
If you run into this problem, you can first try to launch again the superbuild (just re-run the `ninja/make` command, or even easier, use `cmake --build` that will call the right generator for you.
If this fails again, try to build the PCL project with less jobs, then resume the superbuild :
```bash
cd <LidarView-build>/lidarview-superbuild/common-superbuild/pcl/build/
cmake --build . --target --install -- -j1 # build and install PCL project with only 1 job
cd <LidarView-build>
cmake --build . # resume whole superbuild
```
### Using superbuild with system-wide Boost install
Boost libraries can be tricky to install and to manage, especially as they do not rely on CMake, and if different versions are available on your machine. To avoid these problems, the Superbuild will by default install all the Boost components it needs, and will build LidarView against this local Boost installation.
### Superbuild failure with PCL enabled
However, if you have a system-wide installation of Boost on your machine, and especially if you defined some global environment variables related to Boost, the local installation may be hidden or ignored by CMake. Therefore, if your global install lacks some of the required components, or if there is any ABI incompatibility between the global and local libraries, compilation or runtime errors may arise.
Depending on your hardware, when enabling (`-DENABLE_pcl=True`) the superbuild might fail during PCL compilation with an *Internal compiler error* due to intense memory allocation.
To avoid these issues, delete your current superbuild build directory, then to rebuild it, either :
- **Use the superbuild Boost (preferred)** : remove the Boost environment variables during the compilation process (`BOOST_ROOT`, `BOOSTROOT`, `BOOST_LIBARYDIR`, `BOOST_INCLUDEDIR`, ...).
- **Use only your system Boost** : tell the superbuild to use your system-wide install instead of installing a local one by enabling flag `USE_SYSTEM_boost=True` in the CMake superbuild configuration.
To work aroudn this issue you can try:
- Re-running the build command, as successive incremental builds may eventually succeed.
- Lowering the number of compilation jobs in the build command using the `-j N` option.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment