// File: auton1[P]viterbi/viterbi.cpp
// Function: viterbi(std::vector<std::vector<bool, std::allocator<bool>>, std::allocator<std::vector<bool, std::allocator<bool>>>> const&, std::vector<double, std::allocator<double>> const&, int, parameters const&, std::vector<int, std::allocator<int>>&)
void viterbi(const vector<vector<bool> > &haps, const vector<double> &map, int indv_idx, const parameters &params, vector<int> &out_path)
{
	int N_hap = haps.size()-1;	// The minus 1 accounts for the current haplotype.
	int N_pos = haps[0].size();
	vector<double> v(N_hap, 0.0);
	//vector<double> va(N_hap, -numeric_limits<double>::max());
	vector<double> vb(N_hap, -numeric_limits<double>::max());
	vector<double>::iterator it;
	vector<vector<unsigned short> > ptr(N_pos-1, vector<unsigned short>(N_hap, 0));	// Lots of memory used here

	double em_match = log(1.0 - params.p_error);
	double em_mismatch = max(log(params.p_error), -9999.9);

	vector<int> v_idx_to_hap_idx(N_hap);
	int idx_i=0;
	for (int i=0; i<haps.size(); i++)
	{
		if (i == indv_idx)
			continue;
		v_idx_to_hap_idx[idx_i] = i;

		if (haps[indv_idx][0] == haps[i][0])
			v[idx_i] = em_match;
		else
			v[idx_i] = em_mismatch;

		idx_i++;
	}

	int numthreads = min(min((int)thread::hardware_concurrency(), params.max_threads), 8);
	LOG.printLOG("Using " + output_log::int2str(numthreads) + " threads\n");
	int rows = N_hap / numthreads;
	int extra = N_hap % numthreads;
	int output_count = 0;

	struct timespec start_time;
	struct timespec end_time;
	double prev_elapsed = numeric_limits<double>::max();
	bool increase = true;

	#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
		clock_serv_t cclock;
		mach_timespec_t mts;
		host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
		clock_get_time(cclock, &mts);
		mach_port_deallocate(mach_task_self(), cclock);
		start_time.tv_sec = mts.tv_sec;
		start_time.tv_nsec = mts.tv_nsec;
	#else
		clock_gettime(CLOCK_REALTIME, &start_time);
	#endif

	for (int i=1; i < N_pos; i++)
	{
		bool allele = haps[indv_idx][i];
		double rho = 4.0*params.Ne*((map[i] - map[i-1])/100.0);

		double tmp = exp(-rho / N_hap);
		double p_rec = (1.0-tmp) / N_hap;
		double p_no_rec = tmp + p_rec;

		p_rec = log(p_rec);
		p_no_rec = log(p_no_rec);

		/*
		for (int j=0; j < N_hap; j++)	// Could parallelize this loop?
		{	// Fast Version
			transform(v.begin(), v.end(), va.begin(), bind2nd(std::plus<double>(), p_rec));
			va[j] = v[j] + p_no_rec;
			it = max_element(va.begin(), va.end());
			ptr[i-1][j] = distance(va.begin(), it);

			if (haps[ v_idx_to_hap_idx[j] ][i] == allele)
			{	// Match
				vb[j] = em_match + *it;
			}
			else
			{	// Mismatch
				vb[j] = em_mismatch + *it;
			}
		}
		*/

		int start = 0; int end = rows;
		vector<std::thread> workers;

		for (int t=0; t<numthreads; t++)
		{
			if (t == (numthreads-1))
				end += extra;	// Last thread does extra work

			workers.push_back(std::thread(inner_loop_viterbi, ref(v), p_rec, p_no_rec, ref(haps),
					em_match, em_mismatch, i, start, end,
					ref(v_idx_to_hap_idx), allele, ref(ptr), ref(vb)));
			start = end;
			end = end + rows;
		}
		for (thread& t : workers)
			t.join();

		v = vb;	// Replace old state with new state.

		if ((i % 100) == 0)
		{
			// Adaptive threading
			#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
				host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
				clock_get_time(cclock, &mts);
				mach_port_deallocate(mach_task_self(), cclock);
				end_time.tv_sec = mts.tv_sec;
				end_time.tv_nsec = mts.tv_nsec;
			#else
				clock_gettime(CLOCK_REALTIME, &end_time);
			#endif

			double elapsed = diff(start_time, end_time);

			LOG.printLOG(output_log::dbl2str(double(i)/N_pos*100, 3) + "% " + output_log::int2str(numthreads) + " threads " + output_log::dbl2str(elapsed, 3) + " seconds\n");

			if (((elapsed > prev_elapsed) && (increase == false)) || ((elapsed < prev_elapsed) && (increase == true)))
			{	// Try increasing the number of threads
				numthreads++;
				numthreads = min(numthreads, min((int)thread::hardware_concurrency(), params.max_threads));
				rows = N_hap / numthreads;
				extra = N_hap % numthreads;
				increase = true;
			}
			else if (((elapsed > prev_elapsed) && (increase == true)) || ((elapsed < prev_elapsed) && (increase == false)))
			{	// Try decreasing the number of threads
				numthreads -= 2;
				numthreads = max(numthreads, 1);
				rows = N_hap / numthreads;
				extra = N_hap % numthreads;
				increase = false;
			}
			prev_elapsed = elapsed;

			#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
				host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
				clock_get_time(cclock, &mts);
				mach_port_deallocate(mach_task_self(), cclock);
				start_time.tv_sec = mts.tv_sec;
				start_time.tv_nsec = mts.tv_nsec;
			#else
				clock_gettime(CLOCK_REALTIME, &start_time);
			#endif
		}
	}

	double max_v = -numeric_limits<double>::max();
	int max_v_idx = -1;
	for (int j=0; j<N_hap; j++)
	{
		if (v[j] > max_v)
		{
			max_v = v[j];
			max_v_idx = j;
		}
	}

	LOG.printLOG("Best Path Prob: " + output_log::dbl2str(max_v,6) + "\n");

	out_path.resize(N_pos);
	out_path[N_pos-1] = v_idx_to_hap_idx[max_v_idx];
	for (int i=N_pos-2; i >= 0; i--)
	{
		max_v_idx = ptr[i][max_v_idx];
		out_path[i] = v_idx_to_hap_idx[max_v_idx];
	}
}

