// File: /workspace/github_cpp_makefile_star2_O2/m1c0l[P]TCP/client.cpp
// Function: main
int main(int argc, char **argv)
{
    if (argc != 3) {
		cerr << "usage: " << argv[0] << " SERVER-HOST-OR-IP PORT-NUMBER" << '\n';
        exit(1);
    }

    string ip = argv[1];
    string port = argv[2];

	// Get IP address if we're given a hostname
	addrinfo hints;
	addrinfo* res;

	// prepare hints
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET; // IPv4
	hints.ai_socktype = SOCK_STREAM; // TCP

	// get address
	int status = 0;
	if ((status = getaddrinfo(ip.c_str(), port.c_str(), &hints, &res)) != 0) {
		// cerr << "getaddrinfo: " << gai_strerror(status) << '\n';
		exit(2);
	}

	addrinfo* p = res;
	// convert address to IPv4 address
	sockaddr_in* ipv4;
	char ipstr[INET_ADDRSTRLEN] = {'\0'};
	if (p != 0) {
		ipv4 = (sockaddr_in*)p->ai_addr;

		// convert the IP to a string
		inet_ntop(p->ai_family, &(ipv4->sin_addr), ipstr, sizeof(ipstr));
	}
	else {
		// cerr << "IP address not found for " << ip << endl;
		exit(3);
	}
	ip = ipstr;
	// cerr << "IP: " << ip << "\n";

	srand (time(NULL)); //Used to generate random ISN
 
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket");
		exit(1);
    }

	// Set receive timeout of 0.5 s
	timeval recvTimeval;
	recvTimeval.tv_sec = 0;
	recvTimeval.tv_usec = TIMEOUT * 1000;
	setSocketTimeout(sockfd, recvTimeval);
 
    sockaddr_in si_server;
    memset((char *) &si_server, 0, sizeof(si_server));
    si_server.sin_family = AF_INET;
    si_server.sin_port = htons(stoi(port));
	socklen_t serverLen = sizeof(si_server);

    if (inet_aton(ip.c_str(), &si_server.sin_addr) == 0) {
        perror("inet_aton");
	    exit(1);
    }


	uint16_t seqToSend = rand() % MAX_SEQ_NUM;
   	uint16_t ackToSend = 0;
	uint16_t recvWindowToSend = INIT_RECV_WINDOW;
	TcpMessage packetToSend, packetReceived;
	uint16_t synAckSeq;


	/* handshake */
	bool hasResentSyn = false;
	while (true) {
		/* send SYN */
		packetToSend = TcpMessage(seqToSend, ackToSend, recvWindowToSend, "S");
		printSend("SYN", seqToSend, hasResentSyn);
		hasResentSyn = true; // set this to true so "retransmit" will print the 2nd time
		// keep this // cerr output for now, remove it later
		// cerr << "sending SYN:" << endl;
		packetToSend.dump();
		packetToSend.sendto(sockfd, &si_server, serverLen);

		/* receive SYN-ACK */
		int r = packetReceived.recvfrom(sockfd, &si_server, serverLen);
		if (r == RECV_TIMEOUT) {
			continue; // resend SYN
		}
		else {
			printRecv(packetReceived.seqNum);
			// cerr << "receiving SYN-ACK:" << endl;
			packetReceived.dump();
			if (!packetReceived.getFlag('a') || !packetReceived.getFlag('s')) {
				// error: server responded, but without syn-ack
				// cerr << "Server responded, but without syn-ack!\n";
				//exit(1);
			}
			if (packetReceived.ackNum != incSeqNum(seqToSend, 1)) {
				// cerr << "SYN-ACK has wrong ack number; drop packet" << endl;
				continue;
			}
			synAckSeq = packetReceived.seqNum;
			break;
		}
	}

	// seq/ack for client's ACK for handshake
	seqToSend = incSeqNum(seqToSend, 1);// increase sequence number by 1
	uint16_t handshakeSeq = seqToSend;
	ackToSend = incSeqNum(packetReceived.seqNum, 1);
	uint16_t handshakeAck = ackToSend;

	//return 0;

	/* receive data */

	ofstream outFile(OUTPUT_FILE);
	bool handshakeComplete = false;
	TcpMessage dataAck;

	// store the out-of-order packets in case we get in order packets
	unordered_map<uint16_t, TcpMessage> outOfOrderPkts; // seqNum -> TcpMessage
	// first data packet's sequence number we should receive
	uint16_t nextInOrderSeq = ackToSend;
	uint16_t lastAckSent = BAD_SEQ_NUM;
	bool handshakeAckResend = false;

	while (true) {
		/* send handshake ACK */
		if (!handshakeComplete) {
			packetToSend = TcpMessage(handshakeSeq, handshakeAck, recvWindowToSend, "A");
			printSend("ACK", handshakeAck, handshakeAckResend);
			lastAckSent = handshakeAck;
			// cerr << "sending ACK:" << endl;
			packetToSend.dump();
			packetToSend.sendto(sockfd, &si_server, serverLen);
			handshakeAckResend = true;
		}

		/* receive data packet */
		int r = packetReceived.recvfrom(sockfd, &si_server, serverLen);
		// if timeout, try to recvfrom again
		if (r == RECV_TIMEOUT) {
			continue;
		}
		// if duplicate SYN-ACK, resend handshake ACK
		if (packetReceived.seqNum == synAckSeq) {
			continue;
		}
		handshakeComplete = true; // done with handshake if this is a data pkt

		// else, r == RECV_SUCCESS
		// cerr << "receiving data:" << endl;
		packetReceived.dump();

		// FIN received
		if (packetReceived.getFlag('F')) {
			// cerr << "OoO map size at FIN: " << outOfOrderPkts.size() << '\n';
			printRecv(packetReceived.seqNum);
			break;
		}
		printRecv(packetReceived.seqNum);

		streamsize dataSize = packetReceived.data.size();
		uint16_t seqReceived = packetReceived.seqNum;
		bool shouldDropPkt = false;
		// check if packet's within window boundary; if not, drop packet
		uint16_t windowMaxSeq = incSeqNum(nextInOrderSeq, recvWindowToSend);
		if (windowMaxSeq > nextInOrderSeq) {
			// no wrap around
			shouldDropPkt = seqReceived < nextInOrderSeq || seqReceived > windowMaxSeq;
		}
		else {
			// wrap around
			shouldDropPkt = seqReceived > windowMaxSeq && seqReceived < nextInOrderSeq;
		}
		if (shouldDropPkt) {
			// cerr << "Received pkt not w/in window!\n";
		}
		if (!shouldDropPkt) {
			if (seqReceived == nextInOrderSeq) { 
				// cerr << "Received in order packet!\n";
				// save data to file
				const char *data = packetReceived.data.c_str();
				outFile.write(data, dataSize);

				// see if we received an OoO pkt earlier w/ this seq #
				if (outOfOrderPkts.count(seqReceived)) {
					// delete it from map
					outOfOrderPkts.erase(seqReceived);
				}
				// update the next expected sequence number, increase by data size we got
				nextInOrderSeq = incSeqNum(nextInOrderSeq, dataSize);
				// loop through saved OoO packets to see if they're next in order
				while (outOfOrderPkts.count(nextInOrderSeq)) {
					// cerr << "Writing OoO pkt w/ seq # " << nextInOrderSeq << " from map\n";
					TcpMessage poppedMsg = outOfOrderPkts[nextInOrderSeq];
					const char *poppedData = poppedMsg.data.c_str();
					streamsize poppedDataSize = poppedMsg.data.size();
					outFile.write(poppedData, poppedDataSize);
					outOfOrderPkts.erase(nextInOrderSeq);
					nextInOrderSeq = incSeqNum(nextInOrderSeq, poppedDataSize);
				}
			}
			else {
				// out of order, store it for later
				// cerr << "Received out of order packet! Writing to map\n";
				outOfOrderPkts[seqReceived] = packetReceived;
			}
		}
		ackToSend = nextInOrderSeq; 
		dataAck = TcpMessage(seqToSend, ackToSend, recvWindowToSend, "A");
		printSend("ACK", ackToSend, ackToSend == lastAckSent);
		// cerr << "sending ACK:" << endl;
		dataAck.dump();
		dataAck.sendto(sockfd, &si_server, serverLen);
		lastAckSent = ackToSend;
	}

 

	/* Send FIN-ACK for the FIN received earlier */
	bool hasSentFinAck = false;
	bool hasSentFin = false;
	bool hasReceivedAck = false; /* receive packets until a FIN-ACK is received from server */
	// seq # stays same b/c no payload
	ackToSend = incSeqNum(packetReceived.seqNum, 1);
	packetToSend = TcpMessage(seqToSend, ackToSend, recvWindowToSend, "FA");
	packetToSend.sendto(sockfd, &si_server, serverLen);
	printSend("FIN", ackToSend, hasSentFinAck);
	// cerr << "Sending FIN-ACK to server\n";
	packetToSend.dump();

	while (!hasReceivedAck) {

		/* Send FIN; seq # stays same b/c no payload */
		packetToSend = TcpMessage(seqToSend, ackToSend, recvWindowToSend, "F");
		packetToSend.sendto(sockfd, &si_server, serverLen);
		printSend("FIN", ackToSend, hasSentFin);
		hasSentFin = true; // so "retransmission" prints the second time
		// cerr << "Sending FIN to server\n";
		packetToSend.dump();

		int r = packetReceived.recvfrom(sockfd, &si_server, serverLen);
		if (r == RECV_TIMEOUT) {
			continue;
		}
		printRecv(packetReceived.seqNum);
		switch(packetReceived.flags) {
			// server resends FIN
			case FIN_FLAG:
				/* Send FIN-ACK */
				printSend("FIN", ackToSend, true);
				// cerr << "Received FIN\n";
				ackToSend = incSeqNum(packetReceived.seqNum, 1);
				packetToSend = TcpMessage(seqToSend, ackToSend, recvWindowToSend, "FA");
				packetToSend.sendto(sockfd, &si_server, serverLen);
				// cerr << "Sending FIN-ACK to server\n";
				packetToSend.dump();
				break;

			// get FIN-ACK; can exit now
			case ACK_FLAG:
				// cerr << "Received ACK of FIN! Closing connection.\n";
				hasReceivedAck = true;
				break;

			default:
				// cerr << "Received packet wasn't FIN-ACK or FIN!\n";
				//exit(1);
				break;

		}
	}



	close(sockfd);
	outFile.close();
	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x518, %rsp            # imm = 0x518
