// File: 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
movq %rsp, %rbp
subq $0x890, %rsp            # imm = 0x890
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x3, -0x8(%rbp)
je 0x33d7
movq 0x7c5a(%rip), %rdi      # 0xaff0
leaq 0x3cec(%rip), %rsi      # 0x7089
callq 0x2220
movq %rax, %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rsi
callq 0x2220
movq %rax, %rdi
leaq 0x3cd6(%rip), %rsi      # 0x7091
callq 0x2220
movq %rax, %rdi
movl $0xa, %esi
callq 0x22b0
movl $0x1, %edi
callq 0x22c0
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x720(%rbp)
leaq -0x31(%rbp), %rdi
movq %rdi, -0x718(%rbp)
callq 0x23d0
movq -0x720(%rbp), %rsi
movq -0x718(%rbp), %rdx
leaq -0x30(%rbp), %rdi
callq 0x2bc0
jmp 0x340f
leaq -0x31(%rbp), %rdi
callq 0x2270
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x730(%rbp)
leaq -0x69(%rbp), %rdi
movq %rdi, -0x728(%rbp)
callq 0x23d0
movq -0x730(%rbp), %rsi
movq -0x728(%rbp), %rdx
leaq -0x68(%rbp), %rdi
callq 0x2bc0
jmp 0x3450
leaq -0x69(%rbp), %rdi
callq 0x2270
xorps %xmm0, %xmm0
movaps %xmm0, -0x80(%rbp)
movaps %xmm0, -0x90(%rbp)
movaps %xmm0, -0xa0(%rbp)
movl $0x2, -0x9c(%rbp)
movl $0x1, -0x98(%rbp)
movl $0x0, -0xac(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x20f0
movq %rax, -0x740(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x20f0
movq -0x740(%rbp), %rdi
movq %rax, %rsi
leaq -0xa0(%rbp), %rdx
leaq -0xa8(%rbp), %rcx
callq 0x22f0
movl %eax, -0x734(%rbp)
jmp 0x34ca
movl -0x734(%rbp), %eax
movl %eax, -0xac(%rbp)
cmpl $0x0, %eax
je 0x352a
movl $0x2, %edi
callq 0x22c0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x31(%rbp), %rdi
callq 0x2270
jmp 0x49d6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x69(%rbp), %rdi
callq 0x2270
jmp 0x49cd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x49c4
movq -0xa8(%rbp), %rax
movq %rax, -0xb8(%rbp)
leaq -0xd0(%rbp), %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x2120
cmpq $0x0, -0xb8(%rbp)
je 0x358f
movq -0xb8(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0xc0(%rbp)
movq -0xb8(%rbp), %rax
movl 0x4(%rax), %edi
movq -0xc0(%rbp), %rsi
addq $0x4, %rsi
leaq -0xd0(%rbp), %rdx
movl $0x10, %ecx
callq 0x2260
jmp 0x3599
movl $0x3, %edi
callq 0x22c0
leaq -0x30(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
callq 0x2330
jmp 0x35ab
xorl %eax, %eax
movl %eax, %edi
callq 0x2200
movl %eax, %edi
callq 0x2210
movl $0x2, %esi
xorl %edx, %edx
movl %esi, %edi
callq 0x2090
movl %eax, -0xd4(%rbp)
cmpl $-0x1, -0xd4(%rbp)
jne 0x35f0
leaq 0x3ad1(%rip), %rdi      # 0x70b0
callq 0x21c0
jmp 0x35e6
movl $0x1, %edi
callq 0x22c0
movq $0x0, -0xe8(%rbp)
movq $0x7a120, -0xe0(%rbp) # imm = 0x7A120
movl -0xd4(%rbp), %edi
movups -0xe8(%rbp), %xmm0
movaps %xmm0, -0x100(%rbp)
movq -0x100(%rbp), %rsi
movq -0xf8(%rbp), %rdx
callq 0x30d0
jmp 0x362f
xorps %xmm0, %xmm0
movaps %xmm0, -0x110(%rbp)
movw $0x2, -0x110(%rbp)
xorl %eax, %eax
movl %eax, %esi
leaq -0x68(%rbp), %rdi
movl $0xa, %edx
callq 0x4a10
movl %eax, -0x744(%rbp)
jmp 0x365c
movl -0x744(%rbp), %eax
movzwl %ax, %edi
callq 0x2050
movw %ax, -0x10e(%rbp)
movl $0x10, -0x114(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x20f0
movq %rax, %rdi
leaq -0x110(%rbp), %rsi
addq $0x4, %rsi
callq 0x2180
cmpl $0x0, %eax
jne 0x36b4
leaq 0x3a14(%rip), %rdi      # 0x70b7
callq 0x21c0
jmp 0x36aa
movl $0x1, %edi
callq 0x22c0
callq 0x20a0
movslq %eax, %rcx
imulq $-0x77777777, %rcx, %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
movw %ax, -0x116(%rbp)
movw $0x0, -0x118(%rbp)
movw $0x3c00, -0x11a(%rbp)   # imm = 0x3C00
leaq -0x148(%rbp), %rdi
callq 0x27b0
jmp 0x3702
leaq -0x170(%rbp), %rdi
callq 0x27b0
jmp 0x3710
movb $0x0, -0x173(%rbp)
jmp 0x3719
movw -0x116(%rbp), %ax
movw %ax, -0x756(%rbp)
movw -0x118(%rbp), %ax
movw %ax, -0x754(%rbp)
movw -0x11a(%rbp), %ax
movw %ax, -0x752(%rbp)
leaq -0x1c1(%rbp), %rdi
movq %rdi, -0x750(%rbp)
callq 0x23d0
movq -0x750(%rbp), %rdx
leaq 0x395d(%rip), %rsi      # 0x70c1
leaq -0x1c0(%rbp), %rdi
callq 0x2bc0
jmp 0x3772
movw -0x752(%rbp), %ax
movw -0x754(%rbp), %cx
movw -0x756(%rbp), %dx
movzwl %dx, %esi
movzwl %cx, %edx
movzwl %ax, %ecx
leaq -0x1a0(%rbp), %rdi
leaq -0x1c0(%rbp), %r8
callq 0x25b0
jmp 0x37a5
leaq -0x148(%rbp), %rdi
leaq -0x1a0(%rbp), %rsi
movq %rsi, -0x768(%rbp)
callq 0x4a50
movq -0x768(%rbp), %rdi
callq 0x4a90
leaq -0x1c0(%rbp), %rdi
callq 0x2140
leaq -0x1c1(%rbp), %rdi
callq 0x2270
leaq -0x1e9(%rbp), %rdi
movq %rdi, -0x760(%rbp)
callq 0x23d0
movq -0x760(%rbp), %rdx
leaq 0x386d(%rip), %rsi      # 0x7071
leaq -0x1e8(%rbp), %rdi
callq 0x2bc0
jmp 0x3812
movzwl -0x116(%rbp), %esi
movzbl -0x173(%rbp), %edx
andl $0x1, %edx
leaq -0x1e8(%rbp), %rdi
callq 0x32a0
jmp 0x3831
leaq -0x1e8(%rbp), %rdi
callq 0x2140
leaq -0x1e9(%rbp), %rdi
callq 0x2270
movb $0x1, -0x173(%rbp)
leaq -0x148(%rbp), %rdi
callq 0x2bb0
jmp 0x385e
movl -0xd4(%rbp), %esi
movl -0x114(%rbp), %ecx
leaq -0x148(%rbp), %rdi
leaq -0x110(%rbp), %rdx
callq 0x2a80
jmp 0x387f
movl -0xd4(%rbp), %esi
movl -0x114(%rbp), %ecx
leaq -0x170(%rbp), %rdi
leaq -0x110(%rbp), %rdx
callq 0x2b00
movl %eax, -0x76c(%rbp)
jmp 0x38a6
movl -0x76c(%rbp), %eax
movl %eax, -0x1f0(%rbp)
cmpl $0x2, -0x1f0(%rbp)
jne 0x3954
jmp 0x3717
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x49b8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x38fb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x1c0(%rbp), %rdi
callq 0x2140
leaq -0x1c1(%rbp), %rdi
callq 0x2270
jmp 0x49ac
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x3932
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x1e8(%rbp), %rdi
callq 0x2140
leaq -0x1e9(%rbp), %rdi
callq 0x2270
jmp 0x49ac
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x49ac
movzwl -0x170(%rbp), %edi
callq 0x3250
jmp 0x3962
leaq -0x170(%rbp), %rdi
callq 0x2bb0
jmp 0x3970
leaq -0x170(%rbp), %rdi
movl $0x61, %esi
callq 0x2830
movb %al, -0x76d(%rbp)
jmp 0x3989
movb -0x76d(%rbp), %al
testb $0x1, %al
jne 0x3995
jmp 0x39ba
leaq -0x170(%rbp), %rdi
movl $0x73, %esi
callq 0x2830
movb %al, -0x76e(%rbp)
jmp 0x39ae
movb -0x76e(%rbp), %al
testb $0x1, %al
jne 0x39bc
jmp 0x39ba
jmp 0x39bc
movzwl -0x16e(%rbp), %eax
movl %eax, -0x774(%rbp)
movzwl -0x116(%rbp), %edi
movl $0x1, %esi
callq 0x2f10
movw %ax, -0x770(%rbp)
jmp 0x39e3
movl -0x774(%rbp), %eax
movw -0x770(%rbp), %cx
movzwl %cx, %ecx
cmpl %ecx, %eax
je 0x39fc
jmp 0x3717
movw -0x170(%rbp), %ax
movw %ax, -0x172(%rbp)
movzwl -0x116(%rbp), %edi
movl $0x1, %esi
callq 0x2f10
movw %ax, -0x776(%rbp)
jmp 0x3a24
movw -0x776(%rbp), %ax
movw %ax, -0x116(%rbp)
movw -0x116(%rbp), %ax
movw %ax, -0x1f2(%rbp)
movzwl -0x170(%rbp), %edi
movl $0x1, %esi
callq 0x2f10
movw %ax, -0x778(%rbp)
jmp 0x3a5a
movw -0x778(%rbp), %ax
movw %ax, -0x118(%rbp)
movw -0x118(%rbp), %ax
movw %ax, -0x1f4(%rbp)
leaq 0x3646(%rip), %rsi      # 0x70c3
leaq -0x3f8(%rbp), %rdi
movl $0x10, %edx
callq 0x2280
jmp 0x3a90
movb $0x0, -0x3f9(%rbp)
leaq -0x428(%rbp), %rdi
callq 0x27b0
jmp 0x3aa5
leaq -0x460(%rbp), %rdi
callq 0x4ab0
movw -0x118(%rbp), %ax
movw %ax, -0x462(%rbp)
movw $0xd903, -0x464(%rbp)   # imm = 0xD903
movb $0x0, -0x465(%rbp)
jmp 0x3ad1
testb $0x1, -0x3f9(%rbp)
jne 0x3ce7
movw -0x1f2(%rbp), %ax
movw %ax, -0x786(%rbp)
movw -0x1f4(%rbp), %ax
movw %ax, -0x784(%rbp)
movw -0x11a(%rbp), %ax
movw %ax, -0x782(%rbp)
leaq -0x4b1(%rbp), %rdi
movq %rdi, -0x780(%rbp)
callq 0x23d0
movq -0x780(%rbp), %rdx
leaq 0x35a9(%rip), %rsi      # 0x70d2
leaq -0x4b0(%rbp), %rdi
callq 0x2bc0
jmp 0x3b37
movw -0x782(%rbp), %ax
movw -0x784(%rbp), %cx
movw -0x786(%rbp), %dx
movzwl %dx, %esi
movzwl %cx, %edx
movzwl %ax, %ecx
leaq -0x490(%rbp), %rdi
leaq -0x4b0(%rbp), %r8
callq 0x25b0
jmp 0x3b6a
leaq -0x148(%rbp), %rdi
leaq -0x490(%rbp), %rsi
movq %rsi, -0x798(%rbp)
callq 0x4a50
movq -0x798(%rbp), %rdi
callq 0x4a90
leaq -0x4b0(%rbp), %rdi
callq 0x2140
leaq -0x4b1(%rbp), %rdi
callq 0x2270
leaq -0x4d9(%rbp), %rdi
movq %rdi, -0x790(%rbp)
callq 0x23d0
movq -0x790(%rbp), %rdx
leaq 0x34bc(%rip), %rsi      # 0x7085
leaq -0x4d8(%rbp), %rdi
callq 0x2bc0
jmp 0x3bd7
movzwl -0x1f4(%rbp), %esi
movzbl -0x465(%rbp), %edx
andl $0x1, %edx
leaq -0x4d8(%rbp), %rdi
callq 0x32a0
jmp 0x3bf6
leaq -0x4d8(%rbp), %rdi
callq 0x2140
leaq -0x4d9(%rbp), %rdi
callq 0x2270
movw -0x1f4(%rbp), %ax
movw %ax, -0x464(%rbp)
leaq -0x148(%rbp), %rdi
callq 0x2bb0
jmp 0x3c2a
movl -0xd4(%rbp), %esi
movl -0x114(%rbp), %ecx
leaq -0x148(%rbp), %rdi
leaq -0x110(%rbp), %rdx
callq 0x2a80
jmp 0x3c4b
movb $0x1, -0x465(%rbp)
jmp 0x3ce7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x49a0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x3c8e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x4b0(%rbp), %rdi
callq 0x2140
leaq -0x4b1(%rbp), %rdi
callq 0x2270
jmp 0x4988
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x3cc5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x4d8(%rbp), %rdi
callq 0x2140
leaq -0x4d9(%rbp), %rdi
callq 0x2270
jmp 0x4988
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x4988
movl -0xd4(%rbp), %esi
movl -0x114(%rbp), %ecx
leaq -0x170(%rbp), %rdi
leaq -0x110(%rbp), %rdx
callq 0x2b00
movl %eax, -0x79c(%rbp)
jmp 0x3d0e
movl -0x79c(%rbp), %eax
movl %eax, -0x4e0(%rbp)
cmpl $0x2, -0x4e0(%rbp)
jne 0x3d28
jmp 0x3acf
movzwl -0x170(%rbp), %eax
movzwl -0x172(%rbp), %ecx
cmpl %ecx, %eax
jne 0x3d3f
jmp 0x3acf
movb $0x1, -0x3f9(%rbp)
leaq -0x170(%rbp), %rdi
callq 0x2bb0
jmp 0x3d54
leaq -0x170(%rbp), %rdi
movl $0x46, %esi
callq 0x2830
movb %al, -0x79d(%rbp)
jmp 0x3d6d
movb -0x79d(%rbp), %al
testb $0x1, %al
jne 0x3d79
jmp 0x3d8c
movzwl -0x170(%rbp), %edi
callq 0x3250
jmp 0x3d87
jmp 0x4289
movzwl -0x170(%rbp), %edi
callq 0x3250
jmp 0x3d9a
leaq -0x168(%rbp), %rdi
callq 0x2160
movq %rax, -0x4e8(%rbp)
movw -0x170(%rbp), %ax
movw %ax, -0x4ea(%rbp)
movb $0x0, -0x4eb(%rbp)
movzwl -0x462(%rbp), %edi
movzwl -0x11a(%rbp), %esi
callq 0x2f10
movw %ax, -0x7a0(%rbp)
jmp 0x3dde
movw -0x7a0(%rbp), %ax
movw %ax, -0x4ee(%rbp)
movzwl -0x4ee(%rbp), %eax
movzwl -0x462(%rbp), %ecx
cmpl %ecx, %eax
jle 0x3e41
movzwl -0x4ea(%rbp), %ecx
movzwl -0x462(%rbp), %edx
movb $0x1, %al
cmpl %edx, %ecx
movb %al, -0x7a1(%rbp)
jl 0x3e31
movzwl -0x4ea(%rbp), %eax
movzwl -0x4ee(%rbp), %ecx
cmpl %ecx, %eax
setg %al
movb %al, -0x7a1(%rbp)
movb -0x7a1(%rbp), %al
andb $0x1, %al
movb %al, -0x4eb(%rbp)
jmp 0x3e82
movzwl -0x4ea(%rbp), %ecx
movzwl -0x4ee(%rbp), %edx
xorl %eax, %eax
cmpl %edx, %ecx
movb %al, -0x7a2(%rbp)
jle 0x3e74
movzwl -0x4ea(%rbp), %eax
movzwl -0x462(%rbp), %ecx
cmpl %ecx, %eax
setl %al
movb %al, -0x7a2(%rbp)
movb -0x7a2(%rbp), %al
andb $0x1, %al
movb %al, -0x4eb(%rbp)
testb $0x1, -0x4eb(%rbp)
je 0x3e8d
jmp 0x3e8d
testb $0x1, -0x4eb(%rbp)
jne 0x4094
movzwl -0x4ea(%rbp), %eax
movzwl -0x462(%rbp), %ecx
cmpl %ecx, %eax
jne 0x405f
leaq -0x168(%rbp), %rdi
callq 0x20f0
movq %rax, -0x4f8(%rbp)
movq -0x4f8(%rbp), %rsi
movq -0x4e8(%rbp), %rdx
leaq -0x3f8(%rbp), %rdi
callq 0x2300
jmp 0x3edf
leaq -0x460(%rbp), %rdi
leaq -0x4ea(%rbp), %rsi
callq 0x4ad0
movq %rax, -0x7b0(%rbp)
jmp 0x3efb
movq -0x7b0(%rbp), %rax
cmpq $0x0, %rax
je 0x3f1f
leaq -0x460(%rbp), %rdi
leaq -0x4ea(%rbp), %rsi
callq 0x4b00
jmp 0x3f1d
jmp 0x3f1f
movzwl -0x462(%rbp), %edi
movzwl -0x4e8(%rbp), %esi
callq 0x2f10
movw %ax, -0x7b2(%rbp)
jmp 0x3f3b
movw -0x7b2(%rbp), %ax
movw %ax, -0x462(%rbp)
leaq -0x460(%rbp), %rdi
leaq -0x462(%rbp), %rsi
callq 0x4ad0
movq %rax, -0x7c0(%rbp)
jmp 0x3f65
movq -0x7c0(%rbp), %rax
cmpq $0x0, %rax
je 0x405d
leaq -0x460(%rbp), %rdi
leaq -0x462(%rbp), %rsi
callq 0x4b30
movq %rax, -0x7c8(%rbp)
jmp 0x3f92
movq -0x7c8(%rbp), %rsi
leaq -0x520(%rbp), %rdi
callq 0x4b60
jmp 0x3fa7
leaq -0x518(%rbp), %rdi
movq %rdi, -0x7d0(%rbp)
callq 0x20f0
movq -0x7d0(%rbp), %rdi
movq %rax, -0x528(%rbp)
callq 0x2160
movq %rax, -0x530(%rbp)
movq -0x528(%rbp), %rsi
movq -0x530(%rbp), %rdx
leaq -0x3f8(%rbp), %rdi
callq 0x2300
jmp 0x3ff0
leaq -0x460(%rbp), %rdi
leaq -0x462(%rbp), %rsi
callq 0x4b00
jmp 0x4005
movzwl -0x462(%rbp), %edi
movzwl -0x530(%rbp), %esi
callq 0x2f10
movw %ax, -0x7d2(%rbp)
jmp 0x4021
movw -0x7d2(%rbp), %ax
movw %ax, -0x462(%rbp)
leaq -0x520(%rbp), %rdi
callq 0x4a90
jmp 0x3f49
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x520(%rbp), %rdi
callq 0x4a90
jmp 0x4988
jmp 0x4092
leaq -0x460(%rbp), %rdi
leaq -0x4ea(%rbp), %rsi
callq 0x4b30
movq %rax, -0x7e0(%rbp)
jmp 0x407b
movq -0x7e0(%rbp), %rdi
leaq -0x170(%rbp), %rsi
callq 0x4ba0
jmp 0x4090
jmp 0x4092
jmp 0x4094
movw -0x462(%rbp), %ax
movw %ax, -0x118(%rbp)
movw -0x116(%rbp), %ax
movw %ax, -0x7ee(%rbp)
movw -0x118(%rbp), %ax
movw %ax, -0x7ec(%rbp)
movw -0x11a(%rbp), %ax
movw %ax, -0x7ea(%rbp)
leaq -0x579(%rbp), %rdi
movq %rdi, -0x7e8(%rbp)
callq 0x23d0
movq -0x7e8(%rbp), %rdx
leaq 0x2fe5(%rip), %rsi      # 0x70d2
leaq -0x578(%rbp), %rdi
callq 0x2bc0
jmp 0x40fb
movw -0x7ea(%rbp), %ax
movw -0x7ec(%rbp), %cx
movw -0x7ee(%rbp), %dx
movzwl %dx, %esi
movzwl %cx, %edx
movzwl %ax, %ecx
leaq -0x558(%rbp), %rdi
leaq -0x578(%rbp), %r8
callq 0x25b0
jmp 0x412e
leaq -0x428(%rbp), %rdi
leaq -0x558(%rbp), %rsi
movq %rsi, -0x800(%rbp)
callq 0x4a50
movq -0x800(%rbp), %rdi
callq 0x4a90
leaq -0x578(%rbp), %rdi
callq 0x2140
leaq -0x579(%rbp), %rdi
callq 0x2270
leaq -0x5a1(%rbp), %rdi
movq %rdi, -0x7f8(%rbp)
callq 0x23d0
movq -0x7f8(%rbp), %rdx
leaq 0x2ef8(%rip), %rsi      # 0x7085
leaq -0x5a0(%rbp), %rdi
callq 0x2bc0
jmp 0x419b
movzwl -0x118(%rbp), %esi
movzwl -0x464(%rbp), %ecx
movl %esi, %eax
subl %ecx, %eax
sete %al
movzbl %al, %edx
leaq -0x5a0(%rbp), %rdi
callq 0x32a0
jmp 0x41c1
leaq -0x5a0(%rbp), %rdi
callq 0x2140
leaq -0x5a1(%rbp), %rdi
callq 0x2270
leaq -0x428(%rbp), %rdi
callq 0x2bb0
jmp 0x41e7
movl -0xd4(%rbp), %esi
movl -0x114(%rbp), %ecx
leaq -0x428(%rbp), %rdi
leaq -0x110(%rbp), %rdx
callq 0x2a80
jmp 0x4208
movw -0x118(%rbp), %ax
movw %ax, -0x464(%rbp)
jmp 0x3acf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x4241
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x578(%rbp), %rdi
callq 0x2140
leaq -0x579(%rbp), %rdi
callq 0x2270
jmp 0x4988
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x4278
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x5a0(%rbp), %rdi
callq 0x2140
leaq -0x5a1(%rbp), %rdi
callq 0x2270
jmp 0x4988
movb $0x0, -0x5a2(%rbp)
movb $0x0, -0x5a3(%rbp)
movb $0x0, -0x5a4(%rbp)
movzwl -0x170(%rbp), %edi
movl $0x1, %esi
callq 0x2f10
movw %ax, -0x802(%rbp)
jmp 0x42b8
movw -0x802(%rbp), %ax
movw %ax, -0x118(%rbp)
movw -0x116(%rbp), %ax
movw %ax, -0x816(%rbp)
movw -0x118(%rbp), %ax
movw %ax, -0x814(%rbp)
movw -0x11a(%rbp), %ax
movw %ax, -0x812(%rbp)
leaq -0x5f1(%rbp), %rdi
movq %rdi, -0x810(%rbp)
callq 0x23d0
movq -0x810(%rbp), %rdx
leaq 0x2dc0(%rip), %rsi      # 0x70d1
leaq -0x5f0(%rbp), %rdi
callq 0x2bc0
jmp 0x431f
movw -0x812(%rbp), %ax
movw -0x814(%rbp), %cx
movw -0x816(%rbp), %dx
movzwl %dx, %esi
movzwl %cx, %edx
movzwl %ax, %ecx
leaq -0x5d0(%rbp), %rdi
leaq -0x5f0(%rbp), %r8
callq 0x25b0
jmp 0x4352
leaq -0x148(%rbp), %rdi
movq %rdi, -0x820(%rbp)
leaq -0x5d0(%rbp), %rsi
movq %rsi, -0x828(%rbp)
callq 0x4a50
movq -0x828(%rbp), %rdi
callq 0x4a90
leaq -0x5f0(%rbp), %rdi
callq 0x2140
leaq -0x5f1(%rbp), %rdi
callq 0x2270
movq -0x820(%rbp), %rdi
movl -0xd4(%rbp), %esi
movl -0x114(%rbp), %ecx
leaq -0x110(%rbp), %rdx
callq 0x2a80
jmp 0x43b8
leaq -0x619(%rbp), %rdi
movq %rdi, -0x830(%rbp)
callq 0x23d0
movq -0x830(%rbp), %rdx
leaq 0x2cfb(%rip), %rsi      # 0x70d4
leaq -0x618(%rbp), %rdi
callq 0x2bc0
jmp 0x43e7
movzwl -0x118(%rbp), %esi
movzbl -0x5a2(%rbp), %edx
andl $0x1, %edx
leaq -0x618(%rbp), %rdi
callq 0x32a0
jmp 0x4406
leaq -0x618(%rbp), %rdi
callq 0x2140
leaq -0x619(%rbp), %rdi
callq 0x2270
leaq -0x148(%rbp), %rdi
callq 0x2bb0
jmp 0x442c
jmp 0x442e
movb -0x5a4(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x443f
jmp 0x490c
movw -0x116(%rbp), %ax
movw %ax, -0x83e(%rbp)
movw -0x118(%rbp), %ax
movw %ax, -0x83c(%rbp)
movw -0x11a(%rbp), %ax
movw %ax, -0x83a(%rbp)
leaq -0x669(%rbp), %rdi
movq %rdi, -0x838(%rbp)
callq 0x23d0
movq -0x838(%rbp), %rdx
leaq 0x2c4e(%rip), %rsi      # 0x70d8
leaq -0x668(%rbp), %rdi
callq 0x2bc0
jmp 0x4498
movw -0x83a(%rbp), %ax
movw -0x83c(%rbp), %cx
movw -0x83e(%rbp), %dx
movzwl %dx, %esi
movzwl %cx, %edx
movzwl %ax, %ecx
leaq -0x648(%rbp), %rdi
leaq -0x668(%rbp), %r8
callq 0x25b0
jmp 0x44cb
leaq -0x148(%rbp), %rdi
movq %rdi, -0x848(%rbp)
leaq -0x648(%rbp), %rsi
movq %rsi, -0x850(%rbp)
callq 0x4a50
movq -0x850(%rbp), %rdi
callq 0x4a90
leaq -0x668(%rbp), %rdi
callq 0x2140
leaq -0x669(%rbp), %rdi
callq 0x2270
movq -0x848(%rbp), %rdi
movl -0xd4(%rbp), %esi
movl -0x114(%rbp), %ecx
leaq -0x110(%rbp), %rdx
callq 0x2a80
jmp 0x4531
leaq -0x691(%rbp), %rdi
movq %rdi, -0x858(%rbp)
callq 0x23d0
movq -0x858(%rbp), %rdx
leaq 0x2b82(%rip), %rsi      # 0x70d4
leaq -0x690(%rbp), %rdi
callq 0x2bc0
jmp 0x4560
movzwl -0x118(%rbp), %esi
movzbl -0x5a3(%rbp), %edx
andl $0x1, %edx
leaq -0x690(%rbp), %rdi
callq 0x32a0
jmp 0x457f
leaq -0x690(%rbp), %rdi
callq 0x2140
leaq -0x691(%rbp), %rdi
callq 0x2270
movb $0x1, -0x5a3(%rbp)
leaq -0x148(%rbp), %rdi
callq 0x2bb0
jmp 0x45ac
movl -0xd4(%rbp), %esi
movl -0x114(%rbp), %ecx
leaq -0x170(%rbp), %rdi
leaq -0x110(%rbp), %rdx
callq 0x2b00
movl %eax, -0x85c(%rbp)
jmp 0x45d3
movl -0x85c(%rbp), %eax
movl %eax, -0x698(%rbp)
cmpl $0x2, -0x698(%rbp)
jne 0x46cd
jmp 0x442e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x4617
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x5f0(%rbp), %rdi
callq 0x2140
leaq -0x5f1(%rbp), %rdi
callq 0x2270
jmp 0x4988
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x464e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x618(%rbp), %rdi
callq 0x2140
leaq -0x619(%rbp), %rdi
callq 0x2270
jmp 0x4988
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x4685
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x668(%rbp), %rdi
callq 0x2140
leaq -0x669(%rbp), %rdi
callq 0x2270
jmp 0x4988
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x46bc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x690(%rbp), %rdi
callq 0x2140
leaq -0x691(%rbp), %rdi
callq 0x2270
jmp 0x4988
movzwl -0x170(%rbp), %edi
callq 0x3250
jmp 0x46db
movzwl -0x16a(%rbp), %eax
movl %eax, -0x860(%rbp)
subl $0x1, %eax
je 0x4703
jmp 0x46ef
movl -0x860(%rbp), %eax
subl $0x4, %eax
je 0x48fc
jmp 0x4905
leaq -0x6b9(%rbp), %rdi
movq %rdi, -0x868(%rbp)
callq 0x23d0
movq -0x868(%rbp), %rdx
leaq 0x29b0(%rip), %rsi      # 0x70d4
leaq -0x6b8(%rbp), %rdi
callq 0x2bc0
jmp 0x4732
movzwl -0x118(%rbp), %esi
leaq -0x6b8(%rbp), %rdi
movl $0x1, %edx
callq 0x32a0
jmp 0x474c
leaq -0x6b8(%rbp), %rdi
callq 0x2140
leaq -0x6b9(%rbp), %rdi
callq 0x2270
movzwl -0x170(%rbp), %edi
movl $0x1, %esi
callq 0x2f10
movw %ax, -0x86a(%rbp)
jmp 0x477e
movw -0x86a(%rbp), %ax
movw %ax, -0x118(%rbp)
movw -0x116(%rbp), %ax
movw %ax, -0x87e(%rbp)
movw -0x118(%rbp), %ax
movw %ax, -0x87c(%rbp)
movw -0x11a(%rbp), %ax
movw %ax, -0x87a(%rbp)
leaq -0x709(%rbp), %rdi
movq %rdi, -0x878(%rbp)
callq 0x23d0
movq -0x878(%rbp), %rdx
leaq 0x28fa(%rip), %rsi      # 0x70d1
leaq -0x708(%rbp), %rdi
callq 0x2bc0
jmp 0x47e5
movw -0x87a(%rbp), %ax
movw -0x87c(%rbp), %cx
movw -0x87e(%rbp), %dx
movzwl %dx, %esi
movzwl %cx, %edx
movzwl %ax, %ecx
leaq -0x6e8(%rbp), %rdi
leaq -0x708(%rbp), %r8
callq 0x25b0
jmp 0x4818
leaq -0x148(%rbp), %rdi
movq %rdi, -0x888(%rbp)
leaq -0x6e8(%rbp), %rsi
movq %rsi, -0x890(%rbp)
callq 0x4a50
movq -0x890(%rbp), %rdi
callq 0x4a90
leaq -0x708(%rbp), %rdi
callq 0x2140
leaq -0x709(%rbp), %rdi
callq 0x2270
movq -0x888(%rbp), %rdi
movl -0xd4(%rbp), %esi
movl -0x114(%rbp), %ecx
leaq -0x110(%rbp), %rdx
callq 0x2a80
jmp 0x487e
leaq -0x148(%rbp), %rdi
callq 0x2bb0
jmp 0x488c
jmp 0x4907
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x48b4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x6b8(%rbp), %rdi
callq 0x2140
leaq -0x6b9(%rbp), %rdi
callq 0x2270
jmp 0x4988
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x48eb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x708(%rbp), %rdi
callq 0x2140
leaq -0x709(%rbp), %rdi
callq 0x2270
jmp 0x4988
movb $0x1, -0x5a4(%rbp)
jmp 0x4907
jmp 0x4907
jmp 0x442e
movl -0xd4(%rbp), %edi
callq 0x2400
jmp 0x4919
leaq -0x3f8(%rbp), %rdi
callq 0x2340
jmp 0x4927
movl $0x0, -0x4(%rbp)
leaq -0x460(%rbp), %rdi
callq 0x4be0
leaq -0x428(%rbp), %rdi
callq 0x4a90
leaq -0x3f8(%rbp), %rdi
callq 0x2370
leaq -0x170(%rbp), %rdi
callq 0x4a90
leaq -0x148(%rbp), %rdi
callq 0x4a90
leaq -0x68(%rbp), %rdi
callq 0x2140
leaq -0x30(%rbp), %rdi
callq 0x2140
movl -0x4(%rbp), %eax
addq $0x890, %rsp            # imm = 0x890
popq %rbp
retq
leaq -0x460(%rbp), %rdi
callq 0x4be0
leaq -0x428(%rbp), %rdi
callq 0x4a90
leaq -0x3f8(%rbp), %rdi
callq 0x2370
leaq -0x170(%rbp), %rdi
callq 0x4a90
leaq -0x148(%rbp), %rdi
callq 0x4a90
leaq -0x68(%rbp), %rdi
callq 0x2140
leaq -0x30(%rbp), %rdi
callq 0x2140
movq -0x40(%rbp), %rdi
callq 0x23c0
nop