// File: xdsopl[P]FEC/testbench.cc
// Function: void test_bch<6, 1, 5, 4, 19, unsigned char>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, BoseChaudhuriHocquenghem<6, 1, 5, GF::Types<4, 19, unsigned char>>&, unsigned char*, unsigned char*, std::vector<unsigned char, std::allocator<unsigned char>>&)
void test_bch(std::string name, BoseChaudhuriHocquenghem<NR, FCR, K, GF::Types<M, P, TYPE>> &bch, TYPE *code, TYPE *target, std::vector<uint8_t> &data)
{
	std::cout << "testing: " << name << std::endl;

	{
		bch.encode(code);
		bool error = false;
		for (int i = 0; i < bch.N; ++i)
			error |= code[i] != target[i];
		if (error)
			std::cout << "encoder error!" << std::endl;
		assert(!error);
		//print_table(code + K, "parity", bch.NP);
		error = bch.decode(code);
		if (error)
			std::cout << "decoder error!" << std::endl;
		assert(!error);
		int pos = 0, cap = 0, corrupt = 0, erasures_count = 0;
		TYPE erasures[NR];
		// need one root per erasure
		for (int i = 0; pos < bch.N && cap+1 <= NR && i < NR/2; ++i, ++corrupt, ++pos, ++cap)
			code[erasures[erasures_count++] = pos] ^= 1;
		// need two roots per error
		for (int i = 0; pos < bch.N && cap+2 <= NR && i < NR/2; ++i, ++corrupt, ++pos, cap+=2)
			code[pos] ^= 1;
		int corrected = bch.decode(code, erasures, erasures_count);
		if (corrupt != corrected)
			std::cout << "decoder error: expected " << corrupt << " but got " << corrected << std::endl;
		assert(corrupt == corrected);
		TYPE syndromes[NR];
		if (corrected >= 0 && bch.compute_syndromes(code, syndromes)) {
			std::cout << "decoder error: result of correction is not a codeword!" << std::endl;
			assert(false);
		}
		error = false;
		for (int i = 0; i < bch.N; ++i)
			error |= code[i] != target[i];
		if (error)
			std::cout << "decoder error: code doesnt match target" << std::endl;
		assert(!error);
	}
	int blocks = (8 * data.size() + K - 1) / K;
	TYPE *coded = new TYPE[bch.N * blocks];
	{
		unsigned pos = 0;
		for (unsigned byte : data) {
			for (int bit = 0; bit < 8; ++bit) {
				coded[pos++] = (byte >> bit) & 1;
				if (pos % bch.N >= K)
					pos += bch.NP;
			}
		}
	}
	{
		auto start = std::chrono::system_clock::now();
		for (int i = 0; i < blocks; ++i)
			bch.encode(coded + i * bch.N);
		auto end = std::chrono::system_clock::now();
		auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
		int mbs = (data.size() + msec.count() / 2) / msec.count();
		int bytes = (bch.N * blocks) / 8;
		float redundancy = (100.0f*(bytes-data.size())) / data.size();
		std::cout << "encoding of " << data.size() << " random bytes into " << bytes << " codeword bytes (" << std::setprecision(1) << std::fixed << redundancy << "% redundancy) in " << blocks << " blocks took " << msec.count() << " milliseconds (" << mbs << "KB/s)." << std::endl;
	}
	std::random_device rd;
	std::default_random_engine generator(rd());
	std::uniform_int_distribution<int> pos_dist(0, bch.N-1);
	auto rnd_pos = std::bind(pos_dist, generator);
	std::vector<uint8_t> recovered(data.size());
	TYPE *tmp = new TYPE[bch.N * blocks];
	TYPE *erasures = new TYPE[NR * blocks];
	for (int places = 0; places <= NR; ++places) {
		for (int erasures_count = 0; erasures_count <= places; ++erasures_count) {
			for (int i = 0; i < bch.N * blocks; ++i)
				tmp[i] = coded[i];
			int corrupt = 0;
			for (int i = 0; i < blocks; ++i) {
				for (int j = 0; j < places; ++j) {
					erasures[i*NR + j] = rnd_pos();
					for (int k = 0; k < j;) {
						if (erasures[i*NR + k++] == erasures[i*NR + j]) {
							erasures[i*NR + j] = rnd_pos();
							k = 0;
						}
					}
					tmp[i * bch.N + erasures[i*NR + j]] ^= 1;
					++corrupt;
				}
			}
			int corrected = 0, wrong = 0;
			auto start = std::chrono::system_clock::now();
			for (int i = 0; i < blocks; ++i) {
				int result = bch.decode(tmp + i * bch.N, erasures + i * NR, erasures_count);
				if (places > NR/2 && places > erasures_count && result >= 0)
					for (int j = i * bch.N; j < (i + 1) * bch.N; ++j)
						wrong += coded[j] != tmp[j];
				corrected += result;
			}
			auto end = std::chrono::system_clock::now();
			auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
			int bytes = (bch.N * blocks) / 8;
			int mbs = (bytes + msec.count() / 2) / msec.count();
			std::cout << "decoding with " << places << " errors and " << erasures_count << " known erasures per block took " << msec.count() << " milliseconds (" << mbs << "KB/s).";
			if (corrupt != corrected || wrong)
				std::cout << " expected " << corrupt << " corrected errors but got " << corrected << " and " << wrong << " wrong corrections.";
			std::cout << std::endl;
			assert((places > NR/2 && places > erasures_count) || (corrupt == corrected && !wrong));
			int left = 0;
			for (int i = 0; i < bch.N * blocks; ++i)
				left += tmp[i] > 1;
			if (left)
				std::cout << "correction left GF(2) " << left << " times!" << std::endl;
			if (corrupt == corrected && !wrong) {
				unsigned acc = 0, bit = 0, pos = 0;
				for (uint8_t &byte: recovered) {
					while (bit < 8) {
						acc |= (unsigned)tmp[pos++] << bit++;
						if (pos % bch.N >= K)
							pos += bch.NP;
					}
					bit -= 8;
					byte = 255 & acc;
					acc >>= 8;
				}
				for (int i = 0; i < blocks; ++i) {
					TYPE syndromes[NR];
					if (bch.compute_syndromes(tmp + i * bch.N, syndromes)) {
						std::cout << "decoder error: result of correction is not a codeword!" << std::endl;
						assert(false);
					}
				}
				if (data != recovered) {
					std::cout << "decoder error: data could not be recovered from corruption!" << std::endl;
					assert(places > NR/2 && places > erasures_count);
				}
			}
		}
	}
	delete[] erasures;
	delete[] tmp;
	delete[] coded;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1700, %rsp           # imm = 0x1700
movq %rdi, -0x1568(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq 0xdebdb(%rip), %rdi     # 0xe1fd8
leaq 0x164fb(%rip), %rsi     # 0x198ff
callq 0x21b0
movq -0x1568(%rbp), %rsi
movq %rax, %rdi
callq 0x2190
movq %rax, %rdi
movq 0xdeba6(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0xc2c0
movb $0x0, -0x29(%rbp)
movl $0x0, -0x30(%rbp)
cmpl $0xf, -0x30(%rbp)
jge 0x3487
movq -0x18(%rbp), %rax
movslq -0x30(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movq -0x20(%rbp), %rcx
movslq -0x30(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
cmpl %ecx, %eax
setne %al
andb $0x1, %al
movzbl %al, %ecx
movb -0x29(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
orl %ecx, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x29(%rbp)
movl -0x30(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x30(%rbp)
jmp 0x343f
testb $0x1, -0x29(%rbp)
je 0x34af
movq 0xdeb44(%rip), %rdi     # 0xe1fd8
leaq 0x1646e(%rip), %rsi     # 0x19909
callq 0x21b0
movq %rax, %rdi
movq 0xdeb1e(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movb -0x29(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x34ba
jmp 0x34bc
jmp 0x34db
leaq 0x16455(%rip), %rdi     # 0x19918
leaq 0x16455(%rip), %rsi     # 0x1991f
movl $0xbe, %edx
leaq 0x16456(%rip), %rcx     # 0x1992c
callq 0x2100
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
xorl %ecx, %ecx
callq 0xc2f0
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x29(%rbp)
testb $0x1, -0x29(%rbp)
je 0x3521
movq 0xdead2(%rip), %rdi     # 0xe1fd8
leaq 0x164df(%rip), %rsi     # 0x199ec
callq 0x21b0
movq %rax, %rdi
movq 0xdeaac(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movb -0x29(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x352c
jmp 0x352e
jmp 0x354d
leaq 0x163e3(%rip), %rdi     # 0x19918
leaq 0x163e3(%rip), %rsi     # 0x1991f
movl $0xc3, %edx
leaq 0x163e4(%rip), %rcx     # 0x1992c
callq 0x2100
movl $0x0, -0x34(%rbp)
movl $0x0, -0x38(%rbp)
movl $0x0, -0x3c(%rbp)
movl $0x0, -0x40(%rbp)
movl $0x0, -0x4c(%rbp)
xorl %eax, %eax
cmpl $0xf, -0x34(%rbp)
movb %al, -0x1569(%rbp)
jge 0x359e
movl -0x38(%rbp), %ecx
addl $0x1, %ecx
xorl %eax, %eax
cmpl $0x6, %ecx
movb %al, -0x1569(%rbp)
jg 0x359e
cmpl $0x3, -0x4c(%rbp)
setl %al
movb %al, -0x1569(%rbp)
movb -0x1569(%rbp), %al
testb $0x1, %al
jne 0x35aa
jmp 0x35f9
movq -0x18(%rbp), %rax
movl -0x34(%rbp), %ecx
movl -0x40(%rbp), %edx
movl %edx, %esi
addl $0x1, %esi
movl %esi, -0x40(%rbp)
movslq %edx, %rdx
movb %cl, -0x46(%rbp,%rdx)
movzbl %cl, %ecx
movzbl (%rax,%rcx), %edx
xorl $0x1, %edx
movb %dl, (%rax,%rcx)
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
jmp 0x3570
movl $0x0, -0x50(%rbp)
xorl %eax, %eax
cmpl $0xf, -0x34(%rbp)
movb %al, -0x156a(%rbp)
jge 0x362e
movl -0x38(%rbp), %ecx
addl $0x2, %ecx
xorl %eax, %eax
cmpl $0x6, %ecx
movb %al, -0x156a(%rbp)
jg 0x362e
cmpl $0x3, -0x50(%rbp)
setl %al
movb %al, -0x156a(%rbp)
movb -0x156a(%rbp), %al
testb $0x1, %al
jne 0x363a
jmp 0x3672
movq -0x18(%rbp), %rax
movslq -0x34(%rbp), %rcx
movzbl (%rax,%rcx), %edx
xorl $0x1, %edx
movb %dl, (%rax,%rcx)
movl -0x50(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x50(%rbp)
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
movl -0x38(%rbp), %eax
addl $0x2, %eax
movl %eax, -0x38(%rbp)
jmp 0x3600
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
leaq -0x46(%rbp), %rdx
movl -0x40(%rbp), %ecx
callq 0xc2f0
movl %eax, -0x54(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x54(%rbp), %eax
je 0x36d8
movq 0xde940(%rip), %rdi     # 0xe1fd8
leaq 0x1635c(%rip), %rsi     # 0x199fb
callq 0x21b0
movq %rax, %rdi
movl -0x3c(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
leaq 0x1648c(%rip), %rsi     # 0x19b45
callq 0x21b0
movq %rax, %rdi
movl -0x54(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
movq 0xde8f5(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movl -0x3c(%rbp), %eax
cmpl -0x54(%rbp), %eax
jne 0x36e2
jmp 0x3701
leaq 0x1632b(%rip), %rdi     # 0x19a14
leaq 0x1622f(%rip), %rsi     # 0x1991f
movl $0xcf, %edx
leaq 0x16230(%rip), %rcx     # 0x1992c
callq 0x2100
cmpl $0x0, -0x54(%rbp)
jl 0x375e
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
leaq -0x5a(%rbp), %rdx
callq 0xc330
cmpl $0x0, %eax
je 0x375e
movq 0xde8b4(%rip), %rdi     # 0xe1fd8
leaq 0x162fe(%rip), %rsi     # 0x19a29
callq 0x21b0
movq %rax, %rdi
movq 0xde88e(%rip), %rsi     # 0xe1fc8
callq 0x21e0
leaq 0x1631a(%rip), %rdi     # 0x19a60
leaq 0x161d2(%rip), %rsi     # 0x1991f
movl $0xd3, %edx
leaq 0x161d3(%rip), %rcx     # 0x1992c
callq 0x2100
movb $0x0, -0x29(%rbp)
movl $0x0, -0x60(%rbp)
cmpl $0xf, -0x60(%rbp)
jge 0x37b1
movq -0x18(%rbp), %rax
movslq -0x60(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movq -0x20(%rbp), %rcx
movslq -0x60(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
cmpl %ecx, %eax
setne %al
andb $0x1, %al
movzbl %al, %ecx
movb -0x29(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
orl %ecx, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x29(%rbp)
movl -0x60(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x60(%rbp)
jmp 0x3769
testb $0x1, -0x29(%rbp)
je 0x37d9
movq 0xde81a(%rip), %rdi     # 0xe1fd8
leaq 0x162a1(%rip), %rsi     # 0x19a66
callq 0x21b0
movq %rax, %rdi
movq 0xde7f4(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movb -0x29(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x37e4
jmp 0x37e6
jmp 0x3805
leaq 0x1612b(%rip), %rdi     # 0x19918
leaq 0x1612b(%rip), %rsi     # 0x1991f
movl $0xda, %edx
leaq 0x1612c(%rip), %rcx     # 0x1992c
callq 0x2100
movq -0x28(%rbp), %rdi
callq 0xc360
shlq $0x3, %rax
addq $0x5, %rax
subq $0x1, %rax
movl $0x5, %ecx
xorl %edx, %edx
divq %rcx
movl %eax, -0x64(%rbp)
imull $0xf, -0x64(%rbp), %eax
movslq %eax, %rdi
callq 0x2030
movq %rax, -0x70(%rbp)
movl $0x0, -0x74(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rdi
callq 0x2f50
movq %rax, -0x88(%rbp)
movq -0x80(%rbp), %rdi
callq 0x2f80
movq %rax, -0x90(%rbp)
leaq -0x88(%rbp), %rdi
leaq -0x90(%rbp), %rsi
callq 0xb750
testb $0x1, %al
jne 0x3882
jmp 0x3911
leaq -0x88(%rbp), %rdi
callq 0xb7c0
movzbl (%rax), %eax
movl %eax, -0x94(%rbp)
movl $0x0, -0x98(%rbp)
cmpl $0x8, -0x98(%rbp)
jge 0x38fe
movl -0x94(%rbp), %eax
movl -0x98(%rbp), %ecx
shrl %cl, %eax
andl $0x1, %eax
movb %al, %dl
movq -0x70(%rbp), %rax
movl -0x74(%rbp), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, -0x74(%rbp)
movl %ecx, %ecx
movb %dl, (%rax,%rcx)
movl -0x74(%rbp), %eax
movl $0xf, %ecx
xorl %edx, %edx
divl %ecx
cmpl $0x5, %edx
jb 0x38eb
movl -0x74(%rbp), %eax
addl $0xa, %eax
movl %eax, -0x74(%rbp)
jmp 0x38ed
movl -0x98(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x98(%rbp)
jmp 0x38a1
jmp 0x3900
leaq -0x88(%rbp), %rdi
callq 0xb7e0
jmp 0x3866
callq 0x2040
movq %rax, -0xa0(%rbp)
movl $0x0, -0xa4(%rbp)
movl -0xa4(%rbp), %eax
cmpl -0x64(%rbp), %eax
jge 0x395c
movq -0x10(%rbp), %rdi
movq -0x70(%rbp), %rsi
imull $0xf, -0xa4(%rbp), %eax
cltq
addq %rax, %rsi
callq 0xc2c0
movl -0xa4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa4(%rbp)
jmp 0x3927
callq 0x2040
movq %rax, -0xb0(%rbp)
leaq -0xb0(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0xc3b0
movq %rax, -0xc0(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0xc380
movq %rax, -0xb8(%rbp)
movq -0x28(%rbp), %rdi
callq 0xc360
movq %rax, -0x1590(%rbp)
leaq -0xb8(%rbp), %rdi
movq %rdi, -0x1598(%rbp)
callq 0xc400
movq -0x1598(%rbp), %rdi
movq %rax, %rcx
movq -0x1590(%rbp), %rax
movq %rcx, %rdx
shrq $0x3f, %rdx
addq %rdx, %rcx
sarq %rcx
addq %rcx, %rax
movq %rax, -0x1588(%rbp)
callq 0xc400
movq %rax, %rcx
movq -0x1588(%rbp), %rax
xorl %edx, %edx
divq %rcx
movl %eax, -0xc4(%rbp)
movl -0x64(%rbp), %ecx
movl %ecx, %eax
leal (%rax,%rax,4), %eax
movl %eax, %ecx
leal (%rcx,%rcx,2), %eax
leal 0x7(%rcx,%rcx,2), %ecx
testl %eax, %eax
cmovsl %ecx, %eax
sarl $0x3, %eax
movl %eax, -0xc8(%rbp)
movslq -0xc8(%rbp), %rax
movq %rax, -0x1580(%rbp)
movq -0x28(%rbp), %rdi
callq 0xc360
movq %rax, %rcx
movq -0x1580(%rbp), %rax
subq %rcx, %rax
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, -0x1574(%rbp)
testq %rax, %rax
movss %xmm0, -0x1570(%rbp)
js 0x3a7e
movss -0x1574(%rbp), %xmm0
movss %xmm0, -0x1570(%rbp)
movss -0x1570(%rbp), %xmm0
movss 0x15576(%rip), %xmm1    # 0x19004
mulss %xmm1, %xmm0
movss %xmm0, -0x15a4(%rbp)
movq -0x28(%rbp), %rdi
callq 0xc360
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, -0x15a0(%rbp)
testq %rax, %rax
movss %xmm0, -0x159c(%rbp)
js 0x3ae4
movss -0x15a0(%rbp), %xmm0
movss %xmm0, -0x159c(%rbp)
movss -0x15a4(%rbp), %xmm0
movss -0x159c(%rbp), %xmm1
divss %xmm1, %xmm0
movss %xmm0, -0xcc(%rbp)
movq 0xde4d1(%rip), %rdi     # 0xe1fd8
leaq 0x15f80(%rip), %rsi     # 0x19a8e
callq 0x21b0
movq %rax, -0x15c8(%rbp)
movq -0x28(%rbp), %rdi
callq 0xc360
movq -0x15c8(%rbp), %rdi
movq %rax, %rsi
callq 0x2060
movq %rax, %rdi
leaq 0x15f5f(%rip), %rsi     # 0x19a9b
callq 0x21b0
movq %rax, %rdi
movl -0xc8(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
leaq 0x15f56(%rip), %rsi     # 0x19aaf
callq 0x21b0
movq %rax, -0x15c0(%rbp)
movl $0x1, %edi
callq 0xc420
movq -0x15c0(%rbp), %rdi
movl %eax, -0xd0(%rbp)
movl -0xd0(%rbp), %esi
callq 0x2280
movq %rax, %rdi
leaq 0x88af(%rip), %rsi      # 0xc440
callq 0x2080
movq %rax, %rdi
movss -0xcc(%rbp), %xmm0
callq 0x2130
movq %rax, %rdi
leaq 0x15f11(%rip), %rsi     # 0x19ac1
callq 0x21b0
movq %rax, %rdi
movl -0x64(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
leaq 0x15f09(%rip), %rsi     # 0x19ad3
callq 0x21b0
movq -0x1598(%rbp), %rdi
movq %rax, -0x15b8(%rbp)
callq 0xc400
movq -0x15b8(%rbp), %rdi
movq %rax, %rsi
callq 0x22f0
movq %rax, %rdi
leaq 0x15ee6(%rip), %rsi     # 0x19ae1
callq 0x21b0
movq %rax, %rdi
movl -0xc4(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
leaq 0x15ed9(%rip), %rsi     # 0x19af1
callq 0x21b0
movq %rax, %rdi
movq 0xde3a1(%rip), %rsi     # 0xe1fc8
callq 0x21e0
leaq -0x1458(%rbp), %rdi
movq %rdi, -0x15b0(%rbp)
callq 0x2d20
movq -0x15b0(%rbp), %rdi
callq 0x2dc0
movl %eax, -0x15a8(%rbp)
jmp 0x3c53
movl -0x15a8(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
leaq -0x1460(%rbp), %rdi
callq 0x2de0
jmp 0x3c6b
leaq -0x1474(%rbp), %rdi
xorl %esi, %esi
movl $0xe, %edx
callq 0xc470
jmp 0x3c80
leaq -0x1488(%rbp), %rdi
leaq -0x1474(%rbp), %rsi
leaq -0x1460(%rbp), %rdx
callq 0xc4a0
jmp 0x3c9c
movq -0x28(%rbp), %rdi
callq 0xc360
movq %rax, -0x15d8(%rbp)
leaq -0x14a1(%rbp), %rdi
movq %rdi, -0x15d0(%rbp)
callq 0x2e40
movq -0x15d8(%rbp), %rsi
movq -0x15d0(%rbp), %rdx
leaq -0x14a0(%rbp), %rdi
callq 0x2e60
jmp 0x3cdb
leaq -0x14a1(%rbp), %rdi
callq 0x2ed0
movl -0x64(%rbp), %ecx
movl %ecx, %eax
leal (%rax,%rax,4), %ecx
movl %ecx, %eax
leal (%rax,%rax,2), %eax
movslq %eax, %rdi
callq 0x2030
movq %rax, -0x15e0(%rbp)
jmp 0x3d05
movq -0x15e0(%rbp), %rax
movq %rax, -0x14b0(%rbp)
movl -0x64(%rbp), %ecx
addl %ecx, %ecx
movl %ecx, %eax
leal (%rax,%rax,2), %eax
movslq %eax, %rdi
callq 0x2030
movq %rax, -0x15e8(%rbp)
jmp 0x3d2e
movq -0x15e8(%rbp), %rax
movq %rax, -0x14b8(%rbp)
movl $0x0, -0x14bc(%rbp)
cmpl $0x6, -0x14bc(%rbp)
jg 0x4801
movl $0x0, -0x14c0(%rbp)
movl -0x14c0(%rbp), %eax
cmpl -0x14bc(%rbp), %eax
jg 0x47eb
movl $0x0, -0x14c4(%rbp)
movl -0x14c4(%rbp), %eax
imull $0xf, -0x64(%rbp), %ecx
cmpl %ecx, %eax
jge 0x3e18
movq -0x70(%rbp), %rax
movslq -0x14c4(%rbp), %rcx
movb (%rax,%rcx), %dl
movq -0x14b0(%rbp), %rax
movslq -0x14c4(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x14c4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14c4(%rbp)
jmp 0x3d79
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1468(%rbp)
movl %eax, -0x146c(%rbp)
jmp 0x487f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1468(%rbp)
movl %eax, -0x146c(%rbp)
leaq -0x14a1(%rbp), %rdi
callq 0x2ed0
jmp 0x487f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1468(%rbp)
movl %eax, -0x146c(%rbp)
leaq -0x14a0(%rbp), %rdi
callq 0xaab0
jmp 0x487f
movl $0x0, -0x14c8(%rbp)
movl $0x0, -0x14cc(%rbp)
movl -0x14cc(%rbp), %eax
cmpl -0x64(%rbp), %eax
jge 0x3fa6
movl $0x0, -0x14d0(%rbp)
movl -0x14d0(%rbp), %eax
cmpl -0x14bc(%rbp), %eax
jge 0x3f90
leaq -0x1488(%rbp), %rdi
callq 0xc4e0
movl %eax, -0x15ec(%rbp)
jmp 0x3e6b
movl -0x15ec(%rbp), %eax
movb %al, %dl
movq -0x14b8(%rbp), %rax
imull $0x6, -0x14cc(%rbp), %ecx
addl -0x14d0(%rbp), %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl $0x0, -0x14d4(%rbp)
movl -0x14d4(%rbp), %eax
cmpl -0x14d0(%rbp), %eax
jge 0x3f35
movq -0x14b8(%rbp), %rax
imull $0x6, -0x14cc(%rbp), %ecx
movl -0x14d4(%rbp), %edx
movl %edx, %esi
addl $0x1, %esi
movl %esi, -0x14d4(%rbp)
addl %edx, %ecx
movslq %ecx, %rcx
movzbl (%rax,%rcx), %eax
movq -0x14b8(%rbp), %rcx
imull $0x6, -0x14cc(%rbp), %edx
addl -0x14d0(%rbp), %edx
movslq %edx, %rdx
movzbl (%rcx,%rdx), %ecx
cmpl %ecx, %eax
jne 0x3f30
leaq -0x1488(%rbp), %rdi
callq 0xc4e0
movl %eax, -0x15f0(%rbp)
jmp 0x3f04
movl -0x15f0(%rbp), %eax
movb %al, %dl
movq -0x14b8(%rbp), %rax
imull $0x6, -0x14cc(%rbp), %ecx
addl -0x14d0(%rbp), %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl $0x0, -0x14d4(%rbp)
jmp 0x3e97
movq -0x14b0(%rbp), %rax
imull $0xf, -0x14cc(%rbp), %ecx
movq -0x14b8(%rbp), %rdx
imull $0x6, -0x14cc(%rbp), %esi
addl -0x14d0(%rbp), %esi
movslq %esi, %rsi
movzbl (%rdx,%rsi), %edx
addl %edx, %ecx
movslq %ecx, %rcx
movzbl (%rax,%rcx), %edx
xorl $0x1, %edx
movb %dl, (%rax,%rcx)
movl -0x14c8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14c8(%rbp)
movl -0x14d0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14d0(%rbp)
jmp 0x3e45
jmp 0x3f92
movl -0x14cc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14cc(%rbp)
jmp 0x3e2c
movl $0x0, -0x14d8(%rbp)
movl $0x0, -0x14dc(%rbp)
callq 0x2040
movq %rax, -0x14e8(%rbp)
movl $0x0, -0x14ec(%rbp)
movl -0x14ec(%rbp), %eax
cmpl -0x64(%rbp), %eax
jge 0x40e8
movq -0x10(%rbp), %rdi
movq -0x14b0(%rbp), %rsi
movl -0x14ec(%rbp), %ecx
movl %ecx, %eax
leal (%rax,%rax,4), %edx
movl %edx, %eax
leal (%rax,%rax,2), %eax
cltq
addq %rax, %rsi
movq -0x14b8(%rbp), %rdx
addl %ecx, %ecx
movl %ecx, %eax
leal (%rax,%rax,2), %eax
cltq
addq %rax, %rdx
movl -0x14c0(%rbp), %ecx
callq 0xc2f0
movl %eax, -0x15f4(%rbp)
jmp 0x4025
movl -0x15f4(%rbp), %eax
movl %eax, -0x14f0(%rbp)
cmpl $0x3, -0x14bc(%rbp)
jle 0x40c2
movl -0x14bc(%rbp), %eax
cmpl -0x14c0(%rbp), %eax
jle 0x40c2
cmpl $0x0, -0x14f0(%rbp)
jl 0x40c2
imull $0xf, -0x14ec(%rbp), %eax
movl %eax, -0x14f4(%rbp)
movl -0x14f4(%rbp), %eax
movl -0x14ec(%rbp), %ecx
addl $0x1, %ecx
imull $0xf, %ecx, %ecx
cmpl %ecx, %eax
jge 0x40c0
movq -0x70(%rbp), %rax
movslq -0x14f4(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movq -0x14b0(%rbp), %rcx
movslq -0x14f4(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
cmpl %ecx, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
addl -0x14dc(%rbp), %eax
movl %eax, -0x14dc(%rbp)
movl -0x14f4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14f4(%rbp)
jmp 0x4062
jmp 0x40c2
movl -0x14f0(%rbp), %eax
addl -0x14d8(%rbp), %eax
movl %eax, -0x14d8(%rbp)
movl -0x14ec(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14ec(%rbp)
jmp 0x3fd0
callq 0x2040
movq %rax, -0x1500(%rbp)
leaq -0x1500(%rbp), %rdi
leaq -0x14e8(%rbp), %rsi
callq 0xc3b0
movq %rax, -0x1600(%rbp)
jmp 0x4110
movq -0x1600(%rbp), %rax
movq %rax, -0x1510(%rbp)
leaq -0x1510(%rbp), %rdi
callq 0xc380
movq %rax, -0x1608(%rbp)
jmp 0x4133
movq -0x1608(%rbp), %rax
movq %rax, -0x1508(%rbp)
movl -0x64(%rbp), %ecx
movl %ecx, %eax
leal (%rax,%rax,4), %eax
movl %eax, %ecx
leal (%rcx,%rcx,2), %eax
leal 0x7(%rcx,%rcx,2), %ecx
testl %eax, %eax
cmovsl %ecx, %eax
sarl $0x3, %eax
movl %eax, -0x1514(%rbp)
movslq -0x1514(%rbp), %rax
movq %rax, -0x1618(%rbp)
leaq -0x1508(%rbp), %rdi
callq 0xc400
movq %rax, -0x1610(%rbp)
jmp 0x4183
movq -0x1618(%rbp), %rax
movq -0x1610(%rbp), %rcx
movq %rcx, %rdx
shrq $0x3f, %rdx
addq %rdx, %rcx
sarq %rcx
addq %rcx, %rax
movq %rax, -0x1628(%rbp)
leaq -0x1508(%rbp), %rdi
callq 0xc400
movq %rax, -0x1620(%rbp)
jmp 0x41bd
movq -0x1620(%rbp), %rcx
movq -0x1628(%rbp), %rax
cqto
idivq %rcx
movl %eax, -0x1518(%rbp)
movq 0xdddfb(%rip), %rdi     # 0xe1fd8
leaq 0x15914(%rip), %rsi     # 0x19af8
callq 0x21b0
movq %rax, -0x1630(%rbp)
jmp 0x41f2
movq -0x1630(%rbp), %rdi
movl -0x14bc(%rbp), %esi
callq 0x22b0
movq %rax, -0x1638(%rbp)
jmp 0x420d
movq -0x1638(%rbp), %rdi
leaq 0x158ec(%rip), %rsi     # 0x19b07
callq 0x21b0
movq %rax, -0x1640(%rbp)
jmp 0x4229
movq -0x1640(%rbp), %rdi
movl -0x14c0(%rbp), %esi
callq 0x22b0
movq %rax, -0x1648(%rbp)
jmp 0x4244
movq -0x1648(%rbp), %rdi
leaq 0x158c2(%rip), %rsi     # 0x19b14
callq 0x21b0
movq %rax, -0x1650(%rbp)
jmp 0x4260
leaq -0x1508(%rbp), %rdi
callq 0xc400
movq %rax, -0x1658(%rbp)
jmp 0x4275
movq -0x1658(%rbp), %rsi
movq -0x1650(%rbp), %rdi
callq 0x22f0
movq %rax, -0x1660(%rbp)
jmp 0x4291
movq -0x1660(%rbp), %rdi
leaq 0x15842(%rip), %rsi     # 0x19ae1
callq 0x21b0
movq %rax, -0x1668(%rbp)
jmp 0x42ad
movq -0x1668(%rbp), %rdi
movl -0x1518(%rbp), %esi
callq 0x22b0
movq %rax, -0x1670(%rbp)
jmp 0x42c8
movq -0x1670(%rbp), %rdi
leaq 0x1581b(%rip), %rsi     # 0x19af1
callq 0x21b0
jmp 0x42dd
movl -0x14c8(%rbp), %eax
cmpl -0x14d8(%rbp), %eax
jne 0x42f8
cmpl $0x0, -0x14dc(%rbp)
je 0x43b4
movq 0xddcd9(%rip), %rdi     # 0xe1fd8
leaq 0x15703(%rip), %rsi     # 0x19a09
callq 0x21b0
movq %rax, -0x1678(%rbp)
jmp 0x4314
movq -0x1678(%rbp), %rdi
movl -0x14c8(%rbp), %esi
callq 0x22b0
movq %rax, -0x1680(%rbp)
jmp 0x432f
movq -0x1680(%rbp), %rdi
leaq 0x157f7(%rip), %rsi     # 0x19b34
callq 0x21b0
movq %rax, -0x1688(%rbp)
jmp 0x434b
movq -0x1688(%rbp), %rdi
movl -0x14d8(%rbp), %esi
callq 0x22b0
movq %rax, -0x1690(%rbp)
jmp 0x4366
movq -0x1690(%rbp), %rdi
leaq 0x1579a(%rip), %rsi     # 0x19b0e
callq 0x21b0
movq %rax, -0x1698(%rbp)
jmp 0x4382
movq -0x1698(%rbp), %rdi
movl -0x14dc(%rbp), %esi
callq 0x22b0
movq %rax, -0x16a0(%rbp)
jmp 0x439d
movq -0x16a0(%rbp), %rdi
leaq 0x157a4(%rip), %rsi     # 0x19b4f
callq 0x21b0
jmp 0x43b2
jmp 0x43b4
movq 0xddc1d(%rip), %rdi     # 0xe1fd8
movq 0xddc06(%rip), %rsi     # 0xe1fc8
callq 0x21e0
jmp 0x43c9
cmpl $0x3, -0x14bc(%rbp)
jle 0x43e8
movl -0x14bc(%rbp), %ecx
movb $0x1, %al
cmpl -0x14c0(%rbp), %ecx
movb %al, -0x16a1(%rbp)
jg 0x441c
movl -0x14c8(%rbp), %ecx
xorl %eax, %eax
cmpl -0x14d8(%rbp), %ecx
movb %al, -0x16a2(%rbp)
jne 0x4410
cmpl $0x0, -0x14dc(%rbp)
setne %al
xorb $-0x1, %al
movb %al, -0x16a2(%rbp)
movb -0x16a2(%rbp), %al
movb %al, -0x16a1(%rbp)
movb -0x16a1(%rbp), %al
testb $0x1, %al
jne 0x4428
jmp 0x442a
jmp 0x4449
leaq 0x15732(%rip), %rdi     # 0x19b63
leaq 0x154e7(%rip), %rsi     # 0x1991f
movl $0x11d, %edx            # imm = 0x11D
leaq 0x154e8(%rip), %rcx     # 0x1992c
callq 0x2100
movl $0x0, -0x151c(%rbp)
movl $0x0, -0x1520(%rbp)
movl -0x1520(%rbp), %eax
imull $0xf, -0x64(%rbp), %ecx
cmpl %ecx, %eax
jge 0x44a5
movq -0x14b0(%rbp), %rax
movslq -0x1520(%rbp), %rcx
movzbl (%rax,%rcx), %eax
cmpl $0x1, %eax
setg %al
andb $0x1, %al
movzbl %al, %eax
addl -0x151c(%rbp), %eax
movl %eax, -0x151c(%rbp)
movl -0x1520(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1520(%rbp)
jmp 0x445d
cmpl $0x0, -0x151c(%rbp)
je 0x4518
movq 0xddb23(%rip), %rdi     # 0xe1fd8
leaq 0x156f6(%rip), %rsi     # 0x19bb2
callq 0x21b0
movq %rax, -0x16b0(%rbp)
jmp 0x44ca
movq -0x16b0(%rbp), %rdi
movl -0x151c(%rbp), %esi
callq 0x22b0
movq %rax, -0x16b8(%rbp)
jmp 0x44e5
movq -0x16b8(%rbp), %rdi
leaq 0x156d6(%rip), %rsi     # 0x19bc9
callq 0x21b0
movq %rax, -0x16c0(%rbp)
jmp 0x4501
movq -0x16c0(%rbp), %rdi
movq 0xddab9(%rip), %rsi     # 0xe1fc8
callq 0x21e0
jmp 0x4516
jmp 0x4518
movl -0x14c8(%rbp), %eax
cmpl -0x14d8(%rbp), %eax
jne 0x47d5
cmpl $0x0, -0x14dc(%rbp)
jne 0x47d5
movl $0x0, -0x1524(%rbp)
movl $0x0, -0x1528(%rbp)
movl $0x0, -0x152c(%rbp)
leaq -0x14a0(%rbp), %rax
movq %rax, -0x1538(%rbp)
movq -0x1538(%rbp), %rdi
callq 0x2f50
movq %rax, -0x1540(%rbp)
movq -0x1538(%rbp), %rdi
callq 0x2f80
movq %rax, -0x1548(%rbp)
leaq -0x1540(%rbp), %rdi
leaq -0x1548(%rbp), %rsi
callq 0xb750
testb $0x1, %al
jne 0x45a5
jmp 0x4668
leaq -0x1540(%rbp), %rdi
callq 0xb7c0
movq %rax, -0x1550(%rbp)
cmpl $0x8, -0x1528(%rbp)
jae 0x4623
movq -0x14b0(%rbp), %rax
movl -0x152c(%rbp), %ecx
movl %ecx, %edx
addl $0x1, %edx
movl %edx, -0x152c(%rbp)
movl %ecx, %ecx
movzbl (%rax,%rcx), %eax
movl -0x1528(%rbp), %ecx
movl %ecx, %edx
addl $0x1, %edx
movl %edx, -0x1528(%rbp)
shll %cl, %eax
orl -0x1524(%rbp), %eax
movl %eax, -0x1524(%rbp)
movl -0x152c(%rbp), %eax
movl $0xf, %ecx
xorl %edx, %edx
divl %ecx
cmpl $0x5, %edx
jb 0x4621
movl -0x152c(%rbp), %eax
addl $0xa, %eax
movl %eax, -0x152c(%rbp)
jmp 0x45b8
movl -0x1528(%rbp), %eax
subl $0x8, %eax
movl %eax, -0x1528(%rbp)
movl -0x1524(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x1550(%rbp), %rax
movb %cl, (%rax)
movl -0x1524(%rbp), %eax
shrl $0x8, %eax
movl %eax, -0x1524(%rbp)
leaq -0x1540(%rbp), %rdi
callq 0xb7e0
jmp 0x4589
movl $0x0, -0x1554(%rbp)
movl -0x1554(%rbp), %eax
cmpl -0x64(%rbp), %eax
jge 0x4726
movq -0x10(%rbp), %rdi
movq -0x14b0(%rbp), %rsi
movl -0x1554(%rbp), %ecx
movl %ecx, %eax
leal (%rax,%rax,4), %ecx
movl %ecx, %eax
leal (%rax,%rax,2), %eax
cltq
addq %rax, %rsi
leaq -0x155a(%rbp), %rdx
callq 0xc330
movl %eax, -0x16c4(%rbp)
jmp 0x46b5
movl -0x16c4(%rbp), %eax
cmpl $0x0, %eax
je 0x4710
movq 0xdd911(%rip), %rdi     # 0xe1fd8
leaq 0x1535b(%rip), %rsi     # 0x19a29
callq 0x21b0
movq %rax, -0x16d0(%rbp)
jmp 0x46dc
movq -0x16d0(%rbp), %rdi
movq 0xdd8de(%rip), %rsi     # 0xe1fc8
callq 0x21e0
jmp 0x46f1
leaq 0x15368(%rip), %rdi     # 0x19a60
leaq 0x15220(%rip), %rsi     # 0x1991f
movl $0x133, %edx            # imm = 0x133
leaq 0x15221(%rip), %rcx     # 0x1992c
callq 0x2100
jmp 0x4712
movl -0x1554(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1554(%rbp)
jmp 0x4672
movq -0x28(%rbp), %rdi
leaq -0x14a0(%rbp), %rsi
callq 0xc510
movb %al, -0x16d1(%rbp)
jmp 0x473e
movb -0x16d1(%rbp), %al
testb $0x1, %al
jne 0x474d
jmp 0x47d3
movq 0xdd884(%rip), %rdi     # 0xe1fd8
leaq 0x15476(%rip), %rsi     # 0x19bd1
callq 0x21b0
movq %rax, -0x16e0(%rbp)
jmp 0x4769
movq -0x16e0(%rbp), %rdi
movq 0xdd851(%rip), %rsi     # 0xe1fc8
callq 0x21e0
jmp 0x477e
xorl %eax, %eax
cmpl $0x3, -0x14bc(%rbp)
movb %al, -0x16e1(%rbp)
jle 0x47a4
movl -0x14bc(%rbp), %eax
cmpl -0x14c0(%rbp), %eax
setg %al
movb %al, -0x16e1(%rbp)
movb -0x16e1(%rbp), %al
testb $0x1, %al
jne 0x47b0
jmp 0x47b2
jmp 0x47d1
leaq 0x15454(%rip), %rdi     # 0x19c0d
leaq 0x1515f(%rip), %rsi     # 0x1991f
movl $0x138, %edx            # imm = 0x138
leaq 0x15160(%rip), %rcx     # 0x1992c
callq 0x2100
jmp 0x47d3
jmp 0x47d5
jmp 0x47d7
movl -0x14c0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14c0(%rbp)
jmp 0x3d5d
jmp 0x47ed
movl -0x14bc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14bc(%rbp)
jmp 0x3d46
movq -0x14b8(%rbp), %rax
movq %rax, -0x16f0(%rbp)
cmpq $0x0, %rax
je 0x4821
movq -0x16f0(%rbp), %rdi
callq 0x2240
movq -0x14b0(%rbp), %rax
movq %rax, -0x16f8(%rbp)
cmpq $0x0, %rax
je 0x4841
movq -0x16f8(%rbp), %rdi
callq 0x2240
movq -0x70(%rbp), %rax
movq %rax, -0x1700(%rbp)
cmpq $0x0, %rax
je 0x485e
movq -0x1700(%rbp), %rdi
callq 0x2240
leaq -0x14a0(%rbp), %rdi
callq 0xaab0
leaq -0x1458(%rbp), %rdi
callq 0xab10
addq $0x1700, %rsp           # imm = 0x1700
popq %rbp
retq
leaq -0x1458(%rbp), %rdi
callq 0xab10
movq -0x1468(%rbp), %rdi
callq 0x22c0
nopw (%rax,%rax)