// Assembly:
subq $0x528, %rsp            # imm = 0x528
movq %rdi, 0x520(%rsp)
movq %rsi, 0x518(%rsp)
movl %edx, 0x514(%rsp)
movq %rcx, 0x508(%rsp)
movq %r8, 0x500(%rsp)
movq 0x520(%rsp), %rdi
callq 0xf1b0
decl %eax
movl %eax, 0x4fc(%rsp)
movq 0x520(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0xf110
movq %rax, %rdi
callq 0xf1d0
movl %eax, 0x4f8(%rsp)
movslq 0x4fc(%rsp), %rax
movq %rax, 0x110(%rsp)
movq $0x0, 0x4d8(%rsp)
leaq 0x4d7(%rsp), %rdi
movq %rdi, 0x118(%rsp)
callq 0xedd0
movq 0x110(%rsp), %rsi
movq 0x118(%rsp), %rcx
leaq 0x4e0(%rsp), %rdi
leaq 0x4d8(%rsp), %rdx
callq 0xf260
jmp 0xa87c
leaq 0x4d7(%rsp), %rdi
callq 0xee60
movslq 0x4fc(%rsp), %rax
movq %rax, 0x100(%rsp)
callq 0xf250
movaps 0x6979b(%rip), %xmm1    # 0x74040
pxor %xmm1, %xmm0
movlpd %xmm0, 0x4a0(%rsp)
leaq 0x49f(%rsp), %rdi
movq %rdi, 0x108(%rsp)
callq 0xedd0
movq 0x100(%rsp), %rsi
movq 0x108(%rsp), %rcx
leaq 0x4a8(%rsp), %rdi
leaq 0x4a0(%rsp), %rdx
callq 0xf260
jmp 0xa8ee
leaq 0x49f(%rsp), %rdi
callq 0xee60
leaq 0x490(%rsp), %rdi
callq 0xee70
movl 0x4f8(%rsp), %eax
decl %eax
cltq
movq %rax, 0xe8(%rsp)
movslq 0x4fc(%rsp), %rax
movq %rax, 0xf0(%rsp)
movw $0x0, 0x45e(%rsp)
leaq 0x45d(%rsp), %rdi
movq %rdi, 0xf8(%rsp)
callq 0xf720
movq 0xf0(%rsp), %rsi
movq 0xf8(%rsp), %rcx
leaq 0x460(%rsp), %rdi
leaq 0x45e(%rsp), %rdx
callq 0xf730
jmp 0xa971
leaq 0x45c(%rsp), %rdi
movq %rdi, 0xe0(%rsp)
callq 0xf7b0
movq 0xe8(%rsp), %rsi
movq 0xe0(%rsp), %rcx
leaq 0x478(%rsp), %rdi
leaq 0x460(%rsp), %rdx
callq 0xf7c0
jmp 0xa9ad
leaq 0x45c(%rsp), %rdi
callq 0xf840
leaq 0x460(%rsp), %rdi
callq 0xf850
leaq 0x45d(%rsp), %rdi
callq 0xf8b0
movq 0x508(%rsp), %rax
movsd 0x520(%rax), %xmm1
movsd 0x6962c(%rip), %xmm0    # 0x74018
subsd %xmm1, %xmm0
callq 0x6410
movsd %xmm0, 0x450(%rsp)
movq 0x508(%rsp), %rax
movsd 0x520(%rax), %xmm0
callq 0x6410
movsd %xmm0, 0x440(%rsp)
movabsq $-0x3f3c780ccccccccd, %rax # imm = 0xC0C387F333333333
movq %rax, 0x438(%rsp)
leaq 0x440(%rsp), %rdi
leaq 0x438(%rsp), %rsi
callq 0xf380
movq %rax, 0xd8(%rsp)
jmp 0xaa4d
movq 0xd8(%rsp), %rax
movsd (%rax), %xmm0
movsd %xmm0, 0x448(%rsp)
movslq 0x4fc(%rsp), %rax
movq %rax, 0xc8(%rsp)
leaq 0x41f(%rsp), %rdi
movq %rdi, 0xd0(%rsp)
callq 0xf3c0
movq 0xc8(%rsp), %rsi
movq 0xd0(%rsp), %rdx
leaq 0x420(%rsp), %rdi
callq 0xf3d0
jmp 0xaaa6
leaq 0x41f(%rsp), %rdi
callq 0xf450
movl $0x0, 0x418(%rsp)
movl $0x0, 0x414(%rsp)
movslq 0x414(%rsp), %rax
movq %rax, 0xc0(%rsp)
movq 0x520(%rsp), %rdi
callq 0xf1b0
movq %rax, %rcx
movq 0xc0(%rsp), %rax
cmpq %rcx, %rax
jae 0xad4a
movl 0x414(%rsp), %eax
cmpl 0x514(%rsp), %eax
jne 0xabf4
jmp 0xad34
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
leaq 0x4d7(%rsp), %rdi
callq 0xee60
jmp 0xbba3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
leaq 0x49f(%rsp), %rdi
callq 0xee60
jmp 0xbb96
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xaba3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
leaq 0x45c(%rsp), %rdi
callq 0xf840
leaq 0x460(%rsp), %rdi
callq 0xf850
leaq 0x45d(%rsp), %rdi
callq 0xf8b0
jmp 0xbb89
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xbb7c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
leaq 0x41f(%rsp), %rdi
callq 0xf450
jmp 0xbb7c
movl 0x414(%rsp), %eax
movl %eax, 0xb8(%rsp)
movslq 0x418(%rsp), %rsi
leaq 0x420(%rsp), %rdi
callq 0xecf0
movl 0xb8(%rsp), %ecx
movl %ecx, (%rax)
movq 0x520(%rsp), %rdi
movslq 0x514(%rsp), %rsi
callq 0xf110
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0xf150
movb %al, 0xbf(%rsp)
jmp 0xac4a
movb 0xbf(%rsp), %al
movzbl %al, %eax
andl $0x1, %eax
movl %eax, 0xb0(%rsp)
movq 0x520(%rsp), %rdi
movslq 0x414(%rsp), %rsi
callq 0xf110
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0xf150
movb %al, 0xb7(%rsp)
jmp 0xac88
movl 0xb0(%rsp), %eax
movb 0xb7(%rsp), %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl %ecx, %eax
jne 0xacef
movsd 0x450(%rsp), %xmm0
movsd %xmm0, 0xa8(%rsp)
movslq 0x418(%rsp), %rsi
leaq 0x4e0(%rsp), %rdi
callq 0xe870
movsd 0xa8(%rsp), %xmm0
movsd %xmm0, (%rax)
jmp 0xad23
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xbb6f
movsd 0x448(%rsp), %xmm0
movsd %xmm0, 0xa0(%rsp)
movslq 0x418(%rsp), %rsi
leaq 0x4e0(%rsp), %rdi
callq 0xe870
movsd 0xa0(%rsp), %xmm0
movsd %xmm0, (%rax)
movl 0x418(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x418(%rsp)
movl 0x414(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x414(%rsp)
jmp 0xaac9
callq 0x67d0
movl %eax, 0x40c(%rsp)
movq 0x508(%rsp), %rsi
addq $0x528, %rsi            # imm = 0x528
leaq 0x40c(%rsp), %rdi
callq 0xf8c0
movq %rax, 0x98(%rsp)
jmp 0xad7c
movq 0x98(%rsp), %rdi
movl $0x8, 0x408(%rsp)
leaq 0x408(%rsp), %rsi
callq 0xf8c0
movq %rax, 0x90(%rsp)
jmp 0xada6
movq 0x90(%rsp), %rax
movl (%rax), %eax
movl %eax, 0x410(%rsp)
movl 0x410(%rsp), %esi
leaq 0x3a8(%rsp), %rdi
callq 0x71730
jmp 0xadcd
leaq 0x692be(%rip), %rsi     # 0x74092
leaq 0x3c8(%rsp), %rdi
leaq 0x3a8(%rsp), %rdx
callq 0xf4f0
jmp 0xadeb
leaq 0x692a7(%rip), %rdx     # 0x74099
leaq 0x3e8(%rsp), %rdi
leaq 0x3c8(%rsp), %rsi
callq 0xf4a0
jmp 0xae09
leaq 0x887f0(%rip), %rdi     # 0x93600
leaq 0x3e8(%rsp), %rsi
callq 0x71280
jmp 0xae1f
leaq 0x3e8(%rsp), %rdi
callq 0x6b50
leaq 0x3c8(%rsp), %rdi
callq 0x6b50
leaq 0x3a8(%rsp), %rdi
callq 0x6b50
movl 0x4fc(%rsp), %eax
cltd
idivl 0x410(%rsp)
movl %eax, 0x3a4(%rsp)
movl 0x4fc(%rsp), %eax
cltd
idivl 0x410(%rsp)
movl %edx, 0x3a0(%rsp)
movl $0x0, 0x39c(%rsp)
callq 0xf250
movsd %xmm0, 0x370(%rsp)
movb $0x1, 0x36f(%rsp)
xorl %edi, %edi
leaq 0x388(%rsp), %rsi
callq 0x64c0
movl $0x1, 0x368(%rsp)
movl 0x368(%rsp), %eax
cmpl 0x4f8(%rsp), %eax
jge 0xb894
movq 0x520(%rsp), %rdi
movslq 0x514(%rsp), %rsi
callq 0xf110
movq %rax, %rdi
movslq 0x368(%rsp), %rsi
callq 0xf150
movb %al, 0x8f(%rsp)
jmp 0xaeef
movb 0x8f(%rsp), %al
andb $0x1, %al
movb %al, 0x367(%rsp)
movq 0x508(%rsp), %rax
movsd 0x69119(%rip), %xmm0    # 0x74028
mulsd 0x4f0(%rax), %xmm0
movsd %xmm0, 0x80(%rsp)
movq 0x518(%rsp), %rdi
movslq 0x368(%rsp), %rsi
callq 0xeff0
movsd (%rax), %xmm0
movsd %xmm0, 0x78(%rsp)
movq 0x518(%rsp), %rdi
movl 0x368(%rsp), %eax
subl $0x1, %eax
movslq %eax, %rsi
callq 0xeff0
movsd 0x78(%rsp), %xmm1
movsd 0x80(%rsp), %xmm0
subsd (%rax), %xmm1
movsd 0x690ac(%rip), %xmm2    # 0x74020
divsd %xmm2, %xmm1
mulsd %xmm1, %xmm0
movsd %xmm0, 0x358(%rsp)
movsd 0x358(%rsp), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
cvtsi2sdl 0x4fc(%rsp), %xmm1
divsd %xmm1, %xmm0
callq 0x6a00
movsd %xmm0, 0x350(%rsp)
movsd 0x69050(%rip), %xmm0    # 0x74018
subsd 0x350(%rsp), %xmm0
cvtsi2sdl 0x4fc(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x348(%rsp)
movsd 0x350(%rsp), %xmm0
addsd 0x348(%rsp), %xmm0
movsd %xmm0, 0x340(%rsp)
movsd 0x348(%rsp), %xmm0
callq 0x6410
movsd %xmm0, 0x348(%rsp)
movsd 0x340(%rsp), %xmm0
callq 0x6410
movsd %xmm0, 0x340(%rsp)
movl $0x0, 0x33c(%rsp)
movl 0x3a4(%rsp), %eax
movl %eax, 0x338(%rsp)
leaq 0x320(%rsp), %rdi
callq 0xf900
movl $0x0, 0x31c(%rsp)
movl 0x31c(%rsp), %eax
cmpl 0x410(%rsp), %eax
jge 0xb2bf
movl 0x31c(%rsp), %eax
movl 0x410(%rsp), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jne 0xb111
movl 0x3a0(%rsp), %eax
addl 0x338(%rsp), %eax
movl %eax, 0x338(%rsp)
jmp 0xb111
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb0ff
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb0f2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
leaq 0x3e8(%rsp), %rdi
callq 0x6b50
leaq 0x3c8(%rsp), %rdi
callq 0x6b50
leaq 0x3a8(%rsp), %rdi
callq 0x6b50
jmp 0xbb6f
leaq 0x4e0(%rsp), %rdi
callq 0xf940
movq %rax, 0x308(%rsp)
movq 0x520(%rsp), %rdi
callq 0xf970
movq %rax, 0x300(%rsp)
leaq 0x420(%rsp), %rdi
callq 0xf9a0
movq %rax, 0x2f8(%rsp)
leaq 0x478(%rsp), %rdi
callq 0xf9d0
movq %rax, 0x2f0(%rsp)
leaq 0x4a8(%rsp), %rdi
callq 0xf940
movq %rax, 0x2e8(%rsp)
movq %rsp, %rax
movq %rax, 0x70(%rsp)
leaq 0x2e8(%rsp), %rcx
movq %rcx, 0x40(%rax)
leaq 0x2f0(%rsp), %rcx
movq %rcx, 0x38(%rax)
leaq 0x367(%rsp), %rcx
movq %rcx, 0x30(%rax)
leaq 0x2f8(%rsp), %rcx
movq %rcx, 0x28(%rax)
leaq 0x338(%rsp), %rcx
movq %rcx, 0x20(%rax)
leaq 0x33c(%rsp), %rcx
movq %rcx, 0x18(%rax)
leaq 0x368(%rsp), %rcx
movq %rcx, 0x10(%rax)
leaq 0x448(%rsp), %rcx
movq %rcx, 0x8(%rax)
leaq 0x450(%rsp), %rcx
movq %rcx, (%rax)
leaq -0x2ed4(%rip), %rsi     # 0x8320
leaq 0x310(%rsp), %rdi
leaq 0x308(%rsp), %rdx
leaq 0x348(%rsp), %rcx
leaq 0x340(%rsp), %r8
leaq 0x300(%rsp), %r9
callq 0xfa00
jmp 0xb223
leaq 0x320(%rsp), %rdi
leaq 0x310(%rsp), %rsi
callq 0xf910
jmp 0xb23a
leaq 0x310(%rsp), %rdi
callq 0xfc00
movl 0x338(%rsp), %eax
movl %eax, 0x33c(%rsp)
movl 0x338(%rsp), %eax
addl 0x3a4(%rsp), %eax
movl %eax, 0x338(%rsp)
movl 0x31c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x31c(%rsp)
jmp 0xb061
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb882
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
leaq 0x310(%rsp), %rdi
callq 0xfc00
jmp 0xb882
leaq 0x320(%rsp), %rax
movq %rax, 0x2e0(%rsp)
movq 0x2e0(%rsp), %rdi
callq 0xfc20
movq %rax, 0x2d8(%rsp)
movq 0x2e0(%rsp), %rdi
callq 0xfc50
movq %rax, 0x2d0(%rsp)
leaq 0x2d8(%rsp), %rdi
leaq 0x2d0(%rsp), %rsi
callq 0xfc80
testb $0x1, %al
jne 0xb314
jmp 0xb349
leaq 0x2d8(%rsp), %rdi
callq 0xfcc0
movq %rax, 0x2c8(%rsp)
movq 0x2c8(%rsp), %rdi
callq 0x6990
jmp 0xb338
jmp 0xb33a
leaq 0x2d8(%rsp), %rdi
callq 0xfcd0
jmp 0xb2f9
leaq 0x4e0(%rsp), %rdi
leaq 0x4a8(%rsp), %rsi
callq 0xfcf0
jmp 0xb360
movl 0x368(%rsp), %eax
movl $0x64, %ecx
cltd
idivl %ecx
cmpl $0x0, %edx
jne 0xb85f
xorl %edi, %edi
leaq 0x378(%rsp), %rsi
callq 0x64c0
movups 0x388(%rsp), %xmm0
movaps %xmm0, 0x2b0(%rsp)
movups 0x378(%rsp), %xmm0
movaps %xmm0, 0x2a0(%rsp)
movq 0x2b0(%rsp), %rdi
movq 0x2b8(%rsp), %rsi
movq 0x2a0(%rsp), %rdx
movq 0x2a8(%rsp), %rcx
callq 0x8760
movsd %xmm0, 0x2c0(%rsp)
cvtsi2sdl 0x368(%rsp), %xmm0
cvtsi2sdl 0x4f8(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd 0x68c2d(%rip), %xmm1    # 0x74020
mulsd %xmm1, %xmm0
leaq 0x1e0(%rsp), %rdi
movl $0x3, %esi
callq 0x71870
jmp 0xb40b
leaq 0x68c91(%rip), %rdx     # 0x740a3
leaq 0x200(%rsp), %rdi
leaq 0x1e0(%rsp), %rsi
callq 0xf4a0
jmp 0xb429
movl 0x410(%rsp), %esi
leaq 0x1c0(%rsp), %rdi
callq 0x71730
jmp 0xb43f
leaq 0x220(%rsp), %rdi
leaq 0x200(%rsp), %rsi
leaq 0x1c0(%rsp), %rdx
callq 0xffb0
jmp 0xb45e
leaq 0x68c41(%rip), %rdx     # 0x740a6
leaq 0x240(%rsp), %rdi
leaq 0x220(%rsp), %rsi
callq 0xf4a0
jmp 0xb47c
movsd 0x2c0(%rsp), %xmm0
leaq 0x1a0(%rsp), %rdi
movl $0x3, %esi
callq 0x71870
jmp 0xb499
leaq 0x260(%rsp), %rdi
leaq 0x240(%rsp), %rsi
leaq 0x1a0(%rsp), %rdx
callq 0xffb0
jmp 0xb4b8
leaq 0x68bf1(%rip), %rdx     # 0x740b0
leaq 0x280(%rsp), %rdi
leaq 0x260(%rsp), %rsi
callq 0xf4a0
jmp 0xb4d6
leaq 0x88123(%rip), %rdi     # 0x93600
leaq 0x280(%rsp), %rsi
callq 0x71280
jmp 0xb4ec
leaq 0x280(%rsp), %rdi
callq 0x6b50
leaq 0x260(%rsp), %rdi
callq 0x6b50
leaq 0x1a0(%rsp), %rdi
callq 0x6b50
leaq 0x240(%rsp), %rdi
callq 0x6b50
leaq 0x220(%rsp), %rdi
callq 0x6b50
leaq 0x1c0(%rsp), %rdi
callq 0x6b50
leaq 0x200(%rsp), %rdi
callq 0x6b50
leaq 0x1e0(%rsp), %rdi
callq 0x6b50
movsd 0x2c0(%rsp), %xmm0
ucomisd 0x370(%rsp), %xmm0
jbe 0xb579
movb 0x36f(%rsp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0xb5aa
movsd 0x2c0(%rsp), %xmm1
movsd 0x370(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0xb770
movb 0x36f(%rsp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0xb770
movl 0x410(%rsp), %eax
incl %eax
movl %eax, 0x410(%rsp)
callq 0x67d0
movl %eax, 0x19c(%rsp)
movq 0x508(%rsp), %rsi
addq $0x528, %rsi            # imm = 0x528
leaq 0x19c(%rsp), %rdi
callq 0xf8c0
movq %rax, 0x68(%rsp)
jmp 0xb5e9
movq 0x68(%rsp), %rsi
leaq 0x410(%rsp), %rdi
callq 0xf8c0
movq %rax, 0x60(%rsp)
jmp 0xb602
movq 0x60(%rsp), %rax
movl (%rax), %eax
movl %eax, 0x410(%rsp)
movl 0x4fc(%rsp), %eax
cltd
idivl 0x410(%rsp)
movl %eax, 0x3a4(%rsp)
movl 0x4fc(%rsp), %eax
cltd
idivl 0x410(%rsp)
movl %edx, 0x3a0(%rsp)
movb $0x1, 0x36f(%rsp)
jmp 0xb83e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb75e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb751
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb744
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb737
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb72a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb71d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xb710
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
leaq 0x280(%rsp), %rdi
callq 0x6b50
leaq 0x260(%rsp), %rdi
callq 0x6b50
leaq 0x1a0(%rsp), %rdi
callq 0x6b50
leaq 0x240(%rsp), %rdi
callq 0x6b50
leaq 0x220(%rsp), %rdi
callq 0x6b50
leaq 0x1c0(%rsp), %rdi
callq 0x6b50
leaq 0x200(%rsp), %rdi
callq 0x6b50
leaq 0x1e0(%rsp), %rdi
callq 0x6b50
jmp 0xb882
movsd 0x2c0(%rsp), %xmm0
ucomisd 0x370(%rsp), %xmm0
jbe 0xb795
movb 0x36f(%rsp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
je 0xb7c2
movsd 0x2c0(%rsp), %xmm1
movsd 0x370(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0xb83c
movb 0x36f(%rsp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0xb83c
movl 0x410(%rsp), %eax
addl $-0x2, %eax
movl %eax, 0x410(%rsp)
movl $0x1, 0x198(%rsp)
leaq 0x410(%rsp), %rdi
leaq 0x198(%rsp), %rsi
callq 0x100a0
movq %rax, 0x58(%rsp)
jmp 0xb7fa
movq 0x58(%rsp), %rax
movl (%rax), %eax
movl %eax, 0x410(%rsp)
movl 0x4fc(%rsp), %eax
cltd
idivl 0x410(%rsp)
movl %eax, 0x3a4(%rsp)
movl 0x4fc(%rsp), %eax
cltd
idivl 0x410(%rsp)
movl %edx, 0x3a0(%rsp)
movb $0x0, 0x36f(%rsp)
jmp 0xb83e
movsd 0x2c0(%rsp), %xmm0
movsd %xmm0, 0x370(%rsp)
xorl %edi, %edi
leaq 0x388(%rsp), %rsi
callq 0x64c0
leaq 0x320(%rsp), %rdi
callq 0x100e0
movl 0x368(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x368(%rsp)
jmp 0xaead
leaq 0x320(%rsp), %rdi
callq 0x100e0
jmp 0xbb6f
callq 0xf250
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
movsd %xmm0, 0x190(%rsp)
movl $0xffffffff, 0x18c(%rsp) # imm = 0xFFFFFFFF
movl $0x0, 0x188(%rsp)
movl 0x188(%rsp), %eax
cmpl 0x4fc(%rsp), %eax
jge 0xb948
movslq 0x188(%rsp), %rsi
leaq 0x4e0(%rsp), %rdi
callq 0xe870
movsd (%rax), %xmm0
ucomisd 0x190(%rsp), %xmm0
jbe 0xb933
movslq 0x188(%rsp), %rsi
leaq 0x4e0(%rsp), %rdi
callq 0xe870
movsd (%rax), %xmm0
movsd %xmm0, 0x190(%rsp)
movl 0x188(%rsp), %eax
movl %eax, 0x18c(%rsp)
jmp 0xb935
movl 0x188(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x188(%rsp)
jmp 0xb8cf
movsd 0x190(%rsp), %xmm0
leaq 0x128(%rsp), %rdi
movl $0x6, %esi
callq 0x71870
jmp 0xb965
leaq 0x6874e(%rip), %rsi     # 0x740ba
leaq 0x148(%rsp), %rdi
leaq 0x128(%rsp), %rdx
callq 0xf4f0
jmp 0xb983
leaq 0x68761(%rip), %rdx     # 0x740eb
leaq 0x168(%rsp), %rdi
leaq 0x148(%rsp), %rsi
callq 0xf4a0
jmp 0xb9a1
leaq 0x87c58(%rip), %rdi     # 0x93600
leaq 0x168(%rsp), %rsi
callq 0x71280
jmp 0xb9b7
leaq 0x168(%rsp), %rdi
callq 0x6b50
leaq 0x148(%rsp), %rdi
callq 0x6b50
leaq 0x128(%rsp), %rdi
callq 0x6b50
movq 0x500(%rsp), %rdi
movslq 0x4f8(%rsp), %rsi
callq 0x10140
jmp 0xb9f5
movslq 0x18c(%rsp), %rsi
leaq 0x420(%rsp), %rdi
callq 0xecf0
movl (%rax), %eax
movl %eax, 0x54(%rsp)
movq 0x500(%rsp), %rdi
movl 0x4f8(%rsp), %eax
subl $0x1, %eax
movslq %eax, %rsi
callq 0xecf0
movl 0x54(%rsp), %ecx
movl %ecx, (%rax)
movl 0x4f8(%rsp), %eax
subl $0x2, %eax
movl %eax, 0x124(%rsp)
cmpl $0x0, 0x124(%rsp)
jl 0xbb33
movslq 0x124(%rsp), %rsi
leaq 0x478(%rsp), %rdi
callq 0xf0d0
movq %rax, %rdi
movslq 0x18c(%rsp), %rsi
callq 0xf0f0
movzwl (%rax), %eax
movl %eax, 0x18c(%rsp)
movslq 0x18c(%rsp), %rsi
leaq 0x420(%rsp), %rdi
callq 0xecf0
movl (%rax), %eax
movl %eax, 0x50(%rsp)
movq 0x500(%rsp), %rdi
movslq 0x124(%rsp), %rsi
callq 0xecf0
movl 0x50(%rsp), %ecx
movl %ecx, (%rax)
movl 0x124(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0x124(%rsp)
jmp 0xba41
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xbb24
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
jmp 0xbb17
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4c8(%rsp)
movl %eax, 0x4c4(%rsp)
leaq 0x168(%rsp), %rdi
callq 0x6b50
leaq 0x148(%rsp), %rdi
callq 0x6b50
leaq 0x128(%rsp), %rdi
callq 0x6b50
jmp 0xbb6f
leaq 0x420(%rsp), %rdi
callq 0xed70
leaq 0x478(%rsp), %rdi
callq 0x101e0
leaq 0x4a8(%rsp), %rdi
callq 0xed10
leaq 0x4e0(%rsp), %rdi
callq 0xed10
addq $0x528, %rsp            # imm = 0x528
retq
leaq 0x420(%rsp), %rdi
callq 0xed70
leaq 0x478(%rsp), %rdi
callq 0x101e0
leaq 0x4a8(%rsp), %rdi
callq 0xed10
leaq 0x4e0(%rsp), %rdi
callq 0xed10
movq 0x4c8(%rsp), %rdi
callq 0x69e0