// File: /workspace/github_cpp_makefile_star2_O2/auton1[P]viterbi/viterbi.cpp
// Function: main
int main(int argc, char *argv[])
{
	time_t start,end;
	time(&start);

	// The following turns off sync between C and C++ streams.
	// Apparently it's faster to turn sync off, and as I don't use C streams, it's okay to turn off.
	ios_base::sync_with_stdio(false);

	parameters params(argc, argv);
	params.print_help();
	params.read_parameters();
	params.max_alleles = 2;	// Only use biallelic sites

	LOG.open(params.stream_out, params.stream_err, params.output_prefix);
	LOG.printLOG("\nViterbi - " + VCFTOOLS_VERSION + "\n");
	LOG.printLOG("(C) Adam Auton 2014\n\n");

	params.print_params();

	vector<vector<bool> > input_haplotypes;
	vector<unsigned int> positions;
	vector<string> alleles;
	vector<string> haplotype_names;
	
	// Read input haplotypes from VCF
	for (unsigned int ui=0; ui<params.vcf_filenames.size(); ui++)
	{
		LOG.printLOG("Reading " + params.vcf_filenames[ui] + "\n");
		variant_file *vf;
		if (params.vcf_format[ui])
			vf = new vcf_file(params, params.vcf_filenames[ui], ui);
		else
			vf = new bcf_file(params, params.vcf_filenames[ui], ui);

		vf->apply_filters(params);
		LOG.printLOG("After filtering, kept " + output_log::int2str(vf->N_kept_individuals()) + " out of " + output_log::int2str(vf->meta_data.N_indv) + " Individuals\n");

		if (ui==0)
		{
			vf->read_file(params, input_haplotypes, positions, haplotype_names, alleles);
			LOG.printLOG("After filtering, kept " + header::int2str(positions.size()) + " out of a possible " + header::int2str(vf->N_total_sites()) + " Sites\n");
		}
		else
		{
			int passed_sites = vf->add_file(params, input_haplotypes, positions, haplotype_names, alleles);
			LOG.printLOG("After filtering, kept " + header::int2str(passed_sites) + " out of a possible " + header::int2str(vf->N_total_sites()) + " Sites\n");
		}

		if (vf->N_total_sites() <= 0)
			LOG.warning("File does not contain any sites");
		else if (vf->N_kept_sites() <= 0)
			LOG.warning("No data left for analysis!");
		delete vf;
	}
	
	vector<vector<bool> > new_haplotypes;
	vector<unsigned int> new_positions;
	new_haplotypes.resize(haplotype_names.size());
	
	for (unsigned int ui=0; ui<positions.size(); ui++)
	{
		int allele_count = 0;
		for (unsigned int uj=0; uj<haplotype_names.size(); uj++)
			if (input_haplotypes[uj][ui])
				allele_count++;

		if (allele_count > 1 && allele_count < (haplotype_names.size()-1))
		{
			new_positions.push_back(positions[ui]);

			for (unsigned int uj=0; uj<haplotype_names.size(); uj++)
				new_haplotypes[uj].push_back(input_haplotypes[uj][ui]);
		}
		else
			LOG.one_off_warning("\tWarning: Skipping singletons.");
	}
	
	positions = new_positions;
	input_haplotypes = new_haplotypes;

	if (params.vcf_filenames.size() > 1)
		LOG.printLOG("Kept "+ header::int2str(positions.size()) + " sites that are contained in all files\n");
	if (positions.size() == 0)
		LOG.error("No data left for analysis!");
	
	string CHROM = *(params.chrs_to_keep.begin());

	vector<int> alt_allele_counts;
	alt_allele_counts.resize(input_haplotypes[0].size(), 0);
	for (unsigned int uj=0; uj<input_haplotypes[0].size(); uj++)
	{
		for (unsigned int uk=0; uk<input_haplotypes.size(); uk++)
			alt_allele_counts[uj] += input_haplotypes[uk][uj];
//		cout << positions[uj] << " " << alt_allele_counts[uj] << endl;
	}

	vector<double> map;
	if (params.map_filename == "")
	{
		set_genetic_map_at_positions(positions, params.recomb_rate, map);
	}
	else
	{
		read_genetic_map_at_positions(params.map_filename, positions, map);
	}

	if (params.run_viterbi == true)
	{
		cout << "#HAP\tCOPY\tCHR\tSTART\tEND\tN_SNPS\tMIN_ALLELE_COUNT\tMIN_ALLELE_POS\tEXACT_HAP_COUNT\tHAP_COUNT_1_PRCT_MISMATCH" << endl;
		for (int i=0; i<input_haplotypes.size(); i++)
		{
			string indv = haplotype_names[i].substr(0, haplotype_names[i].size()-2);
			if ((params.viterbi_indv.size() > 0) && (params.viterbi_indv.find(indv) == params.viterbi_indv.end()))
			{
				continue;
			}

			LOG.printLOG("Running Viterbi on " + haplotype_names[i] + "\n");
			vector<int> viterbi_path;
			viterbi(input_haplotypes, map, i, params, viterbi_path);

			// Process the viterbi path
			int N_exact_match;
			int N_one_prct_mismatch;
			int min_pos = positions[0];
			int max_pos = positions[0];
			int start_idx = 0;
			int current_haplotype = viterbi_path[0];
			int N_SNPs = 1;
			int min_freq = numeric_limits<int>::max();
			int min_freq_idx = 0;
			if (input_haplotypes[i][0] == 1)
				min_freq = alt_allele_counts[0];
			else
				min_freq = (int)input_haplotypes.size() - alt_allele_counts[0];

			for (int j=1; j<viterbi_path.size(); j++)
			{
				if (viterbi_path[j] != current_haplotype)
				{	// Output haplotype

					// Get haplotype frequency
					get_haplotype_count(input_haplotypes, i, start_idx, j-1, N_exact_match, N_one_prct_mismatch);

					cout << haplotype_names[i] << "\t" << haplotype_names[current_haplotype];
					cout << "\t" << CHROM;
					cout << "\t" << min_pos << "\t" << max_pos << "\t" << N_SNPs;
					cout << "\t" << min_freq << "\t" << positions[min_freq_idx];
					cout << "\t" << N_exact_match << "\t" << N_one_prct_mismatch << endl;
					// Reset
					min_pos = positions[j];	// Haplotype is left shifted
					max_pos = positions[j];
					start_idx = j;
					current_haplotype = viterbi_path[j];
					N_SNPs = 1;
					min_freq = numeric_limits<int>::max();
					min_freq_idx = j;
					if (input_haplotypes[i][j] == 1)
						min_freq = alt_allele_counts[j];
					else
						min_freq = (int)input_haplotypes.size() - alt_allele_counts[j];
				}
				else
				{
					max_pos = positions[j];
					N_SNPs++;
					if (input_haplotypes[i][j] == 1)
					{
						if (alt_allele_counts[j] < min_freq)
						{
							min_freq = alt_allele_counts[j];
							min_freq_idx = j;
						}
					}
					else
					{
						if (((int)input_haplotypes.size() - alt_allele_counts[j]) < min_freq)
						{
							min_freq = (int)input_haplotypes.size() - alt_allele_counts[j];
							min_freq_idx = j;
						}
					}

				}
			}
			// Output last haplotype
			get_haplotype_count(input_haplotypes, i, start_idx, viterbi_path.size()-1, N_exact_match, N_one_prct_mismatch);
			cout << haplotype_names[i] << "\t" << haplotype_names[viterbi_path[viterbi_path.size()-1]];
			cout << "\t" << CHROM;
			cout << "\t" << min_pos << "\t" << max_pos << "\t" << N_SNPs;
			cout << "\t" << min_freq << "\t" << positions[min_freq_idx];
			cout << "\t" << N_exact_match << "\t" << N_one_prct_mismatch << endl;
		}
	}
	else
	{
		cout << "#HAP\tCOPY\tCHR\tPOS\tPROB" << endl;
		for (int i=0; i<input_haplotypes.size(); i++)
		{
			string indv = haplotype_names[i].substr(0, haplotype_names[i].size()-2);
			if ((params.viterbi_indv.size() > 0) && (params.viterbi_indv.find(indv) == params.viterbi_indv.end()))
			{
				continue;
			}

			LOG.printLOG("Running Forward-backward on " + haplotype_names[i] + "\n");
			vector<int> post_path;
			vector<double> post_prob;
			fwdbck(input_haplotypes, map, i, params, post_path, post_prob);

			for (int j=0; j<positions.size(); j++)
			{
				cout << haplotype_names[i] << "\t" << haplotype_names[post_path[j]];
				cout << "\t" << CHROM << "\t" << positions[j] << "\t" << post_prob[j];
				cout << endl;
			}
		}
	}

	time(&end);
	double running_time = difftime(end,start);
	LOG.printLOG("Run Time = " + output_log::dbl2str_fixed(running_time, 2) + " seconds\n");
	LOG.close();
	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x8c8, %rsp            # imm = 0x8C8
movq %rsi, %rbx
movl %edi, %ebp
leaq 0x188(%rsp), %rdi
callq 0x5430
xorl %edi, %edi
callq 0x5180
leaq 0x378(%rsp), %r14
movq %r14, %rdi
movl %ebp, %esi
movq %rbx, %rdx
callq 0x26fac
movq %r14, %rdi
callq 0x2bade
leaq 0x378(%rsp), %rdi
callq 0x278fc
leaq 0x608(%rsp), %rcx
movl $0x2, -0x88(%rcx)
movzbl 0x1a5(%rcx), %esi
movzbl 0x1a4(%rcx), %edx
leaq 0x39377(%rip), %rdi     # 0x414d0
callq 0x2be4c
leaq 0x24f86(%rip), %rsi     # 0x2d0eb
leaq 0x39344(%rip), %rdx     # 0x414b0
leaq 0x70(%rsp), %rdi
callq 0x967d
leaq 0x24f8e(%rip), %rdx     # 0x2d10b
leaq 0x230(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x98b6
leaq 0x3933a(%rip), %rdi     # 0x414d0
leaq 0x230(%rsp), %rsi
callq 0x2beca
leaq 0x230(%rsp), %rdi
callq 0x5908
leaq 0x70(%rsp), %rdi
callq 0x5908
leaq 0x24f36(%rip), %rsi     # 0x2d0f7
leaq 0x210(%rsp), %rdi
leaq 0x70(%rsp), %rdx
callq 0x5160
leaq 0x392f6(%rip), %rdi     # 0x414d0
leaq 0x210(%rsp), %rsi
callq 0x2beca
leaq 0x210(%rsp), %rdi
callq 0x5908
leaq 0x378(%rsp), %rdi
callq 0x293c8
xorps %xmm0, %xmm0
leaq 0x10(%rsp), %rax
movaps %xmm0, (%rax)
andq $0x0, 0x10(%rax)
leaq 0x30(%rsp), %rax
andq $0x0, 0x10(%rax)
leaq 0x190(%rsp), %rcx
andq $0x0, 0x10(%rcx)
movaps %xmm0, (%rax)
movaps %xmm0, (%rcx)
leaq 0x90(%rsp), %rax
movaps %xmm0, (%rax)
andq $0x0, 0x10(%rax)
xorl %ebx, %ebx
leaq 0x358(%rsp), %r15
leaq 0x160(%rsp), %rbp
movl %ebx, %ebx
movq 0x7d0(%rsp), %rdx
movq 0x7d8(%rsp), %rax
subq %rdx, %rax
sarq $0x5, %rax
cmpq %rbx, %rax
jbe 0x8688
movq %rbx, %r13
shlq $0x5, %r13
addq %r13, %rdx
leaq 0x70(%rsp), %r14
movq %r14, %rdi
leaq 0x24e82(%rip), %rsi     # 0x2d10d
callq 0x967d
movq %r15, %r12
movq %r15, %rdi
movq %r14, %rsi
leaq 0x24e6b(%rip), %rdx     # 0x2d10b
callq 0x98b6
leaq 0x39224(%rip), %rdi     # 0x414d0
movq %r12, %rsi
callq 0x2beca
movq %r12, %rdi
callq 0x5908
leaq 0x70(%rsp), %rdi
callq 0x5908
leaq 0x7e8(%rsp), %rdi
movq %rbx, %rsi
callq 0x9cc0
testq %rdx, (%rax)
je 0x8307
movl $0x470, %edi            # imm = 0x470
callq 0x54a0
movq %rax, %r12
addq 0x7d0(%rsp), %r13
movq %rax, %rdi
leaq 0x378(%rsp), %rsi
movq %r13, %rdx
movl %ebx, %ecx
callq 0xde60
jmp 0x8331
movl $0x468, %edi            # imm = 0x468
callq 0x54a0
movq %rax, %r12
addq 0x7d0(%rsp), %r13
movq %rax, %rdi
leaq 0x378(%rsp), %rsi
movq %r13, %rdx
movl %ebx, %ecx
callq 0xc15c
movq %r12, %rdi
leaq 0x378(%rsp), %rsi
callq 0x26534
movq %r12, %rdi
callq 0xe91e
leaq 0xd0(%rsp), %r13
movq %r13, %rdi
movl %eax, %esi
callq 0x2c1fc
leaq 0x50(%rsp), %r14
movq %r14, %rdi
leaq 0x24dac(%rip), %rsi     # 0x2d116
movq %r13, %rdx
callq 0x98d5
leaq 0xa8(%rsp), %rdi
movq %r14, %rsi
leaq 0x24da9(%rip), %rdx     # 0x2d12d
callq 0x98b6
movl 0x2a8(%r12), %esi
movq %rbp, %r14
movq %rbp, %rdi
callq 0x2c1fc
leaq 0x70(%rsp), %r13
movq %r13, %rdi
leaq 0xa8(%rsp), %rsi
movq %r14, %rdx
callq 0x9be3
leaq 0x338(%rsp), %r14
movq %r14, %rdi
movq %r13, %rsi
leaq 0x24d6d(%rip), %rdx     # 0x2d136
callq 0x98b6
leaq 0x390fb(%rip), %rdi     # 0x414d0
movq %r14, %rsi
callq 0x2beca
movq %r14, %rdi
callq 0x5908
leaq 0x70(%rsp), %rdi
callq 0x5908
movq %rbp, %rdi
callq 0x5908
leaq 0xa8(%rsp), %rdi
callq 0x5908
leaq 0x50(%rsp), %rdi
callq 0x5908
leaq 0xd0(%rsp), %rdi
callq 0x5908
testq %rbx, %rbx
je 0x84ef
movq %r12, %rdi
leaq 0x378(%rsp), %rsi
leaq 0x10(%rsp), %rdx
leaq 0x30(%rsp), %rcx
leaq 0x90(%rsp), %r8
leaq 0x190(%rsp), %r9
callq 0xf464
leaq 0xd0(%rsp), %r13
movq %r13, %rdi
movl %eax, %esi
pushq $-0x1
popq %rdx
callq 0x12c9c
leaq 0x50(%rsp), %r14
movq %r14, %rdi
leaq 0x24ca4(%rip), %rsi     # 0x2d116
movq %r13, %rdx
callq 0x98d5
leaq 0xa8(%rsp), %rdi
movq %r14, %rsi
leaq 0x24cb8(%rip), %rdx     # 0x2d144
callq 0x98b6
movq %r12, %rdi
callq 0xe97e
movq %rbp, %r14
movq %rbp, %rdi
movl %eax, %esi
pushq $-0x1
popq %rdx
callq 0x12c9c
leaq 0x70(%rsp), %r13
movq %r13, %rdi
leaq 0xa8(%rsp), %rsi
movq %r14, %rdx
callq 0x9be3
leaq 0x2f8(%rsp), %r14
movq %r14, %rdi
movq %r13, %rsi
leaq 0x24c82(%rip), %rdx     # 0x2d158
callq 0x98b6
leaq 0x38fee(%rip), %rdi     # 0x414d0
movq %r14, %rsi
callq 0x2beca
jmp 0x85c1
movq %r12, %rdi
leaq 0x378(%rsp), %rsi
leaq 0x10(%rsp), %rdx
leaq 0x30(%rsp), %rcx
leaq 0x90(%rsp), %r8
leaq 0x190(%rsp), %r9
callq 0xeeb6
movq 0x38(%rsp), %rsi
subq 0x30(%rsp), %rsi
shrq $0x2, %rsi
leaq 0xd0(%rsp), %r13
movq %r13, %rdi
pushq $-0x1
popq %rdx
callq 0x12c9c
leaq 0x50(%rsp), %r14
movq %r14, %rdi
leaq 0x24bcd(%rip), %rsi     # 0x2d116
movq %r13, %rdx
callq 0x98d5
leaq 0xa8(%rsp), %rdi
movq %r14, %rsi
leaq 0x24be1(%rip), %rdx     # 0x2d144
callq 0x98b6
movq %r12, %rdi
callq 0xe97e
movq %rbp, %r14
movq %rbp, %rdi
movl %eax, %esi
pushq $-0x1
popq %rdx
callq 0x12c9c
leaq 0x70(%rsp), %r13
movq %r13, %rdi
leaq 0xa8(%rsp), %rsi
movq %r14, %rdx
callq 0x9be3
leaq 0x318(%rsp), %r14
movq %r14, %rdi
movq %r13, %rsi
leaq 0x24bab(%rip), %rdx     # 0x2d158
callq 0x98b6
leaq 0x38f17(%rip), %rdi     # 0x414d0
movq %r14, %rsi
callq 0x2beca
movq %r14, %rdi
callq 0x5908
leaq 0x70(%rsp), %rdi
callq 0x5908
movq %rbp, %rdi
callq 0x5908
leaq 0xa8(%rsp), %rdi
callq 0x5908
leaq 0x50(%rsp), %rdi
callq 0x5908
leaq 0xd0(%rsp), %rdi
callq 0x5908
movq %r12, %rdi
callq 0xe97e
testl %eax, %eax
jle 0x8644
movq %r12, %rdi
callq 0xe976
testl %eax, %eax
jg 0x8677
leaq 0x2b8(%rsp), %r14
movq %r14, %rdi
leaq 0x24b57(%rip), %rsi     # 0x2d180
leaq 0x70(%rsp), %rdx
callq 0x5160
leaq 0x38e96(%rip), %rdi     # 0x414d0
movq %r14, %rsi
callq 0x2c0bc
jmp 0x866f
leaq 0x2d8(%rsp), %r14
movq %r14, %rdi
leaq 0x24b0a(%rip), %rsi     # 0x2d160
leaq 0x70(%rsp), %rdx
callq 0x5160
leaq 0x38e69(%rip), %rdi     # 0x414d0
movq %r14, %rsi
callq 0x2c0bc
movq %r14, %rdi
callq 0x5908
movq (%r12), %rax
movq %r12, %rdi
callq *0x38(%rax)
incl %ebx
jmp 0x8250
xorps %xmm0, %xmm0
leaq 0xd0(%rsp), %rdi
movaps %xmm0, (%rdi)
andq $0x0, 0x10(%rdi)
movaps %xmm0, 0x160(%rsp)
andq $0x0, 0x170(%rsp)
movq 0x98(%rsp), %rsi
subq 0x90(%rsp), %rsi
sarq $0x5, %rsi
callq 0x9cde
xorl %ebx, %ebx
leaq 0x298(%rsp), %r12
leaq 0x38dfa(%rip), %rbp     # 0x414d0
movl %ebx, %ebx
movq 0x38(%rsp), %rax
subq 0x30(%rsp), %rax
sarq $0x2, %rax
cmpq %rbx, %rax
jbe 0x87df
xorl %r14d, %r14d
xorl %r15d, %r15d
movl %r15d, %r15d
movq 0x98(%rsp), %rax
subq 0x90(%rsp), %rax
sarq $0x5, %rax
cmpq %r15, %rax
jbe 0x8732
imulq $0x28, %r15, %rdi
addq 0x10(%rsp), %rdi
movq %rbx, %rsi
callq 0x9cc0
andq (%rax), %rdx
cmpq $0x1, %rdx
sbbl $-0x1, %r14d
incl %r15d
jmp 0x86f5
cmpl $0x2, %r14d
jb 0x87b1
decq %rax
movl %r14d, %ecx
cmpq %rcx, %rax
jbe 0x87b1
leaq (,%rbx,4), %rsi
addq 0x30(%rsp), %rsi
leaq 0x160(%rsp), %rdi
callq 0x9d14
xorl %r15d, %r15d
movl %r15d, %r15d
movq 0x98(%rsp), %rax
subq 0x90(%rsp), %rax
sarq $0x5, %rax
cmpq %r15, %rax
jbe 0x87d8
movq 0xd0(%rsp), %r14
imulq $0x28, %r15, %r13
movq 0x10(%rsp), %rdi
addq %r13, %rdi
movq %rbx, %rsi
callq 0x9cc0
addq %r13, %r14
xorl %esi, %esi
testq %rdx, (%rax)
setne %sil
movq %r14, %rdi
callq 0x9d32
incl %r15d
jmp 0x8760
movq %r12, %rdi
leaq 0x249e0(%rip), %rsi     # 0x2d19b
leaq 0x70(%rsp), %rdx
callq 0x5160
movq %rbp, %rdi
movq %r12, %rsi
callq 0x2c10c
movq %r12, %rdi
callq 0x5908
incl %ebx
jmp 0x86d6
leaq 0x30(%rsp), %rdi
leaq 0x160(%rsp), %rsi
callq 0x9d70
leaq 0x10(%rsp), %rdi
leaq 0xd0(%rsp), %rsi
callq 0x9e32
movq 0x7d8(%rsp), %rax
subq 0x7d0(%rsp), %rax
cmpq $0x21, %rax
jb 0x88a5
movq 0x38(%rsp), %rsi
subq 0x30(%rsp), %rsi
shrq $0x2, %rsi
leaq 0xa8(%rsp), %rdi
pushq $-0x1
popq %rdx
callq 0x12c9c
leaq 0x24978(%rip), %rsi     # 0x2d1ba
leaq 0x70(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x98d5
leaq 0x24965(%rip), %rdx     # 0x2d1c0
leaq 0x1f0(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x98b6
leaq 0x38c5c(%rip), %rdi     # 0x414d0
leaq 0x1f0(%rsp), %rsi
callq 0x2beca
leaq 0x1f0(%rsp), %rdi
callq 0x5908
leaq 0x70(%rsp), %rdi
callq 0x5908
leaq 0xa8(%rsp), %rdi
callq 0x5908
movq 0x38(%rsp), %rax
cmpq 0x30(%rsp), %rax
jne 0x88ee
leaq 0x248c8(%rip), %rsi     # 0x2d180
leaq 0x1d0(%rsp), %rdi
leaq 0x70(%rsp), %rdx
callq 0x5160
leaq 0x38bff(%rip), %rdi     # 0x414d0
leaq 0x1d0(%rsp), %rsi
pushq $0x1
popq %rdx
callq 0x2bf18
leaq 0x1d0(%rsp), %rdi
callq 0x5908
movq 0x3e8(%rsp), %rsi
addq $0x20, %rsi
leaq 0x70(%rsp), %rdi
callq 0x5630
leaq 0x110(%rsp), %rdi
andq $0x0, 0x10(%rdi)
xorps %xmm0, %xmm0
movaps %xmm0, (%rdi)
movq 0x10(%rsp), %rax
movq 0x10(%rax), %rcx
movl 0x18(%rax), %edx
subq (%rax), %rcx
leaq (%rdx,%rcx,8), %rsi
leaq 0xa8(%rsp), %rdx
andl $0x0, (%rdx)
callq 0x98fa
xorl %ebx, %ebx
movq 0x10(%rsp), %rdi
pushq $0x28
popq %r13
movl %ebx, %ebx
movq 0x10(%rdi), %rax
movl 0x18(%rdi), %ecx
subq (%rdi), %rax
leaq (%rcx,%rax,8), %rax
cmpq %rbx, %rax
jbe 0x89a2
xorl %r14d, %r14d
movl %r14d, %r14d
movq 0x18(%rsp), %rax
subq %rdi, %rax
cqto
idivq %r13
cmpq %r14, %rax
jbe 0x899e
imulq $0x28, %r14, %rax
addq %rax, %rdi
movq %rbx, %rsi
callq 0x9cc0
andq (%rax), %rdx
movq 0x110(%rsp), %rax
cmpq $0x1, %rdx
sbbl $-0x1, (%rax,%rbx,4)
incl %r14d
movq 0x10(%rsp), %rdi
jmp 0x895d
incl %ebx
jmp 0x8945
xorps %xmm0, %xmm0
movaps %xmm0, 0x140(%rsp)
andq $0x0, 0x150(%rsp)
leaq 0x870(%rsp), %rbx
leaq 0x26472(%rip), %rsi     # 0x2ee37
movq %rbx, %rdi
callq 0x96f3
testb %al, %al
je 0x89ee
movsd 0x890(%rsp), %xmm0
leaq 0x30(%rsp), %rdi
leaq 0x140(%rsp), %rsi
callq 0x61fc
jmp 0x8a03
leaq 0x30(%rsp), %rsi
leaq 0x140(%rsp), %rdx
movq %rbx, %rdi
callq 0x6279
cmpb $0x1, 0x8a4(%rsp)
jne 0x8faf
movq 0x385b0(%rip), %rdi     # 0x40fc8
leaq 0x247c9(%rip), %rsi     # 0x2d1e8
callq 0x5480
movq %rax, %rdi
callq 0x51d0
xorl %r15d, %r15d
leaq 0xa8(%rsp), %rbx
leaq 0x50(%rsp), %r14
leaq 0x258(%rsp), %r12
movq 0x18(%rsp), %rax
subq 0x10(%rsp), %rax
cqto
idivq %r13
cmpq %r15, %rax
jbe 0x91e0
movq 0x90(%rsp), %rsi
movq %r15, %rax
shlq $0x5, %rax
movq 0x8(%rsi,%rax), %rcx
movq %rax, 0xc8(%rsp)
addq %rax, %rsi
addq $-0x2, %rcx
movq %rbx, %rdi
xorl %edx, %edx
callq 0x54c0
cmpq $0x0, 0x860(%rsp)
je 0x8ab5
leaq 0x838(%rsp), %rdi
movq %rbx, %rsi
callq 0xc0d2
leaq 0x840(%rsp), %rcx
cmpq %rcx, %rax
je 0x8f9f
movq 0x90(%rsp), %rdx
addq 0xc8(%rsp), %rdx
movq %r14, %rdi
leaq 0x24782(%rip), %rsi     # 0x2d251
callq 0x967d
movq %r12, %rdi
movq %r14, %rsi
leaq 0x2462a(%rip), %rdx     # 0x2d10b
callq 0x98b6
leaq 0x389e3(%rip), %rdi     # 0x414d0
movq %r12, %rsi
callq 0x2beca
movq %r12, %rdi
callq 0x5908
movq %r14, %rdi
callq 0x5908
xorps %xmm0, %xmm0
movaps %xmm0, 0x50(%rsp)
andq $0x0, 0x60(%rsp)
leaq 0x10(%rsp), %rdi
leaq 0x140(%rsp), %rsi
movl %r15d, %edx
leaq 0x378(%rsp), %rcx
movq %r14, %r8
callq 0x752e
movq 0x30(%rsp), %rax
movl (%rax), %ebx
movq 0x50(%rsp), %rax
movl (%rax), %r14d
imulq $0x28, %r15, %rax
movq 0x10(%rsp), %rdi
movq %rax, 0x138(%rsp)
addq %rax, %rdi
xorl %esi, %esi
callq 0x9cc0
testq %rdx, (%rax)
movq %r15, 0x130(%rsp)
je 0x8b76
movq 0x110(%rsp), %rax
movl (%rax), %eax
jmp 0x8b8f
movq 0x18(%rsp), %rax
subq 0x10(%rsp), %rax
cqto
idivq %r13
movq 0x110(%rsp), %rcx
subl (%rcx), %eax
movq %rax, (%rsp)
xorl %r13d, %r13d
movl %ebx, 0x48(%rsp)
xorl %edx, %edx
pushq $0x1
popq %rax
movl %eax, 0xc(%rsp)
xorl %r15d, %r15d
movq %r13, %rbp
incq %r13
movq 0x50(%rsp), %rax
movq 0x58(%rsp), %rcx
subq %rax, %rcx
sarq $0x2, %rcx
movslq %r15d, %r12
cmpq %r13, %rcx
jbe 0x8e1b
cmpl %r14d, 0x4(%rax,%rbp,4)
jne 0x8c22
movl %edx, %r12d
movq 0x30(%rsp), %rax
movl 0x4(%rax,%rbp,4), %ebx
movq 0x10(%rsp), %rdi
addq 0x138(%rsp), %rdi
movq %r13, %rsi
callq 0x9cc0
incl 0xc(%rsp)
testq %rdx, (%rax)
je 0x8dae
movq 0x110(%rsp), %rax
movl 0x4(%rax,%rbp,4), %eax
incl %ebp
movq (%rsp), %rcx
cmpl %ecx, %eax
cmovll %eax, %ecx
movq %rcx, (%rsp)
cmovll %ebp, %r15d
jmp 0x8ddf
leaq 0x10(%rsp), %rdi
movq 0x130(%rsp), %rsi
movl %ebp, %ecx
leaq 0xf0(%rsp), %r8
leaq 0x4c(%rsp), %r9
callq 0x7faa
movq 0x3837e(%rip), %r15     # 0x40fc8
movq 0x90(%rsp), %rsi
addq 0xc8(%rsp), %rsi
movq %r15, %rdi
callq 0x5400
movq %rax, %rdi
leaq 0x261ca(%rip), %rsi     # 0x2ee36
callq 0x5480
movslq %r14d, %rsi
shlq $0x5, %rsi
addq 0x90(%rsp), %rsi
movq %rax, %rdi
callq 0x5400
movq %r15, %rdi
leaq 0x261a4(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
leaq 0x70(%rsp), %rsi
callq 0x5400
movq %r15, %rdi
leaq 0x26188(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
movl 0x48(%rsp), %esi
callq 0x57e0
movq %rax, %rdi
leaq 0x2616d(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
movl %ebx, %esi
callq 0x57e0
movq %rax, %rdi
leaq 0x26154(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
movl 0xc(%rsp), %esi
callq 0x57e0
movq %r15, %rdi
leaq 0x26139(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
movq (%rsp), %rsi
callq 0x57e0
movq %rax, %rdi
leaq 0x2611e(%rip), %rsi     # 0x2ee36
callq 0x5480
movq 0x30(%rsp), %rcx
movl (%rcx,%r12,4), %esi
movq %rax, %rdi
callq 0x52d0
movq %r15, %rdi
leaq 0x260fe(%rip), %rsi     # 0x2ee36
callq 0x5480
movl 0xf0(%rsp), %esi
movq %rax, %rdi
callq 0x57e0
movq %rax, %rdi
leaq 0x260e0(%rip), %rsi     # 0x2ee36
callq 0x5480
movl 0x4c(%rsp), %esi
movq %rax, %rdi
callq 0x57e0
movq %rax, %rdi
callq 0x51d0
movq 0x30(%rsp), %rax
movl 0x4(%rax,%rbp,4), %ebx
movq 0x50(%rsp), %rax
movl 0x4(%rax,%rbp,4), %r14d
movq 0x10(%rsp), %rdi
addq 0x138(%rsp), %rdi
movq %r13, %rsi
callq 0x9cc0
testq %rdx, (%rax)
movl %ebx, 0x48(%rsp)
je 0x8de7
movq 0x110(%rsp), %rax
movl 0x4(%rax,%rbp,4), %eax
jmp 0x8e05
movq 0x18(%rsp), %rax
subq 0x10(%rsp), %rax
cqto
pushq $0x28
popq %rcx
idivq %rcx
movq 0x110(%rsp), %rcx
subl 0x4(%rcx,%rbp,4), %eax
incl %ebp
movq (%rsp), %rcx
cmpl %ecx, %eax
cmovgel %ecx, %eax
cmovll %ebp, %r15d
movq %rax, (%rsp)
movl %r12d, %edx
jmp 0x8ba6
movq 0x18(%rsp), %rax
subq 0x10(%rsp), %rax
cqto
pushq $0x28
popq %rcx
idivq %rcx
movq 0x110(%rsp), %rcx
subl 0x4(%rcx,%rbp,4), %eax
movq %rax, (%rsp)
movl %r13d, %edx
pushq $0x1
popq %rax
movl %eax, 0xc(%rsp)
movl %r13d, %r15d
jmp 0x8ba6
decl %ecx
leaq 0x10(%rsp), %rdi
movq 0x130(%rsp), %r15
movl %r15d, %esi
leaq 0xf0(%rsp), %r8
leaq 0x4c(%rsp), %r9
callq 0x7faa
movq 0xc8(%rsp), %rsi
addq 0x90(%rsp), %rsi
movq 0x38172(%rip), %rdi     # 0x40fc8
callq 0x5400
movq %rax, %rdi
leaq 0x25fd1(%rip), %rsi     # 0x2ee36
callq 0x5480
movq 0x58(%rsp), %rcx
movslq -0x4(%rcx), %rsi
shlq $0x5, %rsi
addq 0x90(%rsp), %rsi
movq %rax, %rdi
callq 0x5400
movq 0x3813a(%rip), %rdi     # 0x40fc8
leaq 0x25fa1(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
leaq 0x70(%rsp), %rsi
callq 0x5400
movq 0x3811a(%rip), %rdi     # 0x40fc8
leaq 0x25f81(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
movl 0x48(%rsp), %esi
callq 0x57e0
movq %rax, %rdi
leaq 0x25f66(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
movl %ebx, %esi
callq 0x57e0
movq %rax, %rdi
leaq 0x25f4d(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
movl 0xc(%rsp), %esi
callq 0x57e0
movq 0x380c7(%rip), %rdi     # 0x40fc8
leaq 0x25f2e(%rip), %rsi     # 0x2ee36
callq 0x5480
movq %rax, %rdi
movq (%rsp), %rsi
callq 0x57e0
movq %rax, %rdi
leaq 0x25f13(%rip), %rsi     # 0x2ee36
callq 0x5480
movq 0x30(%rsp), %rcx
movl (%rcx,%r12,4), %esi
movq %rax, %rdi
callq 0x52d0
movq 0x38088(%rip), %rdi     # 0x40fc8
leaq 0x25eef(%rip), %rsi     # 0x2ee36
callq 0x5480
movl 0xf0(%rsp), %esi
movq %rax, %rdi
callq 0x57e0
movq %rax, %rdi
leaq 0x25ed1(%rip), %rsi     # 0x2ee36
callq 0x5480
movl 0x4c(%rsp), %esi
movq %rax, %rdi
callq 0x57e0
movq %rax, %rdi
callq 0x51d0
leaq 0x50(%rsp), %r14
movq %r14, %rdi
callq 0xa18e
pushq $0x28
popq %r13
leaq 0xa8(%rsp), %rbx
leaq 0x258(%rsp), %r12
movq %rbx, %rdi
callq 0x5908
incq %r15
jmp 0x8a44
movq 0x38012(%rip), %rdi     # 0x40fc8
leaq 0x242a8(%rip), %rsi     # 0x2d265
callq 0x5480
movq %rax, %rdi
callq 0x51d0
xorl %r14d, %r14d
movq 0x37ff4(%rip), %rbp     # 0x40fc8
leaq 0x25e5b(%rip), %r12     # 0x2ee36
leaq 0x70(%rsp), %rbx
movq 0x18(%rsp), %rax
subq 0x10(%rsp), %rax
cqto
idivq %r13
cmpq %r14, %rax
jbe 0x91e0
movq 0x90(%rsp), %rsi
movq %r14, (%rsp)
shlq $0x5, %r14
movq 0x8(%rsi,%r14), %rcx
addq %r14, %rsi
addq $-0x2, %rcx
leaq 0xa8(%rsp), %rdi
xorl %edx, %edx
callq 0x54c0
cmpq $0x0, 0x860(%rsp)
je 0x9054
leaq 0x838(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0xc0d2
leaq 0x840(%rsp), %rcx
cmpq %rcx, %rax
je 0x91c7
movq 0x90(%rsp), %rdx
addq %r14, %rdx
leaq 0x50(%rsp), %r13
movq %r13, %rdi
leaq 0x2420e(%rip), %rsi     # 0x2d27c
callq 0x967d
leaq 0x278(%rsp), %r15
movq %r15, %rdi
movq %r13, %rsi
leaq 0x24083(%rip), %rdx     # 0x2d10b
callq 0x98b6
leaq 0x3843c(%rip), %rdi     # 0x414d0
movq %r15, %rsi
callq 0x2beca
movq %r15, %rdi
callq 0x5908
movq %r13, %rdi
callq 0x5908
xorps %xmm0, %xmm0
movaps %xmm0, 0x50(%rsp)
andq $0x0, 0x60(%rsp)
movaps %xmm0, 0xf0(%rsp)
andq $0x0, 0x100(%rsp)
leaq 0x10(%rsp), %rdi
leaq 0x140(%rsp), %rsi
movq (%rsp), %rdx
leaq 0x378(%rsp), %rcx
movq %r13, %r8
leaq 0xf0(%rsp), %r9
callq 0x67b9
xorl %r13d, %r13d
movq 0x38(%rsp), %rax
subq 0x30(%rsp), %rax
sarq $0x2, %rax
cmpq %r13, %rax
jbe 0x91ac
movq 0x90(%rsp), %rsi
addq %r14, %rsi
movq %rbp, %rdi
callq 0x5400
movq %rax, %rdi
movq %r12, %rsi
callq 0x5480
movq 0x50(%rsp), %rcx
movslq (%rcx,%r13,4), %rsi
shlq $0x5, %rsi
addq 0x90(%rsp), %rsi
movq %rax, %rdi
callq 0x5400
movq %rbp, %rdi
movq %r12, %rsi
callq 0x5480
movq %rax, %rdi
movq %rbx, %rsi
callq 0x5400
movq %rax, %rdi
movq %r12, %rsi
callq 0x5480
movq 0x30(%rsp), %rcx
movl (%rcx,%r13,4), %esi
movq %rax, %rdi
callq 0x52d0
movq %rax, %rdi
movq %r12, %rsi
callq 0x5480
movq 0xf0(%rsp), %rcx
movsd (%rcx,%r13,8), %xmm0
movq %rax, %rdi
callq 0x5720
movq %rbp, %rdi
callq 0x51d0
incq %r13
jmp 0x90f7
leaq 0xf0(%rsp), %rdi
callq 0xa19c
leaq 0x50(%rsp), %rdi
callq 0xa18e
pushq $0x28
popq %r13
leaq 0xa8(%rsp), %rdi
callq 0x5908
movq (%rsp), %r14
incq %r14
jmp 0x8fe0
leaq 0x250(%rsp), %rbx
movq %rbx, %rdi
callq 0x5430
movq (%rbx), %rdi
movq 0x188(%rsp), %rsi
callq 0x51e0
leaq 0x50(%rsp), %rdi
pushq $0x2
popq %rsi
callq 0x2c348
leaq 0x24085(%rip), %rsi     # 0x2d299
leaq 0xa8(%rsp), %rdi
leaq 0x50(%rsp), %rdx
callq 0x98d5
leaq 0x23ea3(%rip), %rdx     # 0x2d0d0
leaq 0x1b0(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0x98b6
leaq 0x38287(%rip), %rdi     # 0x414d0
leaq 0x1b0(%rsp), %rsi
callq 0x2beca
leaq 0x1b0(%rsp), %rdi
callq 0x5908
leaq 0xa8(%rsp), %rdi
callq 0x5908
leaq 0x50(%rsp), %rdi
callq 0x5908
leaq 0x3824f(%rip), %rdi     # 0x414d0
callq 0x2bec0
leaq 0x140(%rsp), %rdi
callq 0xa19c
leaq 0x110(%rsp), %rdi
callq 0xa18e
leaq 0x70(%rsp), %rdi
callq 0x5908
leaq 0x160(%rsp), %rdi
callq 0xa14c
leaq 0xd0(%rsp), %rdi
callq 0x9efa
leaq 0x90(%rsp), %rdi
callq 0x9f1c
leaq 0x190(%rsp), %rdi
callq 0x9f1c
leaq 0x30(%rsp), %rdi
callq 0xa14c
leaq 0x10(%rsp), %rdi
callq 0x9efa
leaq 0x378(%rsp), %rdi
callq 0x9f3e
xorl %eax, %eax
addq $0x8c8, %rsp            # imm = 0x8C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
leaq 0x1d0(%rsp), %rdi
jmp 0x95df
jmp 0x958f
movq %rax, %rbx
leaq 0x1f0(%rsp), %rdi
callq 0x5908
jmp 0x933d
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x5908
jmp 0x934c
movq %rax, %rbx
leaq 0xa8(%rsp), %rdi
jmp 0x95df
jmp 0x958f
jmp 0x949a
movq %rax, %rbx
leaq 0x1b0(%rsp), %rdi
callq 0x5908
jmp 0x9378
movq %rax, %rbx
leaq 0xa8(%rsp), %rdi
callq 0x5908
jmp 0x938a
movq %rax, %rbx
leaq 0x50(%rsp), %rdi
jmp 0x95bb
jmp 0x949a
jmp 0x9588
jmp 0x958f
movq %rax, %rbx
leaq 0x210(%rsp), %rdi
jmp 0x93cc
jmp 0x93e2
movq %rax, %rbx
leaq 0x230(%rsp), %rdi
callq 0x5908
jmp 0x93c7
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x5908
jmp 0x962c
jmp 0x93e2
jmp 0x949a
jmp 0x958f
movq %rax, %rbx
jmp 0x962c
movq %rax, %rbx
leaq 0x2b8(%rsp), %rdi
jmp 0x9571
jmp 0x957d
jmp 0x9490
jmp 0x9490
jmp 0x954a
movq %rax, %rbx
leaq 0x2d8(%rsp), %rdi
jmp 0x9571
jmp 0x957d
movq %rax, %rbx
leaq 0x318(%rsp), %rdi
jmp 0x9520
jmp 0x9527
jmp 0x94f2
jmp 0x957d
jmp 0x9545
jmp 0x94db
jmp 0x947e
jmp 0x95a6
jmp 0x95a6
movq %rax, %rbx
leaq 0x258(%rsp), %rdi
jmp 0x9477
jmp 0x9490
jmp 0x9594
movq %rax, %rbx
leaq 0x278(%rsp), %rdi
callq 0x5908
jmp 0x9481
movq %rax, %rbx
leaq 0x50(%rsp), %rdi
callq 0x5908
jmp 0x95b3
movq %rax, %rbx
jmp 0x95b3
jmp 0x949a
movq %rax, %rbx
jmp 0x95c0
movq %rax, %rbx
leaq 0x298(%rsp), %rdi
jmp 0x95df
jmp 0x958f
jmp 0x958f
movq %rax, %rbx
leaq 0x2f8(%rsp), %rdi
jmp 0x9520
jmp 0x9527
jmp 0x94f2
jmp 0x954a
jmp 0x957d
jmp 0x9545
jmp 0x957d
movq %rax, %rbx
movq %r12, %rdi
callq 0x5440
jmp 0x95fe
jmp 0x954f
jmp 0x957d
movq %rax, %rbx
jmp 0x9534
movq %rax, %rbx
leaq 0x358(%rsp), %rdi
callq 0x5908
jmp 0x950c
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
jmp 0x9571
jmp 0x957d
movq %rax, %rbx
leaq 0x338(%rsp), %rdi
callq 0x5908
jmp 0x952a
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x5908
leaq 0x160(%rsp), %rdi
callq 0x5908
jmp 0x9552
jmp 0x954f
movq %rax, %rbx
jmp 0x9569
movq %rax, %rbx
jmp 0x955f
movq %rax, %rbx
leaq 0xa8(%rsp), %rdi
callq 0x5908
leaq 0x50(%rsp), %rdi
callq 0x5908
leaq 0xd0(%rsp), %rdi
callq 0x5908
jmp 0x95fe
jmp 0x957d
movq %rax, %rbx
jmp 0x95fe
jmp 0x95a6
jmp 0x95a6
jmp 0x95a6
movq %rax, %rbx
jmp 0x95cd
jmp 0x958f
movq %rax, %rbx
jmp 0x95e4
movq %rax, %rbx
leaq 0xf0(%rsp), %rdi
callq 0xa19c
jmp 0x95a9
movq %rax, %rbx
leaq 0x50(%rsp), %rdi
callq 0xa18e
leaq 0xa8(%rsp), %rdi
callq 0x5908
leaq 0x140(%rsp), %rdi
callq 0xa19c
leaq 0x110(%rsp), %rdi
callq 0xa18e
leaq 0x70(%rsp), %rdi
callq 0x5908
leaq 0x160(%rsp), %rdi
callq 0xa14c
leaq 0xd0(%rsp), %rdi
callq 0x9efa
leaq 0x90(%rsp), %rdi
callq 0x9f1c
leaq 0x190(%rsp), %rdi
callq 0x9f1c
leaq 0x30(%rsp), %rdi
callq 0xa14c
leaq 0x10(%rsp), %rdi
callq 0x9efa
leaq 0x378(%rsp), %rdi
callq 0x9f3e
movq %rbx, %rdi
callq 0x5800
nop