#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void AlltoAll(char *sendbuf, char *recvbuf, int count, MPI_Comm comm) {
int world_rank, world_size;
MPI_Comm_rank(comm, &world_rank);
MPI_Comm_size(comm, &world_size);
// Calculate the size of each message
int message_size = count / world_size;
// Allocate memory for receiving data
char *temp_recvbuf
= (char *)malloc(count
* sizeof(char));
// Scatter data to other processes using point-to-point communication
for (int i = 0; i < world_size; i++) {
if (i != world_rank) {
MPI_Send(sendbuf + i * message_size, message_size, MPI_CHAR, i, 0, comm);
}
}
// Receive data from other processes using point-to-point communication
for (int i = 0; i < world_size; i++) {
if (i != world_rank) {
MPI_Recv(temp_recvbuf + i * message_size, message_size, MPI_CHAR, i, 0, comm, MPI_STATUS_IGNORE);
}
}
// Copy received data to receive buffer
memcpy(recvbuf
, temp_recvbuf
, count
* sizeof(char));
}
void Allgather(char *sendbuf, int sendcount, char *recvbuf, int recvcount, MPI_Comm comm) {
int world_rank, world_size;
MPI_Comm_rank(comm, &world_rank);
MPI_Comm_size(comm, &world_size);
int total_send_count = sendcount * world_size;
// Allocate memory for temporary receive buffer
char *temp_recvbuf
= (char *)malloc(total_send_count
* sizeof(char));
// Send data to all other processes
for (int i = 0; i < world_size; i++) {
if (i != world_rank) {
MPI_Send(sendbuf, sendcount, MPI_CHAR, i, 0, comm);
}
}
// Copy own data to receive buffer
memcpy(recvbuf
+ world_rank
* recvcount
, sendbuf
, sendcount
);
// Receive data from all other processes
for (int i = 0; i < world_size; i++) {
if (i != world_rank) {
MPI_Recv(temp_recvbuf + i * recvcount, recvcount, MPI_CHAR, i, 0, comm, MPI_STATUS_IGNORE);
}
}
// Copy received data to receive buffer
for (int i = 0; i < world_size; i++) {
if (i != world_rank) {
memcpy(recvbuf
+ i
* recvcount
, temp_recvbuf
+ i
* recvcount
, recvcount
); }
}
}
void Allgatherv(char *sendbuf, int sendcount, char *recvbuf, int *recvcounts, int *displs, MPI_Comm comm) {
int world_rank, world_size;
MPI_Comm_rank(comm, &world_rank);
MPI_Comm_size(comm, &world_size);
// Determine the total size of data to be received
int total_recv_count = 0;
for (int i = 0; i < world_size; ++i) {
total_recv_count += recvcounts[i];
}
// Allocate memory for temporary receive buffer
char *temp_recvbuf
= (char *)malloc(total_recv_count
* sizeof(char));
// Receive data from each process and store in temporary buffer
for (int i = 0; i < world_size; ++i) {
MPI_Recv(temp_recvbuf + displs[i], recvcounts[i], MPI_CHAR, i, 0, comm, MPI_STATUS_IGNORE);
}
// Copy data from temporary buffer to final receive buffer
memcpy(recvbuf
, temp_recvbuf
, total_recv_count
* sizeof(char));
// Free temporary buffer
}
void my_Alltoallv(char *sendbuf, int *sendcounts, int *sdispls, char *recvbuf, int *recvcounts, int *rdispls, MPI_Comm comm) {
int world_rank, world_size;
MPI_Comm_rank(comm, &world_rank);
MPI_Comm_size(comm, &world_size);
// Calculate total send and receive counts
int total_send_count = 0;
int total_recv_count = 0;
for (int i = 0; i < world_size; i++) {
total_send_count += sendcounts[i];
total_recv_count += recvcounts[i];
}
// Allocate memory for temporary send and receive buffers
char *temp_sendbuf
= (char *)malloc(total_send_count
* sizeof(char)); char *temp_recvbuf
= (char *)malloc(total_recv_count
* sizeof(char));
// Copy data to temporary send buffer based on send counts and displacements
int send_offset = 0;
for (int i = 0; i < world_size; i++) {
memcpy(temp_sendbuf
+ send_offset
, sendbuf
+ sdispls
[i
], sendcounts
[i
]); send_offset += sendcounts[i];
}
// Exchange data with all other processes using point-to-point communication
for (int i = 0; i < world_size; i++) {
if (i != world_rank) {
// Send data to process i
MPI_Sendrecv(temp_sendbuf + sdispls[i], sendcounts[i], MPI_CHAR, i, 0,
temp_recvbuf + rdispls[i], recvcounts[i], MPI_CHAR, i, 0, comm, MPI_STATUS_IGNORE);
}
}
// Copy data from temporary receive buffer to receive buffer based on receive counts and displacements
int recv_offset = 0;
for (int i = 0; i < world_size; i++) {
memcpy(recvbuf
+ rdispls
[i
], temp_recvbuf
+ recv_offset
, recvcounts
[i
]); recv_offset += recvcounts[i];
}
// Free temporary buffers
}
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int world_rank, world_size;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
// Input data from user
char sendbuf[100]; // Assuming a maximum of 100 characters
if (world_rank == 0) {
printf("Enter data to send: "); }
// AlltoAll
char recvbuf_alltoall[100 * world_size];
AlltoAll(sendbuf, recvbuf_alltoall, 100, MPI_COMM_WORLD);
if (world_rank == 0) {
printf("AlltoAll received data: %s\n", recvbuf_alltoall
); }
// Allgather
char recvbuf_allgather[100 * world_size];
Allgather
(sendbuf
, strlen(sendbuf
) + 1, recvbuf_allgather
, strlen(sendbuf
) + 1, MPI_COMM_WORLD
); if (world_rank == 0) {
printf("Allgather received data: %s\n", recvbuf_allgather
); }
// Allgatherv
int *recvcounts_allgatherv
= (int *)malloc(world_size
* sizeof(int)); int *displs_allgatherv
= (int *)malloc(world_size
* sizeof(int)); int sendcount_allgatherv
= strlen(sendbuf
) + 1; for (int i = 0; i < world_size; ++i) {
recvcounts_allgatherv
[i
] = strlen(sendbuf
) + 1; displs_allgatherv
[i
] = i
* (strlen(sendbuf
) + 1); }
char recvbuf_allgatherv[100 * world_size];
Allgatherv(sendbuf, sendcount_allgatherv, recvbuf_allgatherv, recvcounts_allgatherv, displs_allgatherv, MPI_COMM_WORLD);
if (world_rank == 0) {
printf("Allgatherv received data: %s\n", recvbuf_allgatherv
); }
// Alltoallv
int sendcounts_alltoallv[world_size];
int recvcounts_alltoallv[world_size];
int sdispls_alltoallv[world_size];
int rdispls_alltoallv[world_size];
for (int i = 0; i < world_size; i++) {
sendcounts_alltoallv
[i
] = strlen(sendbuf
) + 1; recvcounts_alltoallv
[i
] = strlen(sendbuf
) + 1; sdispls_alltoallv
[i
] = i
* (strlen(sendbuf
) + 1); rdispls_alltoallv
[i
] = i
* (strlen(sendbuf
) + 1); }
char recvbuf_alltoallv[100 * world_size];
my_Alltoallv(sendbuf, sendcounts_alltoallv, sdispls_alltoallv, recvbuf_alltoallv, recvcounts_alltoallv, rdispls_alltoallv, MPI_COMM_WORLD);
if (world_rank == 0) {
printf("Alltoallv received data: %s\n", recvbuf_alltoallv
); }
// Finalize MPI
MPI_Finalize();
return 0;
}
I2luY2x1ZGUgPG1waS5oPgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8c3RyaW5nLmg+Cgp2b2lkIEFsbHRvQWxsKGNoYXIgKnNlbmRidWYsIGNoYXIgKnJlY3ZidWYsIGludCBjb3VudCwgTVBJX0NvbW0gY29tbSkgewogICAgaW50IHdvcmxkX3JhbmssIHdvcmxkX3NpemU7CiAgICBNUElfQ29tbV9yYW5rKGNvbW0sICZ3b3JsZF9yYW5rKTsKICAgIE1QSV9Db21tX3NpemUoY29tbSwgJndvcmxkX3NpemUpOwoKICAgIC8vIENhbGN1bGF0ZSB0aGUgc2l6ZSBvZiBlYWNoIG1lc3NhZ2UKICAgIGludCBtZXNzYWdlX3NpemUgPSBjb3VudCAvIHdvcmxkX3NpemU7CgogICAgLy8gQWxsb2NhdGUgbWVtb3J5IGZvciByZWNlaXZpbmcgZGF0YQogICAgY2hhciAqdGVtcF9yZWN2YnVmID0gKGNoYXIgKiltYWxsb2MoY291bnQgKiBzaXplb2YoY2hhcikpOwoKICAgIC8vIFNjYXR0ZXIgZGF0YSB0byBvdGhlciBwcm9jZXNzZXMgdXNpbmcgcG9pbnQtdG8tcG9pbnQgY29tbXVuaWNhdGlvbgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCB3b3JsZF9zaXplOyBpKyspIHsKICAgICAgICBpZiAoaSAhPSB3b3JsZF9yYW5rKSB7CiAgICAgICAgICAgIE1QSV9TZW5kKHNlbmRidWYgKyBpICogbWVzc2FnZV9zaXplLCBtZXNzYWdlX3NpemUsIE1QSV9DSEFSLCBpLCAwLCBjb21tKTsKICAgICAgICB9CiAgICB9CgogICAgLy8gUmVjZWl2ZSBkYXRhIGZyb20gb3RoZXIgcHJvY2Vzc2VzIHVzaW5nIHBvaW50LXRvLXBvaW50IGNvbW11bmljYXRpb24KICAgIGZvciAoaW50IGkgPSAwOyBpIDwgd29ybGRfc2l6ZTsgaSsrKSB7CiAgICAgICAgaWYgKGkgIT0gd29ybGRfcmFuaykgewogICAgICAgICAgICBNUElfUmVjdih0ZW1wX3JlY3ZidWYgKyBpICogbWVzc2FnZV9zaXplLCBtZXNzYWdlX3NpemUsIE1QSV9DSEFSLCBpLCAwLCBjb21tLCBNUElfU1RBVFVTX0lHTk9SRSk7CiAgICAgICAgfSAKICAgIH0KCiAgICAvLyBDb3B5IHJlY2VpdmVkIGRhdGEgdG8gcmVjZWl2ZSBidWZmZXIKICAgIG1lbWNweShyZWN2YnVmLCB0ZW1wX3JlY3ZidWYsIGNvdW50ICogc2l6ZW9mKGNoYXIpKTsKCiAgICBmcmVlKHRlbXBfcmVjdmJ1Zik7Cn0KCnZvaWQgQWxsZ2F0aGVyKGNoYXIgKnNlbmRidWYsIGludCBzZW5kY291bnQsIGNoYXIgKnJlY3ZidWYsIGludCByZWN2Y291bnQsIE1QSV9Db21tIGNvbW0pIHsKICAgIGludCB3b3JsZF9yYW5rLCB3b3JsZF9zaXplOwogICAgTVBJX0NvbW1fcmFuayhjb21tLCAmd29ybGRfcmFuayk7CiAgICBNUElfQ29tbV9zaXplKGNvbW0sICZ3b3JsZF9zaXplKTsKCiAgICBpbnQgdG90YWxfc2VuZF9jb3VudCA9IHNlbmRjb3VudCAqIHdvcmxkX3NpemU7CgogICAgLy8gQWxsb2NhdGUgbWVtb3J5IGZvciB0ZW1wb3JhcnkgcmVjZWl2ZSBidWZmZXIKICAgIGNoYXIgKnRlbXBfcmVjdmJ1ZiA9IChjaGFyICopbWFsbG9jKHRvdGFsX3NlbmRfY291bnQgKiBzaXplb2YoY2hhcikpOwoKICAgIC8vIFNlbmQgZGF0YSB0byBhbGwgb3RoZXIgcHJvY2Vzc2VzCiAgICBmb3IgKGludCBpID0gMDsgaSA8IHdvcmxkX3NpemU7IGkrKykgewogICAgICAgIGlmIChpICE9IHdvcmxkX3JhbmspIHsKICAgICAgICAgICAgTVBJX1NlbmQoc2VuZGJ1Ziwgc2VuZGNvdW50LCBNUElfQ0hBUiwgaSwgMCwgY29tbSk7CiAgICAgICAgfQogICAgfQoKICAgIC8vIENvcHkgb3duIGRhdGEgdG8gcmVjZWl2ZSBidWZmZXIKICAgIG1lbWNweShyZWN2YnVmICsgd29ybGRfcmFuayAqIHJlY3Zjb3VudCwgc2VuZGJ1Ziwgc2VuZGNvdW50KTsKCiAgICAvLyBSZWNlaXZlIGRhdGEgZnJvbSBhbGwgb3RoZXIgcHJvY2Vzc2VzCiAgICBmb3IgKGludCBpID0gMDsgaSA8IHdvcmxkX3NpemU7IGkrKykgewogICAgICAgIGlmIChpICE9IHdvcmxkX3JhbmspIHsKICAgICAgICAgICAgTVBJX1JlY3YodGVtcF9yZWN2YnVmICsgaSAqIHJlY3Zjb3VudCwgcmVjdmNvdW50LCBNUElfQ0hBUiwgaSwgMCwgY29tbSwgTVBJX1NUQVRVU19JR05PUkUpOwogICAgICAgIH0KICAgIH0KCiAgICAvLyBDb3B5IHJlY2VpdmVkIGRhdGEgdG8gcmVjZWl2ZSBidWZmZXIKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgd29ybGRfc2l6ZTsgaSsrKSB7CiAgICAgICAgaWYgKGkgIT0gd29ybGRfcmFuaykgewogICAgICAgICAgICBtZW1jcHkocmVjdmJ1ZiArIGkgKiByZWN2Y291bnQsIHRlbXBfcmVjdmJ1ZiArIGkgKiByZWN2Y291bnQsIHJlY3Zjb3VudCk7CiAgICAgICAgfQogICAgfQoKICAgIGZyZWUodGVtcF9yZWN2YnVmKTsKfQoKdm9pZCBBbGxnYXRoZXJ2KGNoYXIgKnNlbmRidWYsIGludCBzZW5kY291bnQsIGNoYXIgKnJlY3ZidWYsIGludCAqcmVjdmNvdW50cywgaW50ICpkaXNwbHMsIE1QSV9Db21tIGNvbW0pIHsKICAgIGludCB3b3JsZF9yYW5rLCB3b3JsZF9zaXplOwogICAgTVBJX0NvbW1fcmFuayhjb21tLCAmd29ybGRfcmFuayk7CiAgICBNUElfQ29tbV9zaXplKGNvbW0sICZ3b3JsZF9zaXplKTsKCiAgICAvLyBEZXRlcm1pbmUgdGhlIHRvdGFsIHNpemUgb2YgZGF0YSB0byBiZSByZWNlaXZlZAogICAgaW50IHRvdGFsX3JlY3ZfY291bnQgPSAwOwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCB3b3JsZF9zaXplOyArK2kpIHsKICAgICAgICB0b3RhbF9yZWN2X2NvdW50ICs9IHJlY3Zjb3VudHNbaV07CiAgICB9CgogICAgLy8gQWxsb2NhdGUgbWVtb3J5IGZvciB0ZW1wb3JhcnkgcmVjZWl2ZSBidWZmZXIKICAgIGNoYXIgKnRlbXBfcmVjdmJ1ZiA9IChjaGFyICopbWFsbG9jKHRvdGFsX3JlY3ZfY291bnQgKiBzaXplb2YoY2hhcikpOwoKICAgIC8vIFJlY2VpdmUgZGF0YSBmcm9tIGVhY2ggcHJvY2VzcyBhbmQgc3RvcmUgaW4gdGVtcG9yYXJ5IGJ1ZmZlcgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCB3b3JsZF9zaXplOyArK2kpIHsKICAgICAgICBNUElfUmVjdih0ZW1wX3JlY3ZidWYgKyBkaXNwbHNbaV0sIHJlY3Zjb3VudHNbaV0sIE1QSV9DSEFSLCBpLCAwLCBjb21tLCBNUElfU1RBVFVTX0lHTk9SRSk7CiAgICB9CgogICAgLy8gQ29weSBkYXRhIGZyb20gdGVtcG9yYXJ5IGJ1ZmZlciB0byBmaW5hbCByZWNlaXZlIGJ1ZmZlcgogICAgbWVtY3B5KHJlY3ZidWYsIHRlbXBfcmVjdmJ1ZiwgdG90YWxfcmVjdl9jb3VudCAqIHNpemVvZihjaGFyKSk7CgogICAgLy8gRnJlZSB0ZW1wb3JhcnkgYnVmZmVyCiAgICBmcmVlKHRlbXBfcmVjdmJ1Zik7Cn0KCnZvaWQgbXlfQWxsdG9hbGx2KGNoYXIgKnNlbmRidWYsIGludCAqc2VuZGNvdW50cywgaW50ICpzZGlzcGxzLCBjaGFyICpyZWN2YnVmLCBpbnQgKnJlY3Zjb3VudHMsIGludCAqcmRpc3BscywgTVBJX0NvbW0gY29tbSkgewogICAgaW50IHdvcmxkX3JhbmssIHdvcmxkX3NpemU7CiAgICBNUElfQ29tbV9yYW5rKGNvbW0sICZ3b3JsZF9yYW5rKTsKICAgIE1QSV9Db21tX3NpemUoY29tbSwgJndvcmxkX3NpemUpOwoKICAgIC8vIENhbGN1bGF0ZSB0b3RhbCBzZW5kIGFuZCByZWNlaXZlIGNvdW50cwogICAgaW50IHRvdGFsX3NlbmRfY291bnQgPSAwOwogICAgaW50IHRvdGFsX3JlY3ZfY291bnQgPSAwOwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCB3b3JsZF9zaXplOyBpKyspIHsKICAgICAgICB0b3RhbF9zZW5kX2NvdW50ICs9IHNlbmRjb3VudHNbaV07CiAgICAgICAgdG90YWxfcmVjdl9jb3VudCArPSByZWN2Y291bnRzW2ldOwogICAgfQoKICAgIC8vIEFsbG9jYXRlIG1lbW9yeSBmb3IgdGVtcG9yYXJ5IHNlbmQgYW5kIHJlY2VpdmUgYnVmZmVycwogICAgY2hhciAqdGVtcF9zZW5kYnVmID0gKGNoYXIgKiltYWxsb2ModG90YWxfc2VuZF9jb3VudCAqIHNpemVvZihjaGFyKSk7CiAgICBjaGFyICp0ZW1wX3JlY3ZidWYgPSAoY2hhciAqKW1hbGxvYyh0b3RhbF9yZWN2X2NvdW50ICogc2l6ZW9mKGNoYXIpKTsKCiAgICAvLyBDb3B5IGRhdGEgdG8gdGVtcG9yYXJ5IHNlbmQgYnVmZmVyIGJhc2VkIG9uIHNlbmQgY291bnRzIGFuZCBkaXNwbGFjZW1lbnRzCiAgICBpbnQgc2VuZF9vZmZzZXQgPSAwOwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCB3b3JsZF9zaXplOyBpKyspIHsKICAgICAgICBtZW1jcHkodGVtcF9zZW5kYnVmICsgc2VuZF9vZmZzZXQsIHNlbmRidWYgKyBzZGlzcGxzW2ldLCBzZW5kY291bnRzW2ldKTsKICAgICAgICBzZW5kX29mZnNldCArPSBzZW5kY291bnRzW2ldOwogICAgfQoKICAgIC8vIEV4Y2hhbmdlIGRhdGEgd2l0aCBhbGwgb3RoZXIgcHJvY2Vzc2VzIHVzaW5nIHBvaW50LXRvLXBvaW50IGNvbW11bmljYXRpb24KICAgIGZvciAoaW50IGkgPSAwOyBpIDwgd29ybGRfc2l6ZTsgaSsrKSB7CiAgICAgICAgaWYgKGkgIT0gd29ybGRfcmFuaykgewogICAgICAgICAgICAvLyBTZW5kIGRhdGEgdG8gcHJvY2VzcyBpCiAgICAgICAgICAgIE1QSV9TZW5kcmVjdih0ZW1wX3NlbmRidWYgKyBzZGlzcGxzW2ldLCBzZW5kY291bnRzW2ldLCBNUElfQ0hBUiwgaSwgMCwKICAgICAgICAgICAgICAgICAgICAgICAgIHRlbXBfcmVjdmJ1ZiArIHJkaXNwbHNbaV0sIHJlY3Zjb3VudHNbaV0sIE1QSV9DSEFSLCBpLCAwLCBjb21tLCBNUElfU1RBVFVTX0lHTk9SRSk7CiAgICAgICAgfQogICAgfQoKICAgIC8vIENvcHkgZGF0YSBmcm9tIHRlbXBvcmFyeSByZWNlaXZlIGJ1ZmZlciB0byByZWNlaXZlIGJ1ZmZlciBiYXNlZCBvbiByZWNlaXZlIGNvdW50cyBhbmQgZGlzcGxhY2VtZW50cwogICAgaW50IHJlY3Zfb2Zmc2V0ID0gMDsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgd29ybGRfc2l6ZTsgaSsrKSB7CiAgICAgICAgbWVtY3B5KHJlY3ZidWYgKyByZGlzcGxzW2ldLCB0ZW1wX3JlY3ZidWYgKyByZWN2X29mZnNldCwgcmVjdmNvdW50c1tpXSk7CiAgICAgICAgcmVjdl9vZmZzZXQgKz0gcmVjdmNvdW50c1tpXTsKICAgIH0KCiAgICAvLyBGcmVlIHRlbXBvcmFyeSBidWZmZXJzCiAgICBmcmVlKHRlbXBfc2VuZGJ1Zik7CiAgICBmcmVlKHRlbXBfcmVjdmJ1Zik7Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyICphcmd2W10pIHsKICAgIE1QSV9Jbml0KCZhcmdjLCAmYXJndik7CgogICAgaW50IHdvcmxkX3JhbmssIHdvcmxkX3NpemU7CiAgICBNUElfQ29tbV9yYW5rKE1QSV9DT01NX1dPUkxELCAmd29ybGRfcmFuayk7CiAgICBNUElfQ29tbV9zaXplKE1QSV9DT01NX1dPUkxELCAmd29ybGRfc2l6ZSk7CgogICAgLy8gSW5wdXQgZGF0YSBmcm9tIHVzZXIKICAgIGNoYXIgc2VuZGJ1ZlsxMDBdOyAvLyBBc3N1bWluZyBhIG1heGltdW0gb2YgMTAwIGNoYXJhY3RlcnMKICAgIGlmICh3b3JsZF9yYW5rID09IDApIHsKICAgICAgICBwcmludGYoIkVudGVyIGRhdGEgdG8gc2VuZDogIik7CiAgICAgICAgc2NhbmYoIiVzIiwgc2VuZGJ1Zik7CiAgICB9CgogICAgLy8gQWxsdG9BbGwKICAgIGNoYXIgcmVjdmJ1Zl9hbGx0b2FsbFsxMDAgKiB3b3JsZF9zaXplXTsKICAgIEFsbHRvQWxsKHNlbmRidWYsIHJlY3ZidWZfYWxsdG9hbGwsIDEwMCwgTVBJX0NPTU1fV09STEQpOwogICAgaWYgKHdvcmxkX3JhbmsgPT0gMCkgewogICAgICAgIHByaW50ZigiQWxsdG9BbGwgcmVjZWl2ZWQgZGF0YTogJXNcbiIsIHJlY3ZidWZfYWxsdG9hbGwpOwogICAgfQoKICAgIC8vIEFsbGdhdGhlcgogICAgY2hhciByZWN2YnVmX2FsbGdhdGhlclsxMDAgKiB3b3JsZF9zaXplXTsKICAgIEFsbGdhdGhlcihzZW5kYnVmLCBzdHJsZW4oc2VuZGJ1ZikgKyAxLCByZWN2YnVmX2FsbGdhdGhlciwgc3RybGVuKHNlbmRidWYpICsgMSwgTVBJX0NPTU1fV09STEQpOwogICAgaWYgKHdvcmxkX3JhbmsgPT0gMCkgewogICAgICAgIHByaW50ZigiQWxsZ2F0aGVyIHJlY2VpdmVkIGRhdGE6ICVzXG4iLCByZWN2YnVmX2FsbGdhdGhlcik7CiAgICB9CgogICAgLy8gQWxsZ2F0aGVydgogICAgaW50ICpyZWN2Y291bnRzX2FsbGdhdGhlcnYgPSAoaW50ICopbWFsbG9jKHdvcmxkX3NpemUgKiBzaXplb2YoaW50KSk7CiAgICBpbnQgKmRpc3Bsc19hbGxnYXRoZXJ2ID0gKGludCAqKW1hbGxvYyh3b3JsZF9zaXplICogc2l6ZW9mKGludCkpOwogICAgaW50IHNlbmRjb3VudF9hbGxnYXRoZXJ2ID0gc3RybGVuKHNlbmRidWYpICsgMTsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgd29ybGRfc2l6ZTsgKytpKSB7CiAgICAgICAgcmVjdmNvdW50c19hbGxnYXRoZXJ2W2ldID0gc3RybGVuKHNlbmRidWYpICsgMTsKICAgICAgICBkaXNwbHNfYWxsZ2F0aGVydltpXSA9IGkgKiAoc3RybGVuKHNlbmRidWYpICsgMSk7CiAgICB9CiAgICBjaGFyIHJlY3ZidWZfYWxsZ2F0aGVydlsxMDAgKiB3b3JsZF9zaXplXTsKICAgIEFsbGdhdGhlcnYoc2VuZGJ1Ziwgc2VuZGNvdW50X2FsbGdhdGhlcnYsIHJlY3ZidWZfYWxsZ2F0aGVydiwgcmVjdmNvdW50c19hbGxnYXRoZXJ2LCBkaXNwbHNfYWxsZ2F0aGVydiwgTVBJX0NPTU1fV09STEQpOwogICAgaWYgKHdvcmxkX3JhbmsgPT0gMCkgewogICAgICAgIHByaW50ZigiQWxsZ2F0aGVydiByZWNlaXZlZCBkYXRhOiAlc1xuIiwgcmVjdmJ1Zl9hbGxnYXRoZXJ2KTsKICAgIH0KCiAgICAvLyBBbGx0b2FsbHYKICAgIGludCBzZW5kY291bnRzX2FsbHRvYWxsdlt3b3JsZF9zaXplXTsKICAgIGludCByZWN2Y291bnRzX2FsbHRvYWxsdlt3b3JsZF9zaXplXTsKICAgIGludCBzZGlzcGxzX2FsbHRvYWxsdlt3b3JsZF9zaXplXTsKICAgIGludCByZGlzcGxzX2FsbHRvYWxsdlt3b3JsZF9zaXplXTsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgd29ybGRfc2l6ZTsgaSsrKSB7CiAgICAgICAgc2VuZGNvdW50c19hbGx0b2FsbHZbaV0gPSBzdHJsZW4oc2VuZGJ1ZikgKyAxOwogICAgICAgIHJlY3Zjb3VudHNfYWxsdG9hbGx2W2ldID0gc3RybGVuKHNlbmRidWYpICsgMTsKICAgICAgICBzZGlzcGxzX2FsbHRvYWxsdltpXSA9IGkgKiAoc3RybGVuKHNlbmRidWYpICsgMSk7CiAgICAgICAgcmRpc3Bsc19hbGx0b2FsbHZbaV0gPSBpICogKHN0cmxlbihzZW5kYnVmKSArIDEpOwogICAgfQogICAgY2hhciByZWN2YnVmX2FsbHRvYWxsdlsxMDAgKiB3b3JsZF9zaXplXTsKICAgIG15X0FsbHRvYWxsdihzZW5kYnVmLCBzZW5kY291bnRzX2FsbHRvYWxsdiwgc2Rpc3Bsc19hbGx0b2FsbHYsIHJlY3ZidWZfYWxsdG9hbGx2LCByZWN2Y291bnRzX2FsbHRvYWxsdiwgcmRpc3Bsc19hbGx0b2FsbHYsIE1QSV9DT01NX1dPUkxEKTsKICAgIGlmICh3b3JsZF9yYW5rID09IDApIHsKICAgICAgICBwcmludGYoIkFsbHRvYWxsdiByZWNlaXZlZCBkYXRhOiAlc1xuIiwgcmVjdmJ1Zl9hbGx0b2FsbHYpOwogICAgfQoKICAgIC8vIEZpbmFsaXplIE1QSQogICAgTVBJX0ZpbmFsaXplKCk7CiAgICByZXR1cm4gMDsKfQo=