movq %rsi, %rbx
cmpl $0x3, %edi
jne 0x3467
movq 0x8(%rbx), %rsi
leaq 0xb0(%rsp), %rdi
leaq 0x318(%rsp), %rdx
callq 0x2780
movq 0x10(%rbx), %rsi
leaq 0x108(%rsp), %rdi
leaq 0x318(%rsp), %rdx
callq 0x2780
xorps %xmm0, %xmm0
leaq 0x2e0(%rsp), %rdx
movaps %xmm0, (%rdx)
movaps %xmm0, 0x10(%rdx)
movaps %xmm0, 0x20(%rdx)
movabsq $0x100000002, %rax      # imm = 0x100000002
movq %rax, 0x4(%rdx)
movq 0xb0(%rsp), %rdi
movq 0x108(%rsp), %rsi
leaq 0xa8(%rsp), %rcx
callq 0x2230
testl %eax, %eax
jne 0x34a1
movq 0xa8(%rsp), %rax
xorps %xmm0, %xmm0
movaps %xmm0, 0x150(%rsp)
testq %rax, %rax
je 0x34a5
movq 0x18(%rax), %rsi
movl 0x4(%rax), %edi
addq $0x4, %rsi
leaq 0x150(%rsp), %rbx
pushq $0x10
popq %rcx
movq %rbx, %rdx
callq 0x21e0
leaq 0xb0(%rsp), %rdi
movq %rbx, %rsi
callq 0x2330
xorl %edi, %edi
callq 0x2190
movl %eax, %edi
callq 0x21a0
pushq $0x2
popq %rdi
movl %edi, %esi
xorl %edx, %edx
callq 0x2060
cmpl $-0x1, %eax
je 0x34a9
movl $0x7a120, %edx          # imm = 0x7A120
movl %eax, 0x14(%rsp)
movl %eax, %edi
xorl %esi, %esi
callq 0x291f
xorps %xmm0, %xmm0
movaps %xmm0, 0x20(%rsp)
movw $0x2, 0x20(%rsp)
leaq 0x108(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x367d
rolw $0x8, %ax
leaq 0x24(%rsp), %rsi
movw %ax, -0x2(%rsi)
movq 0xb0(%rsp), %rdi
callq 0x2120
testl %eax, %eax
je 0x34b2
callq 0x2070
movl $0x7800, %ecx           # imm = 0x7800
cltd
idivl %ecx
movl %edx, %ebx
leaq 0x80(%rsp), %rdi
callq 0x25b2
leaq 0x30(%rsp), %rdi
callq 0x25b2
xorl %r14d, %r14d
movzwl %bx, %ebp
leaq 0x80(%rsp), %rbx
leaq 0x2a0(%rsp), %r12
leaq 0x2c0(%rsp), %r15
movq %r15, %rdi
leaq 0x143d(%rip), %rsi      # 0x40ba
leaq 0xd0(%rsp), %rdx
callq 0x2780
leaq 0x318(%rsp), %r13
movq %r13, %rdi
movl %ebp, %esi
xorl %edx, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
movq %r15, %r8
callq 0x249c
movq %rbx, %rdi
movq %r13, %rsi
callq 0x369a
leaq 0x320(%rsp), %rdi
callq 0x20d0
movq %r15, %rdi
callq 0x20d0
movq %r12, %rdi
leaq 0x139a(%rip), %rsi      # 0x406a
movq %r13, %rdx
callq 0x2780
movzbl %r14b, %edx
andl $0x1, %edx
movq %r12, %rdi
movl %ebp, %esi
callq 0x2a28
movq %r12, %rdi
callq 0x20d0
movq %rbx, %rdi
callq 0x277e
movl 0x14(%rsp), %r14d
leaq 0x20(%rsp), %r15
pushq $0x10
popq %r13
movq %rbx, %rdi
movl %r14d, %esi
movq %r15, %rdx
movl %r13d, %ecx
callq 0x26b4
leaq 0x30(%rsp), %rdi
movl %r14d, %esi
movq %r15, %rdx
movl %r13d, %ecx
callq 0x2710
movb $0x1, %r14b
cmpl $0x2, %eax
je 0x2c6b
movzwl 0x30(%rsp), %edi
callq 0x29fc
leaq 0x30(%rsp), %rdi
callq 0x277e
leaq 0x30(%rsp), %rdi
pushq $0x61
popq %rsi
callq 0x25d8
testb %al, %al
je 0x2d69
leaq 0x30(%rsp), %rdi
pushq $0x73
popq %rsi
callq 0x25d8
movzwl 0x32(%rsp), %r15d
movl %ebp, %edi
pushq $0x1
popq %rsi
callq 0x2854
cmpw %ax, %r15w
jne 0x2c6b
movzwl 0x30(%rsp), %eax
movw %ax, 0x12(%rsp)
pushq $0x1
popq %rsi
movl %ebp, %edi
callq 0x2854
movl %eax, %ebp
movzwl 0x30(%rsp), %edi
pushq $0x1
popq %rsi
callq 0x2854
movl %eax, %ebx
leaq 0x130d(%rip), %rsi      # 0x40bc
leaq 0x318(%rsp), %rdi
pushq $0x10
popq %rdx
callq 0x21f0
leaq 0x128(%rsp), %rdi
callq 0x25b2
leaq 0x100(%rsp), %rax
movq %rax, -0x30(%rax)
movq $0x1, -0x28(%rax)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, -0x10(%rax) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
leaq 0xe(%rsp), %rax
movw %bx, (%rax)
xorl %r14d, %r14d
movzwl %bp, %eax
movw $0xd903, %r15w          # imm = 0xD903
movl %eax, 0x18(%rsp)
leaq 0x58(%rsp), %r13
xorl %r12d, %r12d
testb $0x1, %r14b
jne 0x2ed1
leaq 0x280(%rsp), %r15
movq %r15, %rdi
leaq 0x129e(%rip), %rsi      # 0x40cb
leaq 0x10(%rsp), %rdx
callq 0x2780
movzwl %bx, %ebp
movq %r13, %rdi
movl 0x18(%rsp), %esi
movl %ebp, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
movq %r15, %r8
callq 0x249c
leaq 0x80(%rsp), %rdi
movq %r13, %rsi
callq 0x369a
leaq 0x60(%rsp), %rdi
callq 0x20d0
movq %r15, %rdi
callq 0x20d0
leaq 0x260(%rsp), %r15
movq %r15, %rdi
leaq 0x11fa(%rip), %rsi      # 0x407e
movq %r13, %rdx
callq 0x2780
movzbl %r12b, %edx
andl $0x1, %edx
movq %r15, %rdi
movl %ebp, %esi
callq 0x2a28
movq %r15, %rdi
callq 0x20d0
leaq 0x80(%rsp), %rdi
callq 0x277e
movb $0x1, %r12b
leaq 0x80(%rsp), %rdi
movl 0x14(%rsp), %esi
leaq 0x20(%rsp), %rdx
pushq $0x10
popq %rcx
callq 0x26b4
movl %ebx, %r15d
leaq 0x30(%rsp), %rdi
movl 0x14(%rsp), %esi
leaq 0x20(%rsp), %rdx
pushq $0x10
popq %rcx
callq 0x2710
cmpl $0x2, %eax
je 0x2e11
movzwl 0x12(%rsp), %eax
cmpw %ax, 0x30(%rsp)
je 0x2e11
leaq 0x30(%rsp), %rdi
callq 0x277e
leaq 0x60(%rsp), %r14
leaq 0x30(%rsp), %rdi
pushq $0x46
popq %rsi
callq 0x25d8
movzwl 0x30(%rsp), %edi
testb %al, %al
jne 0x314a
callq 0x29fc
movq 0x40(%rsp), %rbp
movzwl 0x30(%rsp), %eax
movw %ax, 0x10(%rsp)
movzwl 0xe(%rsp), %edi
movl $0x3c00, %esi           # imm = 0x3C00
callq 0x2854
movzwl 0xe(%rsp), %ecx
movzwl 0x10(%rsp), %edx
cmpw %cx, %ax
jbe 0x2f72
cmpw %cx, %dx
setb %sil
cmpw %ax, %dx
seta %al
orb %sil, %al
je 0x2f88
jmp 0x3080
cmpw %ax, %dx
seta %al
cmpw %cx, %dx
setb %sil
testb %sil, %al
jne 0x3080
cmpw %cx, %dx
jne 0x3061
movq 0x38(%rsp), %rsi
leaq 0x318(%rsp), %rdi
movq %rbp, %rdx
callq 0x2240
leaq 0xd0(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x387e
testq %rax, %rax
je 0x2fcf
leaq 0xd0(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x3912
movzwl 0xe(%rsp), %edi
movzwl %bp, %esi
callq 0x2854
movw %ax, 0xe(%rsp)
leaq 0xd0(%rsp), %rdi
leaq 0xe(%rsp), %rsi
callq 0x387e
testq %rax, %rax
je 0x3080
leaq 0xd0(%rsp), %rdi
leaq 0xe(%rsp), %rsi
callq 0x3a18
movq %r13, %rdi
movq %rax, %rsi
callq 0x36b6
movq 0x60(%rsp), %rsi
movq 0x68(%rsp), %rbp
leaq 0x318(%rsp), %rdi
movq %rbp, %rdx
callq 0x2240
leaq 0xd0(%rsp), %rdi
leaq 0xe(%rsp), %rsi
callq 0x3912
movzwl 0xe(%rsp), %edi
movzwl %bp, %esi
callq 0x2854
movw %ax, 0xe(%rsp)
movq %r14, %rdi
callq 0x20d0
jmp 0x2fe1
leaq 0xd0(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x3a18
movq %rax, %rdi
leaq 0x30(%rsp), %rsi
callq 0x36ca
movzwl 0xe(%rsp), %ebp
leaq 0x240(%rsp), %r14
movq %r14, %rdi
leaq 0x1034(%rip), %rsi      # 0x40cb
leaq 0x1f(%rsp), %rdx
callq 0x2780
movw %bp, 0x1c(%rsp)
movzwl %bp, %ebp
movq %r13, %rdi
movl 0x18(%rsp), %esi
movl %ebp, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
movq %r14, %r8
callq 0x249c
leaq 0x128(%rsp), %rdi
movq %r13, %rsi
callq 0x369a
leaq 0x60(%rsp), %rdi
callq 0x20d0
movq %r14, %rdi
callq 0x20d0
leaq 0x220(%rsp), %r14
movq %r14, %rdi
leaq 0xf8b(%rip), %rsi       # 0x407e
movq %r13, %rdx
callq 0x2780
xorl %edx, %edx
cmpw %r15w, %bp
sete %dl
movq %r14, %rdi
movl %ebp, %esi
callq 0x2a28
movq %r14, %rdi
callq 0x20d0
leaq 0x128(%rsp), %rdi
callq 0x277e
movzwl 0x1c(%rsp), %r15d
leaq 0x128(%rsp), %rdi
movl 0x14(%rsp), %esi
leaq 0x20(%rsp), %rdx
pushq $0x10
popq %rcx
callq 0x26b4
movb $0x1, %r14b
jmp 0x2e11
callq 0x29fc
movzwl 0x30(%rsp), %edi
pushq $0x1
popq %rsi
callq 0x2854
movl %eax, %ebp
leaq 0xf65(%rip), %rsi       # 0x40ca
leaq 0x180(%rsp), %rdi
leaq 0x10(%rsp), %rdx
callq 0x2780
movzwl %bp, %ebx
leaq 0x58(%rsp), %rdi
leaq 0x180(%rsp), %r8
movl 0x18(%rsp), %esi
movl %ebx, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
callq 0x249c
leaq 0x80(%rsp), %r14
leaq 0x58(%rsp), %rsi
movq %r14, %rdi
callq 0x369a
leaq 0x60(%rsp), %rdi
callq 0x20d0
leaq 0x180(%rsp), %rdi
callq 0x20d0
leaq 0x20(%rsp), %rdx
pushq $0x10
popq %rcx
movq %r14, %rdi
movl 0x14(%rsp), %esi
callq 0x26b4
leaq 0xeef(%rip), %rsi       # 0x40cd
leaq 0x160(%rsp), %rdi
leaq 0x58(%rsp), %rdx
callq 0x2780
leaq 0x160(%rsp), %rdi
movl %ebx, %esi
xorl %edx, %edx
callq 0x2a28
leaq 0x160(%rsp), %rdi
callq 0x20d0
leaq 0x80(%rsp), %rdi
callq 0x277e
movw %bp, 0x12(%rsp)
xorl %r15d, %r15d
leaq 0x200(%rsp), %r12
leaq 0x58(%rsp), %rbp
leaq 0x80(%rsp), %r14
leaq 0x1e0(%rsp), %r13
xorl %ecx, %ecx
movzwl 0x12(%rsp), %ebx
testb $0x1, %cl
jne 0x33e5
movq %r12, %rdi
leaq 0xe77(%rip), %rsi       # 0x40d1
leaq 0x10(%rsp), %rdx
callq 0x2780
movq %rbp, %rdi
movl 0x18(%rsp), %esi
movl %ebx, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
movq %r12, %r8
callq 0x249c
movq %r14, %rdi
movq %rbp, %rsi
callq 0x369a
leaq 0x60(%rsp), %rdi
callq 0x20d0
movq %r12, %rdi
callq 0x20d0
movq %r14, %rdi
movl 0x14(%rsp), %esi
leaq 0x20(%rsp), %rdx
pushq $0x10
popq %rcx
callq 0x26b4
movq %r13, %rdi
leaq 0xe18(%rip), %rsi       # 0x40cd
movq %rbp, %rdx
callq 0x2780
movzbl %r15b, %edx
andl $0x1, %edx
movq %r13, %rdi
movl %ebx, %esi
callq 0x2a28
movq %r13, %rdi
callq 0x20d0
movq %r14, %rdi
callq 0x277e
leaq 0x30(%rsp), %rdi
movl 0x14(%rsp), %esi
leaq 0x20(%rsp), %rdx
pushq $0x10
popq %rcx
callq 0x2710
movb $0x1, %r15b
xorl %ecx, %ecx
cmpl $0x2, %eax
je 0x3247
movzwl 0x30(%rsp), %edi
callq 0x29fc
movzwl 0x36(%rsp), %eax
cmpl $0x4, %eax
je 0x3323
xorl %ecx, %ecx
cmpl $0x1, %eax
jne 0x3247
jmp 0x332d
movb $0x1, %r15b
movb $0x1, %cl
jmp 0x3247
leaq 0x1c0(%rsp), %r15
movq %r15, %rdi
leaq 0xd8e(%rip), %rsi       # 0x40cd
movq %rbp, %rdx
callq 0x2780
movq %r15, %rdi
movl %ebx, %esi
pushq $0x1
popq %rbx
movl %ebx, %edx
callq 0x2a28
movq %r15, %rdi
callq 0x20d0
movzwl 0x30(%rsp), %edi
movl %ebx, %esi
callq 0x2854
movw %ax, 0x12(%rsp)
leaq 0x1a0(%rsp), %rbx
movq %rbx, %rdi
leaq 0xd49(%rip), %rsi       # 0x40ca
leaq 0x10(%rsp), %rdx
callq 0x2780
movzwl 0x12(%rsp), %edx
movq %rbp, %rdi
movl 0x18(%rsp), %esi
movl $0x3c00, %ecx           # imm = 0x3C00
movq %rbx, %r8
callq 0x249c
movq %r14, %rdi
movq %rbp, %rsi
callq 0x369a
leaq 0x60(%rsp), %rdi
callq 0x20d0
movq %rbx, %rdi
callq 0x20d0
movq %r14, %rdi
movl 0x14(%rsp), %esi
leaq 0x20(%rsp), %rdx
pushq $0x10
popq %rcx
callq 0x26b4
movb $0x1, %r15b
movq %r14, %rdi
callq 0x277e
jmp 0x3240
movl 0x14(%rsp), %edi
callq 0x2340
leaq 0x318(%rsp), %rdi
callq 0x2280
leaq 0xd0(%rsp), %rdi
callq 0x37b4
leaq 0x130(%rsp), %rdi
callq 0x20d0
leaq 0x318(%rsp), %rdi
callq 0x22b0
leaq 0x38(%rsp), %rdi
callq 0x20d0
leaq 0x88(%rsp), %rdi
callq 0x20d0
leaq 0x108(%rsp), %rdi
callq 0x20d0
leaq 0xb0(%rsp), %rdi
callq 0x20d0
xorl %eax, %eax
addq $0x518, %rsp            # imm = 0x518
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x3b82(%rip), %rdi      # 0x6ff0
leaq 0xc0d(%rip), %rsi       # 0x4082
callq 0x21b0
movq (%rbx), %rsi
movq %rax, %rdi
callq 0x21b0
leaq 0xbfe(%rip), %rsi       # 0x408a
movq %rax, %rdi
callq 0x21b0
pushq $0xa
popq %rsi
movq %rax, %rdi
callq 0x2200
jmp 0x34be
pushq $0x2
jmp 0x34c0
pushq $0x3
jmp 0x34c0
leaq 0xbf9(%rip), %rdi       # 0x40a9
jmp 0x34b9
leaq 0xbf7(%rip), %rdi       # 0x40b0
callq 0x2160
pushq $0x1
popq %rdi
callq 0x2210
movq %rax, %rbx
leaq 0x1a0(%rsp), %rdi
jmp 0x3607
jmp 0x3610
movq %rax, %rbx
leaq 0x1c0(%rsp), %rdi
jmp 0x3607
jmp 0x3610
jmp 0x3610
movq %rax, %rbx
leaq 0x160(%rsp), %rdi
jmp 0x3607
jmp 0x3610
movq %rax, %rbx
leaq 0x180(%rsp), %rdi
jmp 0x3607
jmp 0x3610
jmp 0x3610
movq %rax, %rbx
jmp 0x362d
jmp 0x35da
jmp 0x35da
jmp 0x35da
movq %rax, %rbx
jmp 0x3644
jmp 0x354b
jmp 0x354b
jmp 0x354b
jmp 0x354b
movq %rax, %rbx
jmp 0x3651
movq %rax, %rbx
jmp 0x365e
jmp 0x3610
jmp 0x3610
movq %rax, %rbx
leaq 0x200(%rsp), %rdi
jmp 0x3607
movq %rax, %rbx
leaq 0x1e0(%rsp), %rdi
jmp 0x3607
jmp 0x3610
jmp 0x3610
jmp 0x3610
movq %rax, %rbx
leaq 0x240(%rsp), %rdi
jmp 0x3607
jmp 0x3610
movq %rax, %rbx
leaq 0x220(%rsp), %rdi
jmp 0x3607
jmp 0x3610
jmp 0x3610
jmp 0x35da
movq %rax, %rbx
leaq 0x2c0(%rsp), %rdi
jmp 0x35cd
jmp 0x35da
movq %rax, %rbx
leaq 0x2a0(%rsp), %rdi
callq 0x20d0
jmp 0x363a
jmp 0x3610
jmp 0x3610
jmp 0x35da
movq %rax, %rbx
jmp 0x363a
jmp 0x3610
jmp 0x3610
jmp 0x3610
movq %rax, %rbx
leaq 0x260(%rsp), %rdi
jmp 0x3607
jmp 0x3610
movq %rax, %rbx
leaq 0x280(%rsp), %rdi
jmp 0x3607
movq %rax, %rbx
movq %r14, %rdi
callq 0x20d0
jmp 0x3613
jmp 0x3610
movq %rax, %rbx
leaq 0xd0(%rsp), %rdi
callq 0x37b4
leaq 0x130(%rsp), %rdi
callq 0x20d0
leaq 0x318(%rsp), %rdi
callq 0x22b0
leaq 0x38(%rsp), %rdi
callq 0x20d0
leaq 0x88(%rsp), %rdi
callq 0x20d0
leaq 0x108(%rsp), %rdi
callq 0x20d0
leaq 0xb0(%rsp), %rdi
callq 0x20d0
movq %rbx, %rdi
callq 0x2300