// File: /workspace/github_cpp_makefile_star2_O1/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 0x3a77
movq 0x8(%rbx), %rsi
leaq 0x1c8(%rsp), %rdi
leaq 0x2e0(%rsp), %rdx
callq 0x3e44
movq 0x10(%rbx), %rsi
leaq 0x270(%rsp), %rdi
leaq 0x2e0(%rsp), %rdx
callq 0x3e44
xorps %xmm0, %xmm0
leaq 0x4e0(%rsp), %rdx
movaps %xmm0, (%rdx)
movaps %xmm0, 0x10(%rdx)
movaps %xmm0, 0x20(%rdx)
movabsq $0x100000002, %rax      # imm = 0x100000002
movq %rax, 0x4(%rdx)
movq 0x1c8(%rsp), %rdi
movq 0x270(%rsp), %rsi
leaq 0x1c0(%rsp), %rcx
callq 0x2250
testl %eax, %eax
jne 0x3abb
movq 0x1c0(%rsp), %rax
xorps %xmm0, %xmm0
movaps %xmm0, 0x290(%rsp)
testq %rax, %rax
je 0x3ac5
movq 0x18(%rax), %rsi
movl 0x4(%rax), %edi
addq $0x4, %rsi
leaq 0x290(%rsp), %rbx
movq %rbx, %rdx
movl $0x10, %ecx
callq 0x21f0
leaq 0x1c8(%rsp), %r14
movq 0x8(%r14), %r15
movq %rbx, %rdi
callq 0x20d0
movq %r14, %rdi
xorl %esi, %esi
movq %r15, %rdx
movq %rbx, %rcx
movq %rax, %r8
callq 0x22e0
xorl %edi, %edi
callq 0x21a0
movl %eax, %edi
callq 0x21b0
movl $0x2, %edi
movl $0x2, %esi
xorl %edx, %edx
callq 0x2060
cmpl $-0x1, %eax
je 0x3acf
movl $0x7a120, %edx          # imm = 0x7A120
movl %eax, 0x4(%rsp)
movl %eax, %edi
xorl %esi, %esi
callq 0x2ab5
xorps %xmm0, %xmm0
movaps %xmm0, 0x40(%rsp)
movw $0x2, 0x40(%rsp)
movq 0x270(%rsp), %rbx
callq 0x2030
movq %rax, %r14
movl (%rax), %ebp
movl $0x0, (%rax)
leaq 0x2e0(%rsp), %r15
movq %rbx, %rdi
movq %r15, %rsi
movl $0xa, %edx
callq 0x2280
cmpq %rbx, (%r15)
je 0x3ad4
movslq %eax, %rcx
cmpq %rax, %rcx
jne 0x3ae0
movl (%r14), %ecx
cmpl $0x22, %ecx
je 0x3ae0
testl %ecx, %ecx
jne 0x2e53
movl %ebp, (%r14)
rolw $0x8, %ax
leaq 0x44(%rsp), %rsi
movw %ax, -0x2(%rsi)
movq 0x1c8(%rsp), %rdi
callq 0x2130
testl %eax, %eax
je 0x3aec
callq 0x2070
movl %eax, %ebx
leaq 0x78(%rsp), %rdi
callq 0x26fc
movl 0x4(%rsp), %r14d
leaq 0x50(%rsp), %rdi
callq 0x26fc
movslq %ebx, %rax
imulq $-0x77777777, %rax, %rcx # imm = 0x88888889
shrq $0x20, %rcx
addl %eax, %ecx
movl %ecx, %edx
shrl $0x1f, %edx
shrl $0xe, %ecx
addl %edx, %ecx
imull $0x7800, %ecx, %ecx     # imm = 0x7800
subl %ecx, %eax
xorl %r13d, %r13d
movzwl %ax, %ebp
leaq 0x40(%rsp), %r12
leaq 0x50(%rsp), %rbx
leaq 0x190(%rsp), %rax
movq %rax, 0x180(%rsp)
leaq 0x180(%rsp), %r15
movq %r15, %rdi
leaq 0x21d1(%rip), %rsi      # 0x50ba
leaq 0x21cb(%rip), %rdx      # 0x50bb
callq 0x2950
leaq 0x2e0(%rsp), %rdi
movl %ebp, %esi
xorl %edx, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
movq %r15, %r8
callq 0x251c
movq 0x2e0(%rsp), %rax
movq %rax, 0x78(%rsp)
leaq 0x80(%rsp), %rdi
leaq 0x2e8(%rsp), %rsi
callq 0x2240
movq 0x2e8(%rsp), %rdi
leaq 0x2f8(%rsp), %rax
cmpq %rax, %rdi
je 0x2f55
movq 0x2f8(%rsp), %rsi
incq %rsi
callq 0x21e0
movq 0x180(%rsp), %rdi
leaq 0x190(%rsp), %rax
cmpq %rax, %rdi
je 0x2f7a
movq 0x190(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x170(%rsp), %rax
movq %rax, 0x160(%rsp)
leaq 0x160(%rsp), %r15
movq %r15, %rdi
leaq 0x20ce(%rip), %rsi      # 0x506a
leaq 0x20ca(%rip), %rdx      # 0x506d
callq 0x2950
movzbl %r13b, %edx
andl $0x1, %edx
movq %r15, %rdi
movl %ebp, %esi
callq 0x2bd8
movq 0x160(%rsp), %rdi
leaq 0x170(%rsp), %rax
cmpq %rax, %rdi
je 0x2fde
movq 0x170(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x78(%rsp), %r15
movq %r15, %rdi
callq 0x28be
movq %r15, %rdi
movl %r14d, %esi
movq %r12, %rdx
movl $0x10, %ecx
callq 0x280a
movq %rbx, %rdi
movl %r14d, %esi
movq %r12, %rdx
movl $0x10, %ecx
callq 0x2858
movb $0x1, %r13b
cmpl $0x2, %eax
jne 0x301d
movb $0x1, %al
jmp 0x3072
movzwl 0x50(%rsp), %edi
callq 0x2b90
movq %rbx, %rdi
callq 0x28be
movq %rbx, %rdi
movl $0x61, %esi
callq 0x2728
testb %al, %al
je 0x304d
movq %rbx, %rdi
movl $0x73, %esi
callq 0x2728
movzwl 0x52(%rsp), %r14d
movl %ebp, %edi
movl $0x1, %esi
callq 0x29e0
cmpw %ax, %r14w
setne %al
jne 0x3072
movzwl 0x50(%rsp), %ecx
movw %cx, 0x3a(%rsp)
testb %al, %al
movl 0x4(%rsp), %r14d
jne 0x2ec7
movl %ebp, %edi
movl $0x1, %esi
callq 0x29e0
movw %ax, 0xa(%rsp)
movzwl 0x50(%rsp), %edi
movl $0x1, %esi
callq 0x29e0
movw %ax, 0xc(%rsp)
leaq 0x2011(%rip), %rsi      # 0x50bc
leaq 0x2e0(%rsp), %rdi
movl $0x10, %edx
callq 0x2200
leaq 0x1e8(%rsp), %rdi
callq 0x26fc
leaq 0x2d8(%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)
movq %rsp, %r12
movzwl 0xc(%rsp), %eax
movw %ax, (%r12)
movw $0xd903, %r15w          # imm = 0xD903
xorl %ebp, %ebp
leaq 0x2a8(%rsp), %r13
leaq 0x1a0(%rsp), %rbx
movl $0x0, 0x3c(%rsp)
testb $0x1, %bpl
jne 0x3251
leaq 0x1b0(%rsp), %r15
movq %r15, 0x1a0(%rsp)
movq %rbx, %rdi
leaq 0x1f8b(%rip), %rsi      # 0x50cb
leaq 0x1f85(%rip), %rdx      # 0x50cc
callq 0x2950
movq %rbx, %r8
movzwl 0xa(%rsp), %esi
movzwl 0xc(%rsp), %ebx
leaq 0x10(%rsp), %rdi
movl %ebx, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
callq 0x251c
movq 0x10(%rsp), %rax
movq %rax, 0x78(%rsp)
leaq 0x80(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x2240
movq 0x18(%rsp), %rdi
leaq 0x28(%rsp), %rax
cmpq %rax, %rdi
je 0x31a2
movq 0x28(%rsp), %rsi
incq %rsi
callq 0x21e0
movq 0x1a0(%rsp), %rdi
cmpq %r15, %rdi
je 0x31bf
movq 0x1b0(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x150(%rsp), %rax
movq %rax, 0x140(%rsp)
leaq 0x140(%rsp), %r15
movq %r15, %rdi
leaq 0x1e9d(%rip), %rsi      # 0x507e
leaq 0x1e99(%rip), %rdx      # 0x5081
callq 0x2950
movzbl 0x3c(%rsp), %edx
andl $0x1, %edx
movq %r15, %rdi
movl %ebx, %esi
callq 0x2bd8
movq 0x140(%rsp), %rdi
leaq 0x150(%rsp), %rax
cmpq %rax, %rdi
je 0x3224
movq 0x150(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x78(%rsp), %rdi
callq 0x28be
movb $0x1, %al
movl %eax, 0x3c(%rsp)
leaq 0x78(%rsp), %rdi
movl %r14d, %esi
leaq 0x40(%rsp), %rdx
movl $0x10, %ecx
callq 0x280a
movzwl 0xc(%rsp), %r15d
leaq 0x50(%rsp), %rdi
movl %r14d, %esi
leaq 0x40(%rsp), %rdx
movl $0x10, %ecx
callq 0x2858
xorl %ebx, %ebx
cmpl $0x2, %eax
je 0x3577
movzwl 0x3a(%rsp), %eax
cmpw %ax, 0x50(%rsp)
je 0x3577
leaq 0x50(%rsp), %rdi
callq 0x28be
leaq 0x50(%rsp), %rdi
movl $0x46, %esi
callq 0x2728
movzwl 0x50(%rsp), %ecx
testb %al, %al
je 0x32b7
movb $0x1, %bl
movzwl %cx, %edi
callq 0x2b90
movb $0x1, %bpl
jmp 0x3577
movzwl %cx, %edi
callq 0x2b90
movq 0x60(%rsp), %rbx
movzwl 0x50(%rsp), %eax
movw %ax, 0x2(%rsp)
movzwl (%rsp), %edi
movl $0x3c00, %esi           # imm = 0x3C00
callq 0x29e0
leaq 0x18(%rsp), %r14
leaq 0x120(%rsp), %rbp
movzwl (%rsp), %ecx
movzwl 0x2(%rsp), %edx
cmpw %cx, %ax
jbe 0x3309
cmpw %cx, %dx
setb %sil
cmpw %ax, %dx
seta %al
orb %sil, %al
jmp 0x3319
cmpw %ax, %dx
seta %sil
cmpw %cx, %dx
setb %al
andb %sil, %al
testb %al, %al
jne 0x3434
cmpw %cx, 0x2(%rsp)
jne 0x340e
movq 0x58(%rsp), %rsi
leaq 0x2e0(%rsp), %rdi
movq %rbx, %rdx
callq 0x2260
movq %r13, %rdi
leaq 0x2(%rsp), %rsi
callq 0x3f2a
testq %rax, %rax
je 0x3360
movq %r13, %rdi
leaq 0x2(%rsp), %rsi
callq 0x3fa8
movzwl (%rsp), %edi
movzwl %bx, %esi
callq 0x29e0
movw %ax, (%rsp)
movq %r13, %rdi
movq %r12, %rsi
callq 0x3f2a
testq %rax, %rax
je 0x3434
movq %r13, %rdi
movq %r12, %rsi
callq 0x4090
movq (%rax), %rcx
movq %rcx, 0x10(%rsp)
leaq 0x28(%rsp), %rcx
movq %rcx, 0x18(%rsp)
movq 0x8(%rax), %rsi
movq 0x10(%rax), %rdx
addq %rsi, %rdx
movq %r14, %rdi
callq 0x28c0
movq 0x18(%rsp), %rsi
movq 0x20(%rsp), %rbx
leaq 0x2e0(%rsp), %rdi
movq %rbx, %rdx
callq 0x2260
movq %r13, %rdi
movq %r12, %rsi
callq 0x3fa8
movzwl (%rsp), %edi
movzwl %bx, %esi
callq 0x29e0
movw %ax, (%rsp)
movq 0x18(%rsp), %rdi
leaq 0x28(%rsp), %rax
cmpq %rax, %rdi
je 0x3370
movq 0x28(%rsp), %rsi
incq %rsi
callq 0x21e0
jmp 0x3370
movq %r13, %rdi
leaq 0x2(%rsp), %rsi
callq 0x4090
movq 0x50(%rsp), %rcx
movq %rcx, (%rax)
addq $0x8, %rax
movq %rax, %rdi
leaq 0x58(%rsp), %rsi
callq 0x20e0
movzwl (%rsp), %r14d
leaq 0x130(%rsp), %rax
movq %rax, 0x120(%rsp)
movq %rbp, %rdi
leaq 0x1c78(%rip), %rsi      # 0x50cb
leaq 0x1c72(%rip), %rdx      # 0x50cc
callq 0x2950
movzwl 0xa(%rsp), %esi
movzwl %r14w, %ebx
leaq 0x10(%rsp), %rdi
movl %ebx, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
movq %rbp, %r8
callq 0x251c
movq 0x10(%rsp), %rax
movq %rax, 0x1e8(%rsp)
leaq 0x1f0(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x2240
movq 0x18(%rsp), %rdi
leaq 0x28(%rsp), %rax
cmpq %rax, %rdi
je 0x34b7
movq 0x28(%rsp), %rsi
incq %rsi
callq 0x21e0
movq 0x120(%rsp), %rdi
leaq 0x130(%rsp), %rax
cmpq %rax, %rdi
je 0x34dc
movq 0x130(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x110(%rsp), %rax
movq %rax, 0x100(%rsp)
leaq 0x100(%rsp), %rbp
movq %rbp, %rdi
leaq 0x1b80(%rip), %rsi      # 0x507e
leaq 0x1b7c(%rip), %rdx      # 0x5081
callq 0x2950
xorl %edx, %edx
cmpw %r15w, %bx
sete %dl
movq %rbp, %rdi
movl %ebx, %esi
callq 0x2bd8
movq 0x100(%rsp), %rdi
leaq 0x110(%rsp), %rax
cmpq %rax, %rdi
je 0x3542
movq 0x110(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x1e8(%rsp), %rdi
callq 0x28be
leaq 0x1e8(%rsp), %rdi
movl 0x4(%rsp), %esi
leaq 0x40(%rsp), %rdx
movl $0x10, %ecx
callq 0x280a
movb $0x1, %bpl
xorl %ebx, %ebx
movl %r14d, %r15d
movl 0x4(%rsp), %r14d
testb %bl, %bl
leaq 0x1a0(%rsp), %rbx
je 0x311c
movzwl 0x50(%rsp), %edi
movl $0x1, %esi
callq 0x29e0
movl %eax, %r14d
leaq 0x260(%rsp), %r12
movq %r12, -0x10(%r12)
leaq 0x1b1d(%rip), %rsi      # 0x50ca
leaq 0x1b18(%rip), %rdx      # 0x50cc
leaq 0x250(%rsp), %rdi
callq 0x2950
movzwl 0xa(%rsp), %esi
movzwl %r14w, %ebx
leaq 0x10(%rsp), %rdi
leaq 0x250(%rsp), %r8
movl %esi, 0xc(%rsp)
movl %ebx, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
callq 0x251c
leaq 0x18(%rsp), %r15
movq -0x8(%r15), %rax
movq %rax, 0x78(%rsp)
leaq 0x80(%rsp), %rdi
movq %r15, %rsi
callq 0x2240
movq (%r15), %rdi
leaq 0x28(%rsp), %rax
cmpq %rax, %rdi
je 0x361f
movq 0x28(%rsp), %rsi
incq %rsi
callq 0x21e0
movq 0x250(%rsp), %rdi
cmpq %r12, %rdi
je 0x363c
movq 0x260(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x78(%rsp), %rdi
leaq 0x40(%rsp), %rdx
movl 0x4(%rsp), %esi
movl $0x10, %ecx
callq 0x280a
leaq 0x240(%rsp), %r15
movq %r15, -0x10(%r15)
leaq 0x1a66(%rip), %rsi      # 0x50cd
leaq 0x1a62(%rip), %rdx      # 0x50d0
leaq 0x230(%rsp), %rdi
callq 0x2950
leaq 0x230(%rsp), %rdi
movl %ebx, %esi
xorl %edx, %edx
callq 0x2bd8
movq 0x230(%rsp), %rdi
cmpq %r15, %rdi
je 0x36a9
movq 0x240(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x78(%rsp), %rdi
callq 0x28be
xorl %r15d, %r15d
leaq 0x78(%rsp), %r12
xorl %ebp, %ebp
leaq 0xf0(%rsp), %rax
movq %rax, 0xe0(%rsp)
leaq 0xe0(%rsp), %r13
movq %r13, %rdi
leaq 0x19f2(%rip), %rsi      # 0x50d1
leaq 0x19ec(%rip), %rdx      # 0x50d2
callq 0x2950
movzwl %r14w, %ebx
leaq 0x10(%rsp), %rdi
movl 0xc(%rsp), %esi
movl %ebx, %edx
movl $0x3c00, %ecx           # imm = 0x3C00
movq %r13, %r8
callq 0x251c
movq 0x10(%rsp), %rax
movq %rax, 0x78(%rsp)
leaq 0x80(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x2240
movq 0x18(%rsp), %rdi
leaq 0x28(%rsp), %rax
cmpq %rax, %rdi
je 0x373f
movq 0x28(%rsp), %rsi
incq %rsi
callq 0x21e0
movq 0xe0(%rsp), %rdi
leaq 0xf0(%rsp), %rax
cmpq %rax, %rdi
je 0x3764
movq 0xf0(%rsp), %rsi
incq %rsi
callq 0x21e0
movq %r12, %rdi
movl 0x4(%rsp), %esi
leaq 0x40(%rsp), %rdx
movl $0x10, %ecx
callq 0x280a
leaq 0xd0(%rsp), %rax
movq %rax, 0xc0(%rsp)
leaq 0xc0(%rsp), %r13
movq %r13, %rdi
leaq 0x1931(%rip), %rsi      # 0x50cd
leaq 0x192d(%rip), %rdx      # 0x50d0
callq 0x2950
movzbl %bpl, %edx
andl $0x1, %edx
movq %r13, %rdi
movl %ebx, %esi
callq 0x2bd8
movq 0xc0(%rsp), %rdi
leaq 0xd0(%rsp), %rax
cmpq %rax, %rdi
je 0x37de
movq 0xd0(%rsp), %rsi
incq %rsi
callq 0x21e0
movq %r12, %rdi
callq 0x28be
leaq 0x50(%rsp), %rdi
movl 0x4(%rsp), %esi
leaq 0x40(%rsp), %rdx
movl $0x10, %ecx
callq 0x2858
cmpl $0x2, %eax
je 0x395c
movzwl 0x50(%rsp), %edi
callq 0x2b90
movzwl 0x56(%rsp), %eax
cmpl $0x4, %eax
je 0x3959
cmpl $0x1, %eax
jne 0x395c
leaq 0x220(%rsp), %r14
movq %r14, 0x210(%rsp)
leaq 0x210(%rsp), %r13
movq %r13, %rdi
leaq 0x1883(%rip), %rsi      # 0x50cd
leaq 0x187f(%rip), %rdx      # 0x50d0
callq 0x2950
movq %r13, %rdi
movl %ebx, %esi
movl $0x1, %edx
callq 0x2bd8
movq 0x210(%rsp), %rdi
cmpq %r14, %rdi
je 0x3882
movq 0x220(%rsp), %rsi
incq %rsi
callq 0x21e0
movzwl 0x50(%rsp), %edi
movl $0x1, %esi
callq 0x29e0
movl %eax, %r14d
leaq 0xb0(%rsp), %rax
movq %rax, 0xa0(%rsp)
leaq 0xa0(%rsp), %rbx
movq %rbx, %rdi
leaq 0x1814(%rip), %rsi      # 0x50ca
leaq 0x180f(%rip), %rdx      # 0x50cc
callq 0x2950
movzwl %r14w, %edx
leaq 0x10(%rsp), %rdi
movl 0xc(%rsp), %esi
movl $0x3c00, %ecx           # imm = 0x3C00
movq %rbx, %r8
callq 0x251c
movq 0x10(%rsp), %rax
movq %rax, 0x78(%rsp)
leaq 0x80(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x2240
movq 0x18(%rsp), %rdi
leaq 0x28(%rsp), %rax
cmpq %rax, %rdi
je 0x3914
movq 0x28(%rsp), %rsi
incq %rsi
callq 0x21e0
movq 0xa0(%rsp), %rdi
leaq 0xb0(%rsp), %rax
cmpq %rax, %rdi
je 0x3939
movq 0xb0(%rsp), %rsi
incq %rsi
callq 0x21e0
movq %r12, %rdi
movl 0x4(%rsp), %esi
leaq 0x40(%rsp), %rdx
movl $0x10, %ecx
callq 0x280a
movq %r12, %rdi
callq 0x28be
jmp 0x395c
movb $0x1, %r15b
movb $0x1, %bpl
testb $0x1, %r15b
je 0x36bd
movl 0x4(%rsp), %edi
callq 0x2340
leaq 0x2e0(%rsp), %rdi
callq 0x2290
leaq 0x2a8(%rsp), %rdi
callq 0x3e8c
leaq 0x200(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x39ad
movq 0x200(%rsp), %rsi
incq %rsi
callq 0x21e0
movq 0x3614(%rip), %rax      # 0x6fc8
movq (%rax), %rcx
movq 0x18(%rax), %rax
leaq 0x2e8(%rsp), %rdi
movq %rcx, -0x8(%rdi)
movq -0x18(%rcx), %rcx
movq %rax, 0x2e0(%rsp,%rcx)
callq 0x2180
leaq 0x3d8(%rsp), %rdi
callq 0x20a0
leaq 0x68(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3a00
movq 0x68(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x90(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3a21
movq 0x90(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x280(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3a42
movq 0x280(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x1d8(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3a63
movq 0x1d8(%rsp), %rsi
incq %rsi
callq 0x21e0
xorl %eax, %eax
addq $0x518, %rsp            # imm = 0x518
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x3572(%rip), %rdi      # 0x6ff0
leaq 0x15fd(%rip), %rsi      # 0x5082
callq 0x21c0
movq (%rbx), %rsi
movq %rax, %rdi
callq 0x21c0
leaq 0x15ee(%rip), %rsi      # 0x508a
movq %rax, %rdi
callq 0x21c0
movq %rax, %rdi
movl $0xa, %esi
callq 0x2220
movl $0x1, %edi
callq 0x2230
movl $0x2, %edi
callq 0x2230
movl $0x3, %edi
callq 0x2230
callq 0x23b4
leaq 0x15f8(%rip), %rdi      # 0x50d3
callq 0x2100
leaq 0x15ec(%rip), %rdi      # 0x50d3
callq 0x22a0
callq 0x239f
movq %rax, %rbx
movq 0x230(%rsp), %rdi
cmpq %r15, %rdi
je 0x3d83
movq 0x240(%rsp), %rsi
jmp 0x3d7b
jmp 0x3d5f
movq %rax, %rbx
movq 0x250(%rsp), %rdi
cmpq %r12, %rdi
je 0x3d83
movq 0x260(%rsp), %rsi
jmp 0x3d7b
jmp 0x3d5f
movq %rax, %rbx
jmp 0x3db1
jmp 0x3d5a
jmp 0x3d5a
jmp 0x3d5a
movq %rax, %rbx
jmp 0x3dd9
jmp 0x3b62
jmp 0x3b62
jmp 0x3b62
movq %rax, %rbx
jmp 0x3dfa
movq %rax, %rbx
jmp 0x3e1b
movq %rax, %rbx
cmpl $0x0, (%r14)
jne 0x3dfa
movl %ebp, (%r14)
jmp 0x3dfa
jmp 0x3d5f
movq %rax, %rbx
movq 0xa0(%rsp), %rdi
leaq 0xb0(%rsp), %rax
cmpq %rax, %rdi
je 0x3d83
movq 0xb0(%rsp), %rsi
jmp 0x3d7b
jmp 0x3d5f
movq %rax, %rbx
movq 0x210(%rsp), %rdi
cmpq %r14, %rdi
je 0x3d83
movq 0x220(%rsp), %rsi
jmp 0x3d7b
jmp 0x3d5f
jmp 0x3d5f
movq %rax, %rbx
movq 0x100(%rsp), %rdi
leaq 0x110(%rsp), %rax
cmpq %rax, %rdi
je 0x3d83
movq 0x110(%rsp), %rsi
jmp 0x3d7b
jmp 0x3d5f
movq %rax, %rbx
movq 0x120(%rsp), %rdi
leaq 0x130(%rsp), %rax
cmpq %rax, %rdi
je 0x3d83
movq 0x130(%rsp), %rsi
jmp 0x3d7b
jmp 0x3d5f
jmp 0x3d5f
jmp 0x3d5f
movq %rax, %rbx
movq 0x1a0(%rsp), %rdi
cmpq %r15, %rdi
je 0x3d83
movq 0x1b0(%rsp), %rsi
jmp 0x3d7b
movq %rax, %rbx
movq 0x140(%rsp), %rdi
leaq 0x150(%rsp), %rax
cmpq %rax, %rdi
je 0x3d83
movq 0x150(%rsp), %rsi
jmp 0x3d7b
jmp 0x3d5f
jmp 0x3d5f
movq %rax, %rbx
movq 0xe0(%rsp), %rdi
leaq 0xf0(%rsp), %rax
cmpq %rax, %rdi
je 0x3d83
movq 0xf0(%rsp), %rsi
jmp 0x3d7b
jmp 0x3d5f
movq %rax, %rbx
movq 0xc0(%rsp), %rdi
leaq 0xd0(%rsp), %rax
cmpq %rax, %rdi
je 0x3d83
movq 0xd0(%rsp), %rsi
jmp 0x3d7b
jmp 0x3d5f
jmp 0x3d5a
movq %rax, %rbx
movq 0x180(%rsp), %rdi
leaq 0x190(%rsp), %rax
cmpq %rax, %rdi
je 0x3dbe
movq 0x190(%rsp), %rsi
jmp 0x3d46
jmp 0x3d5a
movq %rax, %rbx
movq 0x160(%rsp), %rdi
leaq 0x170(%rsp), %rax
cmpq %rax, %rdi
je 0x3dbe
movq 0x170(%rsp), %rsi
incq %rsi
callq 0x21e0
jmp 0x3dbe
jmp 0x3d5f
jmp 0x3d5f
jmp 0x3d5f
jmp 0x3d5a
jmp 0x3d5f
movq %rax, %rbx
jmp 0x3dbe
movq %rax, %rbx
jmp 0x3d83
movq %rax, %rbx
movq 0x18(%rsp), %rdi
leaq 0x28(%rsp), %rax
cmpq %rax, %rdi
je 0x3d83
movq 0x28(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x2a8(%rsp), %rdi
callq 0x3e8c
leaq 0x200(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3db1
movq 0x200(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x2e0(%rsp), %rdi
callq 0x22c0
leaq 0x68(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3dd9
movq 0x68(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x90(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3dfa
movq 0x90(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x280(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3e1b
movq 0x280(%rsp), %rsi
incq %rsi
callq 0x21e0
leaq 0x1d8(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3e3c
movq 0x1d8(%rsp), %rsi
incq %rsi
callq 0x21e0
movq %rbx, %rdi
callq 0x2310