diff --git a/bucket.c b/bucket.c
new file mode 100644
index 0000000000000000000000000000000000000000..559c3eb21d9a4a04ff57c050f0d291d7802ae2f9
--- /dev/null
+++ b/bucket.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <mpi.h>
+#include <time.h>
+#include <stdlib.h>
+#include <assert.h>
+
+
+int *create_rand_nums(int num_elements, int max_value) {
+	int *rand_nums = malloc(sizeof(int) * num_elements);
+	assert(rand_nums != NULL);
+	int i;
+	for (i = 0; i < num_elements; ++i) {
+		rand_nums[i] = (rand() % (max_value+1));
+	}
+	return rand_nums;
+}
+
+void swap(int *a, int *b) {
+	int c = *a;
+	*a = *b;
+	*b = c;
+}
+
+void sort(int *arr, int arr_size) {
+	int i, j;
+	for (i = 0; i < arr_size; ++i) {
+		for (j = i+1; j < arr_size; ++j) {
+			if (arr[i] > arr[j]) swap(arr+i, arr+j);
+		}
+	}
+}
+
+int main(int argc, char *argv[]) {
+	int send_tag = 0, head_tag = 1, done_tag = 2, root = 0;
+	if (argc != 2) {
+		fprintf(stderr, "Usage: ./bucket [NUM_ELEMENTS]");
+		exit(1);
+	}
+
+	int num_elements = atoi(argv[1]);
+	int min_value = 0;
+	int max_value = num_elements;
+	srand(time(NULL));
+
+	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);
+
+	double start_time = 0.0, end_time = 0.0;
+	if (world_rank == root) {
+		fprintf(stderr, "Starting root process\n");
+		int i;
+		int *arr = create_rand_nums(num_elements, max_value);
+		assert(world_size > 0);
+		int range = max_value/world_size+1;
+		assert(range > 0);
+
+		fprintf(stdout, "Original Array\n");
+		for (i = 0 ; i < num_elements; ++i) {
+			fprintf(stdout, "%d ", arr[i]);
+		}
+		fprintf(stdout, "\n");
+
+		start_time = MPI_Wtime();
+		int *quantity = malloc(sizeof(int) * world_size);
+		for (i = 0; i < world_size; ++i) quantity[i] = 0;
+		for (i = 0; i < num_elements; ++i) {
+			int index = arr[i] / range;
+			quantity[index]++;
+		}
+
+		for (i = 1; i < world_size; ++i) {
+			MPI_Send(quantity+i, 1, MPI_INT, i, head_tag, MPI_COMM_WORLD);
+			fprintf(stderr, "Sending header %d to process %d\n", quantity[i], i);
+		}
+		fprintf(stderr, "Done sending header\n");
+		int *buck = malloc(sizeof(int) * quantity[root]);
+		int *recv_count = malloc(sizeof(int) * world_size);
+		recv_count[root] = 0;
+		for (i = 0; i+1 < world_size; ++i) {
+			recv_count[i+1] = recv_count[i] + quantity[i];
+		}
+
+		for (i = 0; i < num_elements; ++i) {
+			int index = arr[i] / range;
+			assert(index < world_size);
+			if (index > 0) {
+				MPI_Send(arr+i, 1, MPI_INT, index, send_tag, MPI_COMM_WORLD);
+				fprintf(stderr, "Sending value %d to process %d (%d/%d)\n", arr[i], index, i+1, num_elements);
+			}
+			else {
+				*(buck+recv_count[root]) = arr[i];
+				recv_count[root]++;
+			}
+		}
+		fprintf(stderr, "Done sending array\n");
+		sort(buck, quantity[root]);
+
+		MPI_Status Stat;
+		for (i = 0; i < num_elements; ++i) {
+			if (i < quantity[root]) arr[i] = buck[i];
+			else arr[i] = 0;
+		}
+		for (i = 0; i < num_elements-quantity[root]; ++i) {
+			int el;
+			fprintf(stderr, "Root waiting for messages (%d/%d)\n", i+1, num_elements);
+			MPI_Recv(&el, 1, MPI_INT, MPI_ANY_SOURCE, done_tag, MPI_COMM_WORLD, &Stat);
+
+			int index = Stat.MPI_SOURCE;
+			assert(index > 0);
+			fprintf(stderr, "Received message %d from %d, put at %d\n", el, index, index*range+recv_count[index]);
+			arr[recv_count[index]] = el;
+			recv_count[index]++;
+		}
+		end_time = MPI_Wtime();
+
+		fprintf(stdout, "Sorted Array\n");
+		for (i = 0; i < num_elements; ++i) {
+			fprintf(stdout, "%d", arr[i]);
+			if (i+1 < num_elements)
+				fprintf(stdout, " ");
+		}
+		fprintf(stdout, "\n");
+
+		fprintf(stdout, "Bucket Sort Done in %lfs\n", end_time - start_time);
+		free(arr);
+		free(buck);
+		free(quantity);
+		free(recv_count);
+	}
+	else {
+		int quantity;
+		int i;
+		MPI_Status Stat;
+		fprintf(stderr, "Starting process %d\n", world_rank);
+		fprintf(stderr, "Process %d is waiting for header\n", world_rank);
+		MPI_Recv(&quantity, 1, MPI_INT, 0, head_tag, MPI_COMM_WORLD, &Stat);
+		fprintf(stderr, "Process %d receive header %d\n", world_rank, quantity);
+		int *arr = malloc(sizeof(int) * quantity);
+		for (i = 0; i < quantity; ++i) {
+			fprintf(stderr, "Process %d waiting for value (%d/%d)\n", world_rank, i+1, quantity);
+			MPI_Recv(arr+i, 1, MPI_INT, 0, send_tag, MPI_COMM_WORLD, &Stat);
+			fprintf(stderr, "Process %d receive value %d\n", world_rank, arr[i]);
+		}
+
+		// SORT
+		sort(arr, quantity);
+		// DONE SORT
+		fprintf(stderr, "Sorted array at process %d\n", world_rank);
+		for (i = 0; i < quantity; ++i) {
+			fprintf(stderr, "%d", arr[i]);
+			if (i+1 < quantity) fprintf(stderr, " ");
+			MPI_Send(arr+i, 1, MPI_INT, 0, done_tag, MPI_COMM_WORLD);
+		}
+		fprintf(stderr, "\n");
+		free(arr);
+	}
+
+	MPI_Finalize();
+}
diff --git a/laporan.pdf b/laporan.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..b6a6162bebf7ae75e0beebf99dc6a4c07f95f0b7
Binary files /dev/null and b/laporan.pdf differ
diff --git a/mpi_hostfile b/mpi_hostfile
new file mode 100644
index 0000000000000000000000000000000000000000..0f5cc5d494715512210416a9a428a5ea459c4f1c
--- /dev/null
+++ b/mpi_hostfile
@@ -0,0 +1,6 @@
+localhost
+167.205.35.26
+167.205.35.28
+167.205.35.29
+167.205.35.30
+167.205.35.31