Commit 46f84fab authored by Charron Maxime's avatar Charron Maxime
Browse files

Modifications de l'affichage du temps

parent 7af63f94
......@@ -86,10 +86,6 @@ unsigned char* CPU_calculateDiff(unsigned char* input, unsigned char* search, in
//}
}
}
fflush(stdout);
int* time = convert((float) (omp_get_wtime() - compute_diff));
printf("\rDone in \033[0;31m %d minutes %d seconds \033[0m\n", time[0], time[1]);
return diff;
}
......
unsigned char* GPU_rgb2grey (unsigned char *image, int imgWidth, int imgHeight);
void GPU_saveGreyPicture (unsigned char *image, char* filename, int imgWidth, int imgHeight);
unsigned char* GPU_generateRedBox(int x, int y, unsigned char *image, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight);
unsigned char* GPU_calculateDiff(unsigned char* input, unsigned char* search, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight);
int* GPU_findBestCompability (unsigned char* diff, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight);
\ No newline at end of file
......@@ -9,7 +9,7 @@
unsigned char* GPU_rgb2grey (unsigned char *image, int imgWidth, int imgHeight) {
unsigned char* GPU_SIMPLE_rgb2grey (unsigned char *image, int imgWidth, int imgHeight) {
unsigned char *outputGrey = (unsigned char *) malloc(imgWidth * imgHeight * sizeof(unsigned char));
#pragma omp parallel for
for ( int index = 0; index < imgHeight*imgWidth; index++ ){
......@@ -19,7 +19,7 @@ unsigned char* GPU_rgb2grey (unsigned char *image, int imgWidth, int imgHeight)
}
void GPU_saveGreyPicture (unsigned char *image, char* filename, int imgWidth, int imgHeight) {
void GPU_SIMPLE_saveGreyPicture (unsigned char *image, char* filename, int imgWidth, int imgHeight) {
unsigned char *imageFinal = (unsigned char *)malloc(imgWidth* imgHeight * 3 * sizeof(unsigned char));
#pragma omp parallel for
for ( int index = 0; index < imgHeight*imgWidth; index++ ){
......@@ -30,7 +30,7 @@ void GPU_saveGreyPicture (unsigned char *image, char* filename, int imgWidth, in
savePicture(imageFinal, filename, imgWidth, imgHeight);
}
unsigned char* GPU_generateRedBox(int x, int y, unsigned char *image, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight){
unsigned char* GPU_SIMPLE_generateRedBox(int x, int y, unsigned char *image, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight){
unsigned char *ret = (unsigned char *)malloc(inputImgWidth * inputImgHeight * 3 * sizeof(unsigned char));
memcpy( ret, image, inputImgWidth * inputImgHeight * 3 * sizeof(unsigned char) );
#pragma omp parallel for
......@@ -56,7 +56,7 @@ unsigned char* GPU_generateRedBox(int x, int y, unsigned char *image, int inputI
return ret;
}
unsigned char* GPU_calculateDiff(unsigned char* input, unsigned char* search, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight) {
unsigned char* GPU_SIMPLE_calculateDiff(unsigned char* input, unsigned char* search, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight) {
double compute_diff = omp_get_wtime();
unsigned char *diff = (unsigned char *) malloc( (inputImgWidth-searchImgWidth) * (inputImgHeight-searchImgHeight) * sizeof(unsigned char));
#pragma omp parallel for
......@@ -91,14 +91,10 @@ unsigned char* GPU_calculateDiff(unsigned char* input, unsigned char* search, in
//}
}
}
fflush(stdout);
int* time = convert((float) (omp_get_wtime() - compute_diff));
printf("\rDone in \033[0;31m %d minutes %d seconds \033[0m\n", time[0], time[1]);
return diff;
}
int* GPU_findBestCompability (unsigned char* diff, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight){
int* GPU_SIMPLE_findBestCompability (unsigned char* diff, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight){
int minY = 0;
int minX = 0;
for ( int y = 0; y < inputImgHeight - searchImgHeight; y ++ ) {
......
unsigned char* GPU_SIMPLE_rgb2grey (unsigned char *image, int imgWidth, int imgHeight);
void GPU_SIMPLE_saveGreyPicture (unsigned char *image, char* filename, int imgWidth, int imgHeight);
unsigned char* GPU_SIMPLE_generateRedBox(int x, int y, unsigned char *image, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight);
unsigned char* GPU_SIMPLE_calculateDiff(unsigned char* input, unsigned char* search, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight);
int* GPU_SIMPLE_findBestCompability (unsigned char* diff, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight);
\ No newline at end of file
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
#include "func_all.h"
unsigned char* GPU_v2_rgb2grey (unsigned char *image, int imgWidth, int imgHeight) {
unsigned char *outputGrey = (unsigned char *) malloc(imgWidth * imgHeight * sizeof(unsigned char));
#pragma omp parallel for
for ( int index = 0; index < imgHeight*imgWidth; index++ ){
outputGrey[index] = 0.299*image[index*3] + 0.587*image[index*3 + 1] + 0.114*image[index*3 + 2];
}
return outputGrey;
}
void GPU_v2_saveGreyPicture (unsigned char *image, char* filename, int imgWidth, int imgHeight) {
unsigned char *imageFinal = (unsigned char *)malloc(imgWidth* imgHeight * 3 * sizeof(unsigned char));
#pragma omp parallel for
for ( int index = 0; index < imgHeight*imgWidth; index++ ){
imageFinal[index*3] = image[index];
imageFinal[index*3 + 1] = image[index];
imageFinal[index*3 + 2] = image[index];
}
savePicture(imageFinal, filename, imgWidth, imgHeight);
}
unsigned char* GPU_v2_generateRedBox(int x, int y, unsigned char *image, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight){
unsigned char *ret = (unsigned char *)malloc(inputImgWidth * inputImgHeight * 3 * sizeof(unsigned char));
memcpy( ret, image, inputImgWidth * inputImgHeight * 3 * sizeof(unsigned char) );
#pragma omp parallel for
for ( int i = 0; i < searchImgWidth; i++ ){
ret[y*inputImgWidth*3 + (x+i)*3] = 255;
ret[y*inputImgWidth*3 + (x+i)*3 + 1] = 0;
ret[y*inputImgWidth*3 + (x+i)*3 + 2] = 0;
ret[(y+searchImgHeight)*inputImgWidth*3 + (x+i)*3] = 255;
ret[(y+searchImgHeight)*inputImgWidth*3 + (x+i)*3 + 1] = 0;
ret[(y+searchImgHeight)*inputImgWidth*3 + (x+i)*3 + 2] = 0;
}
#pragma omp parallel for
for ( int i = 0; i < searchImgHeight; i++ ){
ret[(y+i)*inputImgWidth*3 + x*3] = 255;
ret[(y+i)*inputImgWidth*3 + x*3 + 1] = 0;
ret[(y+i)*inputImgWidth*3 + x*3 + 2] = 0;
ret[(y+i)*inputImgWidth*3 + (x+searchImgWidth)*3] = 255;
ret[(y+i)*inputImgWidth*3 + (x+searchImgWidth)*3 + 1] = 0;
ret[(y+i)*inputImgWidth*3 + (x+searchImgWidth)*3 + 2] = 0;
}
return ret;
}
unsigned char* GPU_v2_calculateDiff(unsigned char* input, unsigned char* search, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight) {
double compute_diff = omp_get_wtime();
unsigned char *diff = (unsigned char *) malloc( (inputImgWidth-searchImgWidth) * (inputImgHeight-searchImgHeight) * sizeof(unsigned char));
#pragma omp parallel for
for ( int y = 0; y < inputImgHeight - searchImgHeight; y ++ ) {
for ( int x = 0; x < inputImgWidth - searchImgWidth; x++ ) {
// print the process
printf("(%.0f seconds)\r", (float) (omp_get_wtime() - compute_diff));
fflush(stdout);
int sum = 0;
for ( int yBox = 0; yBox < searchImgHeight; yBox++ ) {
for ( int xBox = 0; xBox < searchImgWidth; xBox++ ) {
//if ( search[ (yBox) * inputImgWidth + xBox] > 0 ) {
// Methode 1 : Avec le carré des différences
//if ( methode_one )
sum += pow(abs(input[ (y+yBox) * inputImgWidth + x + xBox] - search[ yBox * searchImgWidth + xBox]),2);
// Methode 2 : Sans le carré des différences
//else
// sum += abs(input[ (y+yBox) * inputImgWidth + x + xBox] - search[ yBox * searchImgWidth + xBox]);
//}
}
}
//if ( methode_one ) {
// Methode 1
// rapporter la somme entre 0 et 255 ( 255^2 * largeur_goat * hauteur_goat / 255)
double som_moy = sum / 1387200;
diff[y * (inputImgWidth - searchImgWidth) + x] = round(som_moy);
//}else{
// Methode 2
//diff[y * (inputImgWidth - searchImgWidth) + x] = sum / 5440;
//}
}
}
return diff;
}
int* GPU_v2_findBestCompability (unsigned char* diff, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight){
int minY = 0;
int minX = 0;
for ( int y = 0; y < inputImgHeight - searchImgHeight; y ++ ) {
for ( int x = 0; x < inputImgWidth - searchImgWidth; x++ ) {
if (diff[y * (inputImgWidth - searchImgWidth) + x] < diff[minY * (inputImgWidth - searchImgWidth) + minX]){
minY = y;
minX = x;
}
}
}
int* ret = (int*) malloc( 2 * sizeof(int));
ret[0] = minX;
ret[1] = minY;
printf("Best compatibily find at x=%d and y=%d\n",minX, minY);
return ret;
}
\ No newline at end of file
unsigned char* GPU_v2_rgb2grey (unsigned char *image, int imgWidth, int imgHeight);
void GPU_v2_saveGreyPicture (unsigned char *image, char* filename, int imgWidth, int imgHeight);
unsigned char* GPU_v2_generateRedBox(int x, int y, unsigned char *image, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight);
unsigned char* GPU_v2_calculateDiff(unsigned char* input, unsigned char* search, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight);
int* GPU_v2_findBestCompability (unsigned char* diff, int inputImgWidth, int inputImgHeight, int searchImgWidth, int searchImgHeight);
\ No newline at end of file
......@@ -46,13 +46,16 @@ void savePicture (unsigned char *image, char* filename, int imgWidth, int imgHei
printf("Picture saved : %s\n",str);
}
int* convert(float t){
float* convert(float t){
int time = (int) t;
int intpart = (int)t;
float decpart = t - intpart;
int minutes = floor((time / 60) % 60);
int seconds = time % 60;
float seconds = (time % 60)+decpart;
int* tab_time = (int*) malloc( 3 * sizeof(int));
tab_time[0] = minutes;
float* tab_time = (float*) malloc( 2 * sizeof(int));
tab_time[0] = (float)minutes;
tab_time[1] = seconds;
return tab_time;
}
......
......@@ -5,4 +5,4 @@ void free_img(unsigned char*);
void savePicture (unsigned char *image, char* filename, int imgWidth, int imgHeight);
int* convert(float t);
\ No newline at end of file
float* convert(float t);
\ No newline at end of file
......@@ -5,21 +5,21 @@
#include <omp.h>
#include "functions/func_all.h"
#include "functions/func_CPU.h"
#include "functions/func_OPEN.h"
#include "functions/func_OPEN_simple_v1.h"
static const int IS_INPUT = 1;
static const int IS_SEARCH = 0;
int inputImgWidth = -1;
int inputImgWidth = -1;
int inputImgHeight = -1;
int searchImgWidth = -1;
int searchImgWidth = -1;
int searchImgHeight = -1;
int main (int argc, char *argv[])
{
{
double temps_initial = omp_get_wtime();
if (argc != 3)
......@@ -29,64 +29,75 @@ int main (int argc, char *argv[])
}
// Get image paths from arguments.
const char *inputImgPath = argv[1];
const char *searchImgPath = argv[2];
const char *inputImgPath = argv[1];
const char *searchImgPath = argv[2];
// ==================================== Loading input image.
double init_input = omp_get_wtime();
double init_time = omp_get_wtime();
unsigned char *inputImg = load_img(inputImgPath, &inputImgWidth, &inputImgHeight);
printf("Done in \033[0;31m %f \033[0m seconds\n", omp_get_wtime() - init_input);
printf("Done in \033[0;32m %f \033[0m seconds\n", omp_get_wtime() - init_time);
double init_search = omp_get_wtime();
unsigned char *searchImg = load_img(searchImgPath, &searchImgWidth, &searchImgHeight);
printf("Done in \033[0;31m %f \033[0m seconds\n", omp_get_wtime() - init_search);
printf("Done in \033[0;32m %f \033[0m seconds\n", omp_get_wtime() - init_search);
// ============================================================================================================
printf("\n============================================\n");
printf("\n\n============================================\n");
printf("\t\tCPU\n");
printf("============================================\n");
double temps_cpu = omp_get_wtime();
double cpu_time = omp_get_wtime();
// ==================================== Convert input image to grey scale
printf("Convert input to grey\n");
double input_to_grey = omp_get_wtime();
double cpu_input_to_grey_time = omp_get_wtime();
unsigned char *inputGrey = CPU_rgb2grey(inputImg, inputImgWidth, inputImgHeight);
//saveGreyPicture(inputImgHeight, inputImgWidth, inputGrey, "input");
printf("Done in \033[0;31m %f \033[0m seconds\n",omp_get_wtime() - input_to_grey);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - cpu_input_to_grey_time);
// ==================================== Convert search image to grey scale
printf("Convert search to grey\n");
double search_to_grey = omp_get_wtime();
double cpu_search_to_grey_time = omp_get_wtime();
unsigned char *searchGrey = CPU_rgb2grey(searchImg, searchImgWidth, searchImgHeight);
//saveGreyPicture(inputImgHeight, inputImgWidth, inputGrey, "search");
printf("Done in \033[0;31m %f \033[0m seconds\n",omp_get_wtime() - search_to_grey);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - cpu_search_to_grey_time);
// ==================================== Calculate compability
printf("Calculate difference\n");
// time execution managed in the function
printf("Calculate difference\n");
double cpu_compute_diff_time = omp_get_wtime();
unsigned char *diff = CPU_calculateDiff(inputGrey,searchGrey, inputImgWidth, inputImgHeight, searchImgWidth, searchImgHeight);
//saveGreyPicture(inputImgHeight-searchImgHeight, inputImgWidth-searchImgWidth, diff, (char*)"debug_m1");
float* time = convert((float) (omp_get_wtime() - cpu_compute_diff_time));
fflush(stdout);
printf("\rDone in \033[0;32m %d minutes %f seconds \033[0m\n", (int) time[0], time[1]);
// ==================================== Search max compability
double find_compa = omp_get_wtime();
double cpu_find_compa_time = omp_get_wtime();
int* coord = CPU_findBestCompability(diff, inputImgWidth, inputImgHeight, searchImgWidth, searchImgHeight);
printf("Done in \033[0;31m %f \033[0m seconds\n",omp_get_wtime() - find_compa);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - cpu_find_compa_time);
free(diff);
// ==================================== Save a copy of 'inputImg' with the red box
printf("Save picture with red box\n");
double box = omp_get_wtime();
double cpu_box_time = omp_get_wtime();
unsigned char *final_m1 = CPU_generateRedBox(coord[0], coord[1], inputImg, inputImgWidth, inputImgHeight, searchImgWidth, searchImgHeight);
printf("Done in \033[0;31m %f \033[0m seconds\n",omp_get_wtime() - box);
savePicture(final_m1, (char*)"final_m1", inputImgWidth, inputImgHeight);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - cpu_box_time);
savePicture(final_m1, (char*)"final_cpu", inputImgWidth, inputImgHeight);
free(final_m1);
printf("======================================================\n");
printf("The CPU took \033[0;31m %f \033[0m seconds to execute\n", omp_get_wtime() - temps_cpu);
time = convert((float)(omp_get_wtime() - temps_initial));
printf("The CPU took \033[0;32m %d minutes %f seconds \033[0m to execute\n", (int) time[0], time[1]);
free(inputGrey);
free(searchGrey);
free(coord);
......@@ -94,53 +105,125 @@ int main (int argc, char *argv[])
// ============================================================================================================
printf("\n============================================\n");
printf("\t\tOPEN MP\n");
printf("\n\n============================================\n");
printf("\tOPEN MP (version simple)\n");
printf("============================================\n");
double temps_open = omp_get_wtime();
double gpu_time = omp_get_wtime();
// ==================================== Convert input image to grey scale
printf("Convert input to grey\n");
input_to_grey = omp_get_wtime();
double gpu_input_to_grey_time = omp_get_wtime();
inputGrey = GPU_SIMPLE_rgb2grey(inputImg, inputImgWidth, inputImgHeight);
//saveGreyPicture(inputImgHeight, inputImgWidth, inputGrey, "input");
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - gpu_input_to_grey_time);
// ==================================== Convert search image to grey scale
printf("Convert search to grey\n");
double gpu_search_to_grey_time = omp_get_wtime();
searchGrey = GPU_SIMPLE_rgb2grey(searchImg, searchImgWidth, searchImgHeight);
//saveGreyPicture(inputImgHeight, inputImgWidth, inputGrey, "search");
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - gpu_search_to_grey_time);
// ==================================== Calculate compability
printf("Calculate difference\n");
// time execution managed in the function
double gpu_compute_diff_time = omp_get_wtime();
diff = GPU_SIMPLE_calculateDiff(inputGrey,searchGrey, inputImgWidth, inputImgHeight, searchImgWidth, searchImgHeight);
//saveGreyPicture(inputImgHeight-searchImgHeight, inputImgWidth-searchImgWidth, diff, (char*)"debug_m1");
time = convert((float) (omp_get_wtime() - gpu_compute_diff_time));
fflush(stdout);
printf("\rDone in \033[0;32m %d minutes %f seconds \033[0m\n",(int) time[0], time[1]);
// ==================================== Search max compability
double gpu_find_compa_time = omp_get_wtime();
coord = GPU_SIMPLE_findBestCompability(diff, inputImgWidth, inputImgHeight, searchImgWidth, searchImgHeight);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - gpu_find_compa_time);
free(diff);
// ==================================== Save a copy of 'inputImg' with the red box
printf("Save picture with red box\n");
double gpu_box_time = omp_get_wtime();
final_m1 = GPU_SIMPLE_generateRedBox(coord[0], coord[1], inputImg, inputImgWidth, inputImgHeight, searchImgWidth, searchImgHeight);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - gpu_box_time);
savePicture(final_m1, (char*)"final_gpu", inputImgWidth, inputImgHeight);
free(final_m1);
printf("======================================================\n");
time = convert((float)(omp_get_wtime() - gpu_time));
printf("The OPEN MP part took \033[0;32m %d minutes %f seconds \033[0m to execute\n",(int) time[0], time[1]);
/*
// ============================================================================================================
printf("\n\n============================================\n");
printf(" OPEN MP (version légérement plus performante)\n");
printf("============================================\n");
double gpu_time = omp_get_wtime();
// ==================================== Convert input image to grey scale
printf("Convert input to grey\n");
double gpu_input_to_grey_time = omp_get_wtime();
inputGrey = GPU_rgb2grey(inputImg, inputImgWidth, inputImgHeight);
//saveGreyPicture(inputImgHeight, inputImgWidth, inputGrey, "input");
printf("Done in \033[0;31m %f \033[0m seconds\n",omp_get_wtime() - input_to_grey);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - gpu_input_to_grey_time);
// ==================================== Convert search image to grey scale
printf("Convert search to grey\n");
search_to_grey = omp_get_wtime();
double gpu_search_to_grey_time = omp_get_wtime();
searchGrey = GPU_rgb2grey(searchImg, searchImgWidth, searchImgHeight);
//saveGreyPicture(inputImgHeight, inputImgWidth, inputGrey, "search");
printf("Done in \033[0;31m %f \033[0m seconds\n",omp_get_wtime() - search_to_grey);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - gpu_search_to_grey_time);
// ==================================== Calculate compability
printf("Calculate difference\n");
// time execution managed in the function
double gpu_compute_diff_time = omp_get_wtime();
diff = GPU_calculateDiff(inputGrey,searchGrey, inputImgWidth, inputImgHeight, searchImgWidth, searchImgHeight);
//saveGreyPicture(inputImgHeight-searchImgHeight, inputImgWidth-searchImgWidth, diff, (char*)"debug_m1");
time = convert((float) (omp_get_wtime() - gpu_compute_diff_time));
fflush(stdout);
printf("\rDone in \033[0;32m %d minutes %d seconds \033[0m\n", time[0], time[1]);
// ==================================== Search max compability
find_compa = omp_get_wtime();
double gpu_find_compa_time = omp_get_wtime();
coord = GPU_findBestCompability(diff, inputImgWidth, inputImgHeight, searchImgWidth, searchImgHeight);
printf("Done in \033[0;31m %f \033[0m seconds\n",omp_get_wtime() - find_compa);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - gpu_find_compa_time);
free(diff);
// ==================================== Save a copy of 'inputImg' with the red box
printf("Save picture with red box\n");
box = omp_get_wtime();
double gpu_box_time = omp_get_wtime();
final_m1 = GPU_generateRedBox(coord[0], coord[1], inputImg, inputImgWidth, inputImgHeight, searchImgWidth, searchImgHeight);
printf("Done in \033[0;31m %f \033[0m seconds\n",omp_get_wtime() - box);
savePicture(final_m1, (char*)"final_m1", inputImgWidth, inputImgHeight);
printf("Done in \033[0;32m %f \033[0m seconds\n",omp_get_wtime() - gpu_box_time);
savePicture(final_m1, (char*)"final_gpu", inputImgWidth, inputImgHeight);
free(final_m1);
printf("======================================================\n");
printf("The OPEN MP part took \033[0;31m %f \033[0m seconds to execute\n", omp_get_wtime() - temps_open);
time = convert((float)(omp_get_wtime() - temps_initial));
printf("The OPEN MP part took \033[0;32m %d minutes %d seconds \033[0m to execute\n", time[0], time[1]);
*/
......@@ -149,8 +232,8 @@ int main (int argc, char *argv[])
free_img(inputImg);
free_img(searchImg);
int* time = convert((float)(omp_get_wtime() - temps_initial));
printf("The CPU took \033[0;31m %d minutes %d seconds \033[0m to execute\n", time[0], time[1]);
time = convert((float)(omp_get_wtime() - temps_initial));
printf("\n\nThe program took \033[0;32m %d minutes %f seconds \033[0m to execute\n",(int) time[0], time[1]);
printf("Good bye!\n");
return EXIT_SUCCESS;
......
No preview for this file type
Supports Markdown
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