diff --git a/src/change b/src/change
new file mode 100644
index 0000000000000000000000000000000000000000..d78540c6dc330c412b7850b2a1bc976244ee4fc3
Binary files /dev/null and b/src/change differ
diff --git a/src/change.c b/src/change.c
new file mode 100644
index 0000000000000000000000000000000000000000..d77c2d9283c56dc119f69151069ebd4b04f0fe93
--- /dev/null
+++ b/src/change.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+int main() {
+   const int x = 10; //define constant int
+   int *ptr;
+   printf("x = %d\n", x);
+   ptr = &x; //ptr points the variable x
+   *ptr = 15; //Updating through pointer
+   printf("x = %d\n", x);
+}
\ No newline at end of file
diff --git a/src/par b/src/par
new file mode 100644
index 0000000000000000000000000000000000000000..ffe23201b382ad85b854f2b410f170a9d593b6e4
Binary files /dev/null and b/src/par differ
diff --git a/src/parallel.c b/src/parallel.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ae1b646b441709643aa91fd5eb71a7eed9de6d2
--- /dev/null
+++ b/src/parallel.c
@@ -0,0 +1,466 @@
+// serial.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <mpi.h>
+
+#define NMAX 100
+#define DATAMAX 1000
+#define DATAMIN -1000
+
+/* 
+ * Struct Matrix
+ *
+ * Matrix representation consists of matrix data 
+ * and effective dimensions 
+ * */
+typedef struct Matrix {
+	int mat[NMAX][NMAX];	// Matrix cells
+	int row_eff;			// Matrix effective row
+	int col_eff;			// Matrix effective column
+} Matrix;
+
+
+/* 
+ * Procedure init_matrix
+ * 
+ * Initializing newly allocated matrix
+ * Setting all data to 0 and effective dimensions according
+ * to nrow and ncol 
+ * */
+void init_matrix(Matrix *m, int nrow, int ncol) {
+	m->row_eff = nrow;
+	m->col_eff = ncol;
+
+	for (int i = 0; i < m->row_eff; i++) {
+		for (int j = 0; j < m->col_eff; j++) {
+			m->mat[i][j] = 0;
+		}
+	}
+}
+
+
+/* 
+ * Function input_matrix
+ *
+ * Returns a matrix with values from stdin input
+ * */
+Matrix input_matrix(int nrow, int ncol) {
+	Matrix input;
+	init_matrix(&input, nrow, ncol);
+
+	for (int i = 0; i < nrow; i++) {
+		for (int j = 0; j < ncol; j++) {
+			scanf("%d", &input.mat[i][j]);
+		}
+	}
+
+	return input;
+}
+
+
+/* 
+ * Procedure print_matrix
+ * 
+ * Print matrix data
+ * */
+void print_matrix(Matrix *m) {
+	for (int i = 0; i < m->row_eff; i++) {
+		for (int j = 0; j < m->col_eff; j++) {
+			printf("%d ", m->mat[i][j]);
+		}
+		printf("\n");
+	}
+}
+
+
+/* 
+ * Function get_matrix_datarange
+ *
+ * Returns the range between maximum and minimum
+ * element of a matrix
+ * */
+int get_matrix_datarange(Matrix *m) {
+	int max = DATAMIN;
+	int min = DATAMAX;
+	for (int i = 0; i < m->row_eff; i++) {
+		for (int j = 0; j < m->col_eff; j++) {
+			int el = m->mat[i][j];
+			if (el > max) max = el;
+			if (el < min) min = el;
+		}
+	}
+
+	return max - min;
+}
+
+
+/*
+ * Function supression_op
+ *
+ * Returns the sum of intermediate value of special multiplication
+ * operation where kernel[0][0] corresponds to target[row][col]
+ * */
+int supression_op(Matrix *kernel, Matrix *target, int row, int col) {
+	int intermediate_sum = 0;
+	for (int i = 0; i < kernel->row_eff; i++) {
+		for (int j = 0; j < kernel->col_eff; j++) {
+			intermediate_sum += kernel->mat[i][j] * target->mat[row + i][col + j];
+		}
+	}
+
+	return intermediate_sum;
+}
+
+
+/* 
+ * Function convolution
+ *
+ * Return the output matrix of convolution operation
+ * between kernel and target
+ * */
+Matrix convolution(Matrix *kernel, Matrix *target) {
+	Matrix out;
+	int out_row_eff = target->row_eff - kernel->row_eff + 1;
+	int out_col_eff = target->col_eff - kernel->col_eff + 1;
+
+    // printf("kernel row %d",kernel->row_eff);
+    // printf("kernel col %d",kernel->col_eff);
+
+    // printf("out_row_eff %d %d",out_row_eff,out_col_eff);
+	
+	init_matrix(&out, out_row_eff, out_col_eff);
+
+	for (int i = 0; i < out.row_eff; i++) {
+		for (int j = 0; j < out.col_eff; j++) {
+			out.mat[i][j] = supression_op(kernel, target, i, j);
+		}
+	}
+
+	return out;
+}
+
+
+/*
+ * Procedure merge_array
+ *
+ * Merges two subarrays of n with n[left..mid] and n[mid+1..right]
+ * to n itself, with n now ordered ascendingly
+ * */
+void merge_array(int *n, int left, int mid, int right) {
+	int n_left = mid - left + 1;
+	int n_right = right - mid;
+	int iter_left = 0, iter_right = 0, iter_merged = left;
+	int arr_left[n_left], arr_right[n_right];
+
+	for (int i = 0; i < n_left; i++) {
+		arr_left[i] = n[i + left];
+	}
+
+	for (int i = 0; i < n_right; i++) {
+		arr_right[i] = n[i + mid + 1];
+	}
+
+	while (iter_left < n_left && iter_right < n_right) {
+		if (arr_left[iter_left] <= arr_right[iter_right]) {
+			n[iter_merged] = arr_left[iter_left++];
+		} else {
+			n[iter_merged] = arr_right[iter_right++];
+		}
+		iter_merged++;
+	}
+
+	while (iter_left < n_left)  {
+		n[iter_merged++] = arr_left[iter_left++];
+	}
+	while (iter_right < n_right) {
+		n[iter_merged++] = arr_right[iter_right++];
+	} 
+}
+
+
+/* 
+ * Procedure merge_sort
+ *
+ * Sorts array n with merge sort algorithm
+ * */
+void merge_sort(int *n, int left, int right) {
+	if (left < right) {
+		int mid = left + (right - left) / 2;
+
+		merge_sort(n, left, mid);
+		merge_sort(n, mid + 1, right);
+
+		merge_array(n, left, mid, right);
+	}	
+}
+ 
+
+/* 
+ * Procedure print_array
+ *
+ * Prints all elements of array n of size to stdout
+ * */
+void print_array(int *n, int size) {
+	for (int i = 0; i < size; i++ ) printf("%d ", n[i]);
+	printf("\n");
+}
+
+
+/* 
+ * Function get_median
+ *
+ * Returns median of array n of length
+ * */
+int get_median(int *n, int length) {
+	int mid = length / 2;
+	if (length & 1) return n[mid];
+
+	return (n[mid - 1] + n[mid]) / 2;
+}
+
+
+/* 
+ * Function get_floored_mean
+ *
+ * Returns floored mean from an array of integers
+ * */
+long get_floored_mean(int *n, int length) {
+	long sum = 0;
+	for (int i = 0; i < length; i++) {
+		sum += n[i];
+	}
+
+	return sum / length;
+}
+
+
+void distribute(void* data, int count, MPI_Datatype datatype, int root,
+              MPI_Comm communicator) {
+	int world_rank;
+	MPI_Comm_rank(communicator, &world_rank);
+	int world_size;
+	MPI_Comm_size(communicator, &world_size);
+
+	// Procecss 0 --> Kirim matriks inputan 1,2,3 ke prcess 1,2,3
+	// process 1,2,3 -> receive
+	// prcess 0 --> kirim matriks input 4,5,6, ke process 1,2,3
+	
+	if (world_rank == root) {
+	// If we are the root process, send our data to every process
+	int i;
+	for (i = 0; i < world_size; i++) {
+		if (i != world_rank) {
+		MPI_Send(data, count, datatype, i, 0, communicator);
+		}
+	}
+	} else {
+	// If we are a receiver process, receive the data from the root
+	MPI_Recv(data, count, datatype, root, 0, communicator,
+				MPI_STATUS_IGNORE);
+    
+
+	// Ngitung con sama data range		 
+	}
+}
+
+// void init_matrix_kernel() {
+// 	m->row_eff = 2;
+// 	m->col_eff = 2;
+
+// 	m->mat[0][0] = 1;
+//     m->mat[0][1] = 0;
+//     m->mat[1][0] = 0;
+//     m->mat[1][1] = -1;
+// }
+
+// main() driver
+int main() {
+	// OPEN MPI
+	MPI_Init(NULL, NULL);
+
+	int world_rank;
+    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
+    int world_size;
+    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
+
+	const int PING_PONG_LIMIT = 3;
+    printf("HELLO WORLD\n");
+	
+    // 10 / 4 = 2 2 2 (10-6)
+    int kernel_row, kernel_col, target_row, target_col, num_targets;
+	
+	// reads kernel's row and column and initalize kernel matrix from input
+	scanf("%d %d", &kernel_row, &kernel_col);
+	Matrix kernel = input_matrix(kernel_row, kernel_col);
+	
+	// reads number of target matrices and their dimensions.
+	// initialize array of matrices and array of data ranges (int)
+	scanf("%d %d %d", &num_targets, &target_row, &target_col);
+	Matrix* arr_mat = (Matrix*)malloc(num_targets * sizeof(Matrix));
+	Matrix* arr_mat2 = (Matrix*)malloc(num_targets * sizeof(Matrix));
+	int arr_range[num_targets];
+    
+	
+	// read each target matrix, compute their convolution matrices, and compute their data ranges
+	for (int i = 0; i < num_targets; i++) {
+		arr_mat[i] = input_matrix(target_row, target_col);	 
+	}
+
+    print_matrix(&kernel);
+
+	int counter_distribute = 0;
+	int counter_receiver = 0;
+
+    printf("HELLO OPEN MPI\n");
+
+	
+
+    // --------------------------- Create the datatype ----------------------------- //
+    MPI_Datatype mat_MPI;
+    int lengths[3] = { NMAX * NMAX, 1, 1 };
+ 
+    // Calculate displacements
+    // In C, by default padding can be inserted between fields. MPI_Get_address will allow
+    // to get the address of each struct field and calculate the corresponding displacement
+    // relative to that struct base address. The displacements thus calculated will therefore
+    // include padding if any.
+    MPI_Aint displacements[3];
+    Matrix dummy_matrix;
+    MPI_Aint base_address;
+    MPI_Get_address(&dummy_matrix, &base_address);
+    MPI_Get_address(&dummy_matrix.mat, &displacements[0]);
+    MPI_Get_address(&dummy_matrix.row_eff, &displacements[1]);
+    MPI_Get_address(&dummy_matrix.col_eff, &displacements[2]);
+    displacements[0] = MPI_Aint_diff(displacements[0], base_address);
+    displacements[1] = MPI_Aint_diff(displacements[1], base_address);
+    displacements[2] = MPI_Aint_diff(displacements[2], base_address);
+ 
+    MPI_Datatype types[3] = { MPI_INT, MPI_INT, MPI_INT };
+    MPI_Type_create_struct(3, lengths, displacements, types, &mat_MPI);
+    MPI_Type_commit(&mat_MPI);
+     
+    // --------------------------- End Create the datatype ----------------------------- //
+
+	// Distribusi matriks input ke process-process
+	
+    /*
+    0 1 2 3 4 5 6 7 8 9
+
+    0 1 2
+
+    3 4 5
+
+    6 7 8
+
+    9
+
+    */ 
+
+
+
+
+    int root = 0;
+
+	if (world_rank == root) {
+			// If we are the root process, send our data to every process
+            int i;
+            for (i = 0; i < world_size; i++) {
+                if (i != world_rank) {
+                    MPI_Send(&arr_mat[counter_distribute], 1, mat_MPI, i, 0, MPI_COMM_WORLD);
+                    counter_distribute++;
+                }
+            }
+            print_matrix(&kernel);
+			printf("PRocess 0 distribute\n ");
+			
+		} else {
+			printf("PRocess selain 0  distribute %d \n", world_rank);
+			// If we are a receiver process, receive the data from the root
+            Matrix recv_data;
+            MPI_Recv(&recv_data, 1, mat_MPI, root, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+            print_matrix(&recv_data);
+
+			printf("HASILLL\n");
+			arr_mat2[counter_receiver] = convolution(&m, &recv_data);
+            
+            print_matrix(&arr_mat2[counter_receiver]);
+			arr_range[counter_receiver] = get_matrix_datarange(&arr_mat2[counter_receiver]);
+
+			counter_receiver++;
+		}
+
+    while (counter_distribute < PING_PONG_LIMIT){
+        // distribute(arr_mat[counter_distribute],1,mat_MPI,0, MPI_COMM_WORLD)
+		printf("Counter dis %d \n", counter_distribute);
+		if (world_rank == root) {
+			// If we are the root process, send our data to every process
+            int i;
+            for (i = 0; i < world_size; i++) {
+                if (i != world_rank) {
+                    MPI_Send(&arr_mat[counter_distribute], 1, mat_MPI, i, 0, MPI_COMM_WORLD);
+                    counter_distribute++;
+                }
+            }
+            print_matrix(&kernel);
+			printf("PRocess 0 distribute\n ");
+			
+		} else {
+			printf("PRocess selain 0  distribute %d \n", world_rank);
+			// If we are a receiver process, receive the data from the root
+            Matrix recv_data;
+            MPI_Recv(&recv_data, 1, mat_MPI, root, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+            print_matrix(&recv_data);
+            Matrix m;
+            m.row_eff = 2;
+            m.col_eff = 2;
+
+            m.mat[0][0] = 1;
+            m.mat[0][1] = 0;
+            m.mat[1][0] = 0;
+            m.mat[1][1] = -1;
+            print_matrix(&m);
+
+			printf("HASILLL\n");
+			arr_mat2[counter_receiver] = convolution(&m, &recv_data);
+            
+            print_matrix(&arr_mat2[counter_receiver]);
+			arr_range[counter_receiver] = get_matrix_datarange(&arr_mat2[counter_receiver]);
+
+			counter_receiver++;
+		}
+    }
+
+	MPI_Finalize();
+    
+
+    // // Print hasil
+	// for (int i = 0; i < num_targets; i++) {
+	// 	printf("\nMATRIX CONV %d",i);
+	// 	print_matrix(arr_mat2); 
+	// }
+
+	// // sort the data range array
+	// printf("\n");
+	// print_array(arr_range,num_targets);
+	// merge_sort(arr_range, 0, num_targets - 1);
+	
+	// int median = get_median(arr_range, num_targets);	
+	// int floored_mean = get_floored_mean(arr_range, num_targets); 
+
+	// // print the min, max, median, and floored mean of data range array
+	// printf("%d\n%d\n%d\n%d\n", 
+	// 		arr_range[0], 
+	// 		arr_range[num_targets - 1], 
+	// 		median, 
+	// 		floored_mean);
+
+    
+	
+    // START OPEN MP	
+	
+	
+    
+	
+	return 0;
+}
diff --git a/src/person.c b/src/person.c
new file mode 100644
index 0000000000000000000000000000000000000000..3b22c3f717e245676c6098c33f3a64fd623256a3
--- /dev/null
+++ b/src/person.c
@@ -0,0 +1,150 @@
+/**
+ * @author RookieHPC
+ * @brief Original source code at https://www.rookiehpc.com/mpi/docs/mpi_type_create_struct.php
+ **/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mpi.h>
+ 
+/**
+ * @brief Illustrates how to create an indexed MPI datatype.
+ * @details This program is meant to be run with 2 processes: a sender and a
+ * receiver. These two MPI processes will exchange a message made of a
+ * structure representing a person.
+ *
+ * Structure of a person:
+ * - age: int
+ * - height: double
+ * - name: char[10]
+ *
+ * How to represent such a structure with an MPI struct:
+ *   
+ *           +----------------- displacement for
+ *           |        block 2: sizeof(int) + sizeof(double)
+ *           |               (+ potential padding)
+ *           |                         |
+ *           +----- displacement for   |
+ *           |    block 2: sizeof(int) |
+ *           |   (+ potential padding) |
+ *           |            |            |
+ *  displacement for      |            |
+ *    block 1: 0          |            |
+ * (+ potential padding)  |            |
+ *           |            |            |
+ *           V            V            V
+ *           +------------+------------+------------+
+ *           |     age    |   height   |    name    |
+ *           +------------+------------+------------+
+ *            <----------> <----------> <---------->
+ *               block 1      block 2      block 3
+ *              1 MPI_INT  1 MPI_DOUBLE  10 MPI_CHAR
+ **/
+ 
+// struct person_t
+// {
+//     int age;
+//     double height;
+//     char name[10];
+// };
+
+#define NMAX 100
+#define DATAMAX 1000
+#define DATAMIN -1000
+
+typedef struct Matrix {
+	int mat[NMAX][NMAX];	// Matrix cells
+	int row_eff;			// Matrix effective row
+	int col_eff;			// Matrix effective column
+} Matrix;
+
+void init_matrix(Matrix *m, int nrow, int ncol) {
+	m->row_eff = nrow;
+	m->col_eff = ncol;
+
+	for (int i = 0; i < m->row_eff; i++) {
+		for (int j = 0; j < m->col_eff; j++) {
+			m->mat[i][j] = 3;
+		}
+	}
+}
+
+void print_matrix(Matrix *m) {
+	for (int i = 0; i < m->row_eff; i++) {
+		for (int j = 0; j < m->col_eff; j++) {
+			printf("%d ", m->mat[i][j]);
+		}
+		printf("\n");
+	}
+}
+ 
+int main(int argc, char* argv[])
+{
+    MPI_Init(&argc, &argv);
+ 
+    // Get the number of processes and check only 2 processes are used
+    int size;
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+    if(size != 2)
+    {
+        printf("This application is meant to be run with 2 processes.\n");
+        MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
+    }
+ 
+    MPI_Datatype mat_MPI;
+    int lengths[3] = { NMAX * NMAX, 1, 1 };
+ 
+    // Calculate displacements
+    // In C, by default padding can be inserted between fields. MPI_Get_address will allow
+    // to get the address of each struct field and calculate the corresponding displacement
+    // relative to that struct base address. The displacements thus calculated will therefore
+    // include padding if any.
+    MPI_Aint displacements[3];
+    Matrix dummy_matrix;
+    MPI_Aint base_address;
+    MPI_Get_address(&dummy_matrix, &base_address);
+    MPI_Get_address(&dummy_matrix.mat, &displacements[0]);
+    MPI_Get_address(&dummy_matrix.row_eff, &displacements[1]);
+    MPI_Get_address(&dummy_matrix.col_eff, &displacements[2]);
+    displacements[0] = MPI_Aint_diff(displacements[0], base_address);
+    displacements[1] = MPI_Aint_diff(displacements[1], base_address);
+    displacements[2] = MPI_Aint_diff(displacements[2], base_address);
+ 
+    MPI_Datatype types[3] = { MPI_INT, MPI_INT, MPI_INT };
+    MPI_Type_create_struct(3, lengths, displacements, types, &mat_MPI);
+    MPI_Type_commit(&mat_MPI);
+ 
+    // Get my rank and do the corresponding job
+    enum rank_roles { SENDER, RECEIVER };
+    int my_rank;
+    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
+    switch(my_rank)
+    {
+        case SENDER:
+        {
+            // Send the message
+            Matrix buffer;
+            
+            buffer.row_eff = 4;
+            buffer.col_eff = 4;
+            init_matrix(&buffer,buffer.row_eff,buffer.col_eff);
+            printf("MPI process %d sends person:\n\t- ROW = %d\n\t- COL = %d\n\t-\n", my_rank, buffer.row_eff, buffer.row_eff);
+            MPI_Send(&buffer, 1, mat_MPI, RECEIVER, 0, MPI_COMM_WORLD);
+            break;
+        }
+        case RECEIVER:
+        {
+            // Receive the message
+            Matrix received;
+            MPI_Recv(&received, 1, mat_MPI, SENDER, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
+            printf("MPI process %d received person:\n\t- ROW = %d\n\t- COL = %d\n\t-\n", my_rank, received.row_eff, received.row_eff);
+            print_matrix(&received);
+            break;
+        }
+    }
+ 
+    MPI_Finalize();
+ 
+    return EXIT_SUCCESS;
+}
diff --git a/src/serial b/src/serial
new file mode 100644
index 0000000000000000000000000000000000000000..8405e5cb485403663d575d0118b9b239f66a299e
Binary files /dev/null and b/src/serial differ
diff --git a/src/serial.c b/src/serial.c
index 94b6f1640582724a735f427ae379feea3d2bfbb4..0b574684aec72468c208e79a7ebc45fb5be79017 100644
--- a/src/serial.c
+++ b/src/serial.c
@@ -237,6 +237,8 @@ int main() {
 	// reads kernel's row and column and initalize kernel matrix from input
 	scanf("%d %d", &kernel_row, &kernel_col);
 	Matrix kernel = input_matrix(kernel_row, kernel_col);
+
+	
 	
 	// reads number of target matrices and their dimensions.
 	// initialize array of matrices and array of data ranges (int)
@@ -248,10 +250,23 @@ int main() {
 	for (int i = 0; i < num_targets; i++) {
 		arr_mat[i] = input_matrix(target_row, target_col);
 		arr_mat[i] = convolution(&kernel, &arr_mat[i]);
-		arr_range[i] = get_matrix_datarange(&arr_mat[i]); 
+		arr_range[i] = get_matrix_datarange(&arr_mat[i]);
+
+		printf("\nhmmmm\n");
+		print_matrix(&arr_mat[i]); 
+	}
+
+	// Print hasil
+	for (int i = 0; i < num_targets; i++) {
+		printf("\nMATRIX CONV %d",i);
+		printf("\nArray mat\n");
+		print_matrix(&arr_mat[i]); 
 	}
+	
 
 	// sort the data range array
+	printf("\n");
+	print_array(arr_range,num_targets);
 	merge_sort(arr_range, 0, num_targets - 1);
 	
 	int median = get_median(arr_range, num_targets);