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

	{
		rs.encode(code);
		bool error = false;
		for (int i = 0; i < rs.N; ++i)
			error |= code[i] != target[i];
		if (error)
			std::cout << "encoder error!" << std::endl;
		assert(!error);
		//print_table(code + rs.K, "parity", NR);
		error = rs.decode(code);
		if (error)
			std::cout << "decoder error!" << std::endl;
		assert(!error);
		// first symbol is without corruption
		int pos = 0, par = 0, corrupt = -1, erasures_count = 0;
		TYPE erasures[NR];
		// need one parity symbol per erasure
		for (int i = 0; pos < rs.N && par+1 <= NR && i < NR/2; ++i, ++corrupt, ++pos, ++par)
			code[erasures[erasures_count++] = pos] ^= pos;
		// need two parity symbols per error
		for (int i = 0; pos < rs.N && par+2 <= NR && i < NR/2; ++i, ++corrupt, ++pos, par+=2)
			code[pos] ^= pos;
		int corrected = rs.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 && rs.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 < rs.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() + M * rs.K - 1) / (M * rs.K);
	TYPE *coded = new TYPE[rs.N * blocks];
	{
		unsigned acc = 0, bit = 0, pos = 0;
		for (unsigned byte : data) {
			acc |= byte << bit;
			bit += 8;
			while (bit >= M) {
				bit -= M;
				coded[pos++] = rs.N & acc;
				acc >>= M;
				if (pos % rs.N >= rs.K)
					pos += NR;
			}
		}
	}
	{
		auto start = std::chrono::system_clock::now();
		for (int i = 0; i < blocks; ++i)
			rs.encode(coded + i * rs.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 = (rs.N * blocks * M) / 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> bit_dist(0, M-1), pos_dist(0, rs.N-1);
	auto rnd_bit = std::bind(bit_dist, generator);
	auto rnd_pos = std::bind(pos_dist, generator);
	std::vector<uint8_t> recovered(data.size());
	TYPE *tmp = new TYPE[rs.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 < rs.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 * rs.N + erasures[i*NR + j]] ^= 1 << rnd_bit();
					++corrupt;
				}
			}
			int corrected = 0, wrong = 0;
			auto start = std::chrono::system_clock::now();
			for (int i = 0; i < blocks; ++i) {
				int result = rs.decode(tmp + i * rs.N, erasures + i * NR, erasures_count);
				if (places > NR/2 && places > erasures_count && result >= 0)
					for (int j = i * rs.N; j < (i + 1) * rs.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 = (rs.N * blocks * M) / 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));
			if (corrupt == corrected && !wrong) {
				unsigned acc = 0, bit = 0, pos = 0;
				for (uint8_t &byte: recovered) {
					while (bit < 8) {
						acc |= (unsigned)tmp[pos++] << bit;
						bit += M;
						if (pos % rs.N >= rs.K)
							pos += NR;
					}
					bit -= 8;
					byte = 255 & acc;
					acc >>= 8;
				}
				for (int i = 0; i < blocks; ++i) {
					TYPE syndromes[NR];
					if (rs.compute_syndromes(tmp + i * rs.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 $0x16e0, %rsp           # imm = 0x16E0
movq %rdi, -0x1570(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq 0xdd39b(%rip), %rdi     # 0xe1fd8
leaq 0x14cbb(%rip), %rsi     # 0x198ff
callq 0x21b0
movq -0x1570(%rbp), %rsi
movq %rax, %rdi
callq 0x2190
movq %rax, %rdi
movq 0xdd366(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0xebe0
movb $0x0, -0x29(%rbp)
movl $0x0, -0x30(%rbp)
cmpl $0xf, -0x30(%rbp)
jge 0x4cc7
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 0x4c7f
testb $0x1, -0x29(%rbp)
je 0x4cef
movq 0xdd304(%rip), %rdi     # 0xe1fd8
leaq 0x14c2e(%rip), %rsi     # 0x19909
callq 0x21b0
movq %rax, %rdi
movq 0xdd2de(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movb -0x29(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x4cfa
jmp 0x4cfc
jmp 0x4d1b
leaq 0x14c15(%rip), %rdi     # 0x19918
leaq 0x14c15(%rip), %rsi     # 0x1991f
movl $0x2b, %edx
leaq 0x155f7(%rip), %rcx     # 0x1a30d
callq 0x2100
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
xorl %ecx, %ecx
callq 0xec10
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x29(%rbp)
testb $0x1, -0x29(%rbp)
je 0x4d61
movq 0xdd292(%rip), %rdi     # 0xe1fd8
leaq 0x14c9f(%rip), %rsi     # 0x199ec
callq 0x21b0
movq %rax, %rdi
movq 0xdd26c(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movb -0x29(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x4d6c
jmp 0x4d6e
jmp 0x4d8d
leaq 0x14ba3(%rip), %rdi     # 0x19918
leaq 0x14ba3(%rip), %rsi     # 0x1991f
movl $0x30, %edx
leaq 0x15585(%rip), %rcx     # 0x1a30d
callq 0x2100
movl $0x0, -0x34(%rbp)
movl $0x0, -0x38(%rbp)
movl $0xffffffff, -0x3c(%rbp) # imm = 0xFFFFFFFF
movl $0x0, -0x40(%rbp)
movl $0x0, -0x48(%rbp)
xorl %eax, %eax
cmpl $0xf, -0x34(%rbp)
movb %al, -0x1571(%rbp)
jge 0x4dde
movl -0x38(%rbp), %ecx
addl $0x1, %ecx
xorl %eax, %eax
cmpl $0x4, %ecx
movb %al, -0x1571(%rbp)
jg 0x4dde
cmpl $0x2, -0x48(%rbp)
setl %al
movb %al, -0x1571(%rbp)
movb -0x1571(%rbp), %al
testb $0x1, %al
jne 0x4dea
jmp 0x4e3b
movl -0x34(%rbp), %esi
movq -0x18(%rbp), %rax
movl -0x34(%rbp), %ecx
movl -0x40(%rbp), %edx
movl %edx, %edi
addl $0x1, %edi
movl %edi, -0x40(%rbp)
movslq %edx, %rdx
movb %cl, -0x44(%rbp,%rdx)
movzbl %cl, %ecx
movzbl (%rax,%rcx), %edx
xorl %esi, %edx
movb %dl, (%rax,%rcx)
movl -0x48(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x48(%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 0x4db0
movl $0x0, -0x4c(%rbp)
xorl %eax, %eax
cmpl $0xf, -0x34(%rbp)
movb %al, -0x1572(%rbp)
jge 0x4e70
movl -0x38(%rbp), %ecx
addl $0x2, %ecx
xorl %eax, %eax
cmpl $0x4, %ecx
movb %al, -0x1572(%rbp)
jg 0x4e70
cmpl $0x2, -0x4c(%rbp)
setl %al
movb %al, -0x1572(%rbp)
movb -0x1572(%rbp), %al
testb $0x1, %al
jne 0x4e7c
jmp 0x4eb6
movl -0x34(%rbp), %esi
movq -0x18(%rbp), %rax
movslq -0x34(%rbp), %rcx
movzbl (%rax,%rcx), %edx
xorl %esi, %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 $0x2, %eax
movl %eax, -0x38(%rbp)
jmp 0x4e42
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
leaq -0x44(%rbp), %rdx
movl -0x40(%rbp), %ecx
callq 0xec10
movl %eax, -0x50(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x50(%rbp), %eax
je 0x4f1c
movq 0xdd0fc(%rip), %rdi     # 0xe1fd8
leaq 0x14b18(%rip), %rsi     # 0x199fb
callq 0x21b0
movq %rax, %rdi
movl -0x3c(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
leaq 0x14c48(%rip), %rsi     # 0x19b45
callq 0x21b0
movq %rax, %rdi
movl -0x50(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
movq 0xdd0b1(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movl -0x3c(%rbp), %eax
cmpl -0x50(%rbp), %eax
jne 0x4f26
jmp 0x4f45
leaq 0x14ae7(%rip), %rdi     # 0x19a14
leaq 0x149eb(%rip), %rsi     # 0x1991f
movl $0x3d, %edx
leaq 0x153cd(%rip), %rcx     # 0x1a30d
callq 0x2100
cmpl $0x0, -0x50(%rbp)
jl 0x4fa2
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
leaq -0x54(%rbp), %rdx
callq 0xec50
cmpl $0x0, %eax
je 0x4fa2
movq 0xdd070(%rip), %rdi     # 0xe1fd8
leaq 0x14aba(%rip), %rsi     # 0x19a29
callq 0x21b0
movq %rax, %rdi
movq 0xdd04a(%rip), %rsi     # 0xe1fc8
callq 0x21e0
leaq 0x14ad6(%rip), %rdi     # 0x19a60
leaq 0x1498e(%rip), %rsi     # 0x1991f
movl $0x41, %edx
leaq 0x15370(%rip), %rcx     # 0x1a30d
callq 0x2100
movb $0x0, -0x29(%rbp)
movl $0x0, -0x58(%rbp)
cmpl $0xf, -0x58(%rbp)
jge 0x4ff5
movq -0x18(%rbp), %rax
movslq -0x58(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movq -0x20(%rbp), %rcx
movslq -0x58(%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 -0x58(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x58(%rbp)
jmp 0x4fad
testb $0x1, -0x29(%rbp)
je 0x501d
movq 0xdcfd6(%rip), %rdi     # 0xe1fd8
leaq 0x14a5d(%rip), %rsi     # 0x19a66
callq 0x21b0
movq %rax, %rdi
movq 0xdcfb0(%rip), %rsi     # 0xe1fc8
callq 0x21e0
movb -0x29(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x5028
jmp 0x502a
jmp 0x5049
leaq 0x148e7(%rip), %rdi     # 0x19918
leaq 0x148e7(%rip), %rsi     # 0x1991f
movl $0x48, %edx
leaq 0x152c9(%rip), %rcx     # 0x1a30d
callq 0x2100
movq -0x28(%rbp), %rdi
callq 0xc360
shlq $0x3, %rax
addq $0x2c, %rax
subq $0x1, %rax
movl $0x2c, %ecx
xorl %edx, %edx
divq %rcx
movl %eax, -0x5c(%rbp)
imull $0xf, -0x5c(%rbp), %eax
movslq %eax, %rdi
callq 0x2030
movq %rax, -0x68(%rbp)
movl $0x0, -0x6c(%rbp)
movl $0x0, -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 0x50d4
jmp 0x5166
leaq -0x88(%rbp), %rdi
callq 0xb7c0
movzbl (%rax), %eax
movl %eax, -0x94(%rbp)
movl -0x94(%rbp), %eax
movl -0x70(%rbp), %ecx
shll %cl, %eax
orl -0x6c(%rbp), %eax
movl %eax, -0x6c(%rbp)
movl -0x70(%rbp), %eax
addl $0x8, %eax
movl %eax, -0x70(%rbp)
cmpl $0x4, -0x70(%rbp)
jb 0x5153
movl -0x70(%rbp), %eax
subl $0x4, %eax
movl %eax, -0x70(%rbp)
movl -0x6c(%rbp), %eax
andl $0xf, %eax
movb %al, %dl
movq -0x68(%rbp), %rax
movl -0x74(%rbp), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, -0x74(%rbp)
movl %ecx, %ecx
movb %dl, (%rax,%rcx)
movl -0x6c(%rbp), %eax
shrl $0x4, %eax
movl %eax, -0x6c(%rbp)
movl -0x74(%rbp), %eax
movl $0xf, %ecx
xorl %edx, %edx
divl %ecx
cmpl $0xb, %edx
jb 0x5151
movl -0x74(%rbp), %eax
addl $0x4, %eax
movl %eax, -0x74(%rbp)
jmp 0x5103
jmp 0x5155
leaq -0x88(%rbp), %rdi
callq 0xb7e0
jmp 0x50b8
callq 0x2040
movq %rax, -0xa0(%rbp)
movl $0x0, -0xa4(%rbp)
movl -0xa4(%rbp), %eax
cmpl -0x5c(%rbp), %eax
jge 0x51b1
movq -0x10(%rbp), %rdi
movq -0x68(%rbp), %rsi
imull $0xf, -0xa4(%rbp), %eax
cltq
addq %rax, %rsi
callq 0xebe0
movl -0xa4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa4(%rbp)
jmp 0x517c
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, -0x1598(%rbp)
leaq -0xb8(%rbp), %rdi
movq %rdi, -0x15a0(%rbp)
callq 0xc400
movq -0x15a0(%rbp), %rdi
movq %rax, %rcx
movq -0x1598(%rbp), %rax
movq %rcx, %rdx
shrq $0x3f, %rdx
addq %rdx, %rcx
sarq %rcx
addq %rcx, %rax
movq %rax, -0x1590(%rbp)
callq 0xc400
movq %rax, %rcx
movq -0x1590(%rbp), %rax
xorl %edx, %edx
divq %rcx
movl %eax, -0xc4(%rbp)
movl -0x5c(%rbp), %eax
imull $0x3c, %eax, %eax
movl %eax, %ecx
addl $0x7, %ecx
testl %eax, %eax
cmovsl %ecx, %eax
sarl $0x3, %eax
movl %eax, -0xc8(%rbp)
movslq -0xc8(%rbp), %rax
movq %rax, -0x1588(%rbp)
movq -0x28(%rbp), %rdi
callq 0xc360
movq %rax, %rcx
movq -0x1588(%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, -0x157c(%rbp)
testq %rax, %rax
movss %xmm0, -0x1578(%rbp)
js 0x52cd
movss -0x157c(%rbp), %xmm0
movss %xmm0, -0x1578(%rbp)
movss -0x1578(%rbp), %xmm0
movss 0x13d27(%rip), %xmm1    # 0x19004
mulss %xmm1, %xmm0
movss %xmm0, -0x15ac(%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, -0x15a8(%rbp)
testq %rax, %rax
movss %xmm0, -0x15a4(%rbp)
js 0x5333
movss -0x15a8(%rbp), %xmm0
movss %xmm0, -0x15a4(%rbp)
movss -0x15ac(%rbp), %xmm0
movss -0x15a4(%rbp), %xmm1
divss %xmm1, %xmm0
movss %xmm0, -0xcc(%rbp)
movq 0xdcc82(%rip), %rdi     # 0xe1fd8
leaq 0x14731(%rip), %rsi     # 0x19a8e
callq 0x21b0
movq %rax, -0x15d0(%rbp)
movq -0x28(%rbp), %rdi
callq 0xc360
movq -0x15d0(%rbp), %rdi
movq %rax, %rsi
callq 0x2060
movq %rax, %rdi
leaq 0x14710(%rip), %rsi     # 0x19a9b
callq 0x21b0
movq %rax, %rdi
movl -0xc8(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
leaq 0x14707(%rip), %rsi     # 0x19aaf
callq 0x21b0
movq %rax, -0x15c8(%rbp)
movl $0x1, %edi
callq 0xc420
movq -0x15c8(%rbp), %rdi
movl %eax, -0xd0(%rbp)
movl -0xd0(%rbp), %esi
callq 0x2280
movq %rax, %rdi
leaq 0x7060(%rip), %rsi      # 0xc440
callq 0x2080
movq %rax, %rdi
movss -0xcc(%rbp), %xmm0
callq 0x2130
movq %rax, %rdi
leaq 0x146c2(%rip), %rsi     # 0x19ac1
callq 0x21b0
movq %rax, %rdi
movl -0x5c(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
leaq 0x146ba(%rip), %rsi     # 0x19ad3
callq 0x21b0
movq -0x15a0(%rbp), %rdi
movq %rax, -0x15c0(%rbp)
callq 0xc400
movq -0x15c0(%rbp), %rdi
movq %rax, %rsi
callq 0x22f0
movq %rax, %rdi
leaq 0x14697(%rip), %rsi     # 0x19ae1
callq 0x21b0
movq %rax, %rdi
movl -0xc4(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
leaq 0x1468a(%rip), %rsi     # 0x19af1
callq 0x21b0
movq %rax, %rdi
movq 0xdcb52(%rip), %rsi     # 0xe1fc8
callq 0x21e0
leaq -0x1458(%rbp), %rdi
movq %rdi, -0x15b8(%rbp)
callq 0x2d20
movq -0x15b8(%rbp), %rdi
callq 0x2dc0
movl %eax, -0x15b0(%rbp)
jmp 0x54a2
movl -0x15b0(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
leaq -0x1460(%rbp), %rdi
callq 0x2de0
jmp 0x54ba
leaq -0x1474(%rbp), %rdi
xorl %esi, %esi
movl $0x3, %edx
callq 0xc470
jmp 0x54cf
leaq -0x147c(%rbp), %rdi
xorl %esi, %esi
movl $0xe, %edx
callq 0xc470
jmp 0x54e4
leaq -0x1490(%rbp), %rdi
leaq -0x1474(%rbp), %rsi
leaq -0x1460(%rbp), %rdx
callq 0xc4a0
jmp 0x5500
leaq -0x14a0(%rbp), %rdi
leaq -0x147c(%rbp), %rsi
leaq -0x1460(%rbp), %rdx
callq 0xc4a0
jmp 0x551c
movq -0x28(%rbp), %rdi
callq 0xc360
movq %rax, -0x15e0(%rbp)
leaq -0x14b9(%rbp), %rdi
movq %rdi, -0x15d8(%rbp)
callq 0x2e40
movq -0x15e0(%rbp), %rsi
movq -0x15d8(%rbp), %rdx
leaq -0x14b8(%rbp), %rdi
callq 0x2e60
jmp 0x555b
leaq -0x14b9(%rbp), %rdi
callq 0x2ed0
movl -0x5c(%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, -0x15e8(%rbp)
jmp 0x5585
movq -0x15e8(%rbp), %rax
movq %rax, -0x14c8(%rbp)
movl -0x5c(%rbp), %eax
shll $0x2, %eax
movslq %eax, %rdi
callq 0x2030
movq %rax, -0x15f0(%rbp)
jmp 0x55aa
movq -0x15f0(%rbp), %rax
movq %rax, -0x14d0(%rbp)
movl $0x0, -0x14d4(%rbp)
cmpl $0x4, -0x14d4(%rbp)
jg 0x5fb3
movl $0x0, -0x14d8(%rbp)
movl -0x14d8(%rbp), %eax
cmpl -0x14d4(%rbp), %eax
jg 0x5f9d
movl $0x0, -0x14dc(%rbp)
movl -0x14dc(%rbp), %eax
imull $0xf, -0x5c(%rbp), %ecx
cmpl %ecx, %eax
jge 0x5694
movq -0x68(%rbp), %rax
movslq -0x14dc(%rbp), %rcx
movb (%rax,%rcx), %dl
movq -0x14c8(%rbp), %rax
movslq -0x14dc(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x14dc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14dc(%rbp)
jmp 0x55f5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1468(%rbp)
movl %eax, -0x146c(%rbp)
jmp 0x6031
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1468(%rbp)
movl %eax, -0x146c(%rbp)
leaq -0x14b9(%rbp), %rdi
callq 0x2ed0
jmp 0x6031
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1468(%rbp)
movl %eax, -0x146c(%rbp)
leaq -0x14b8(%rbp), %rdi
callq 0xaab0
jmp 0x6031
movl $0x0, -0x14e0(%rbp)
movl $0x0, -0x14e4(%rbp)
movl -0x14e4(%rbp), %eax
cmpl -0x5c(%rbp), %eax
jge 0x584c
movl $0x0, -0x14e8(%rbp)
movl -0x14e8(%rbp), %eax
cmpl -0x14d4(%rbp), %eax
jge 0x5836
leaq -0x14a0(%rbp), %rdi
callq 0xc4e0
movl %eax, -0x15f4(%rbp)
jmp 0x56e7
movl -0x15f4(%rbp), %eax
movb %al, %dl
movq -0x14d0(%rbp), %rax
movl -0x14e4(%rbp), %ecx
shll $0x2, %ecx
addl -0x14e8(%rbp), %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl $0x0, -0x14ec(%rbp)
movl -0x14ec(%rbp), %eax
cmpl -0x14e8(%rbp), %eax
jge 0x57b9
movq -0x14d0(%rbp), %rax
movl -0x14e4(%rbp), %ecx
shll $0x2, %ecx
movl -0x14ec(%rbp), %edx
movl %edx, %esi
addl $0x1, %esi
movl %esi, -0x14ec(%rbp)
addl %edx, %ecx
movslq %ecx, %rcx
movzbl (%rax,%rcx), %eax
movq -0x14d0(%rbp), %rcx
movl -0x14e4(%rbp), %edx
shll $0x2, %edx
addl -0x14e8(%rbp), %edx
movslq %edx, %rdx
movzbl (%rcx,%rdx), %ecx
cmpl %ecx, %eax
jne 0x57b4
leaq -0x14a0(%rbp), %rdi
callq 0xc4e0
movl %eax, -0x15f8(%rbp)
jmp 0x5786
movl -0x15f8(%rbp), %eax
movb %al, %dl
movq -0x14d0(%rbp), %rax
movl -0x14e4(%rbp), %ecx
shll $0x2, %ecx
addl -0x14e8(%rbp), %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl $0x0, -0x14ec(%rbp)
jmp 0x5715
leaq -0x1490(%rbp), %rdi
callq 0xc4e0
movl %eax, -0x15fc(%rbp)
jmp 0x57cd
movl -0x15fc(%rbp), %ecx
movl $0x1, %esi
shll %cl, %esi
movq -0x14c8(%rbp), %rax
imull $0xf, -0x14e4(%rbp), %ecx
movq -0x14d0(%rbp), %rdx
movl -0x14e4(%rbp), %edi
shll $0x2, %edi
addl -0x14e8(%rbp), %edi
movslq %edi, %rdi
movzbl (%rdx,%rdi), %edx
addl %edx, %ecx
movslq %ecx, %rcx
movzbl (%rax,%rcx), %edx
xorl %esi, %edx
movb %dl, (%rax,%rcx)
movl -0x14e0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14e0(%rbp)
movl -0x14e8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14e8(%rbp)
jmp 0x56c1
jmp 0x5838
movl -0x14e4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14e4(%rbp)
jmp 0x56a8
movl $0x0, -0x14f0(%rbp)
movl $0x0, -0x14f4(%rbp)
callq 0x2040
movq %rax, -0x1500(%rbp)
movl $0x0, -0x1504(%rbp)
movl -0x1504(%rbp), %eax
cmpl -0x5c(%rbp), %eax
jge 0x598b
movq -0x10(%rbp), %rdi
movq -0x14c8(%rbp), %rsi
movl -0x1504(%rbp), %eax
movl %eax, %ecx
leal (%rcx,%rcx,4), %edx
movl %edx, %ecx
leal (%rcx,%rcx,2), %ecx
movslq %ecx, %rcx
addq %rcx, %rsi
movq -0x14d0(%rbp), %rdx
shll $0x2, %eax
cltq
addq %rax, %rdx
movl -0x14d8(%rbp), %ecx
callq 0xec10
movl %eax, -0x1600(%rbp)
jmp 0x58c8
movl -0x1600(%rbp), %eax
movl %eax, -0x1508(%rbp)
cmpl $0x2, -0x14d4(%rbp)
jle 0x5965
movl -0x14d4(%rbp), %eax
cmpl -0x14d8(%rbp), %eax
jle 0x5965
cmpl $0x0, -0x1508(%rbp)
jl 0x5965
imull $0xf, -0x1504(%rbp), %eax
movl %eax, -0x150c(%rbp)
movl -0x150c(%rbp), %eax
movl -0x1504(%rbp), %ecx
addl $0x1, %ecx
imull $0xf, %ecx, %ecx
cmpl %ecx, %eax
jge 0x5963
movq -0x68(%rbp), %rax
movslq -0x150c(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movq -0x14c8(%rbp), %rcx
movslq -0x150c(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
cmpl %ecx, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
addl -0x14f4(%rbp), %eax
movl %eax, -0x14f4(%rbp)
movl -0x150c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x150c(%rbp)
jmp 0x5905
jmp 0x5965
movl -0x1508(%rbp), %eax
addl -0x14f0(%rbp), %eax
movl %eax, -0x14f0(%rbp)
movl -0x1504(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1504(%rbp)
jmp 0x5876
callq 0x2040
movq %rax, -0x1518(%rbp)
leaq -0x1518(%rbp), %rdi
leaq -0x1500(%rbp), %rsi
callq 0xc3b0
movq %rax, -0x1608(%rbp)
jmp 0x59b3
movq -0x1608(%rbp), %rax
movq %rax, -0x1528(%rbp)
leaq -0x1528(%rbp), %rdi
callq 0xc380
movq %rax, -0x1610(%rbp)
jmp 0x59d6
movq -0x1610(%rbp), %rax
movq %rax, -0x1520(%rbp)
movl -0x5c(%rbp), %eax
imull $0x3c, %eax, %eax
movl %eax, %ecx
addl $0x7, %ecx
testl %eax, %eax
cmovsl %ecx, %eax
sarl $0x3, %eax
movl %eax, -0x152c(%rbp)
movslq -0x152c(%rbp), %rax
movq %rax, -0x1628(%rbp)
leaq -0x1520(%rbp), %rdi
movq %rdi, -0x1630(%rbp)
callq 0xc400
movq -0x1630(%rbp), %rdi
movq %rax, %rcx
movq -0x1628(%rbp), %rax
movq %rcx, %rdx
shrq $0x3f, %rdx
addq %rdx, %rcx
sarq %rcx
addq %rcx, %rax
movq %rax, -0x1620(%rbp)
callq 0xc400
movq %rax, %rcx
movq -0x1620(%rbp), %rax
cqto
idivq %rcx
movl %eax, -0x1530(%rbp)
movq 0xdc571(%rip), %rdi     # 0xe1fd8
leaq 0x1408a(%rip), %rsi     # 0x19af8
callq 0x21b0
movq %rax, -0x1618(%rbp)
jmp 0x5a7c
movq -0x1618(%rbp), %rdi
movl -0x14d4(%rbp), %esi
callq 0x22b0
movq %rax, -0x1638(%rbp)
jmp 0x5a97
movq -0x1638(%rbp), %rdi
leaq 0x14062(%rip), %rsi     # 0x19b07
callq 0x21b0
movq %rax, -0x1640(%rbp)
jmp 0x5ab3
movq -0x1640(%rbp), %rdi
movl -0x14d8(%rbp), %esi
callq 0x22b0
movq %rax, -0x1648(%rbp)
jmp 0x5ace
movq -0x1648(%rbp), %rdi
leaq 0x14038(%rip), %rsi     # 0x19b14
callq 0x21b0
movq %rax, -0x1650(%rbp)
jmp 0x5aea
leaq -0x1520(%rbp), %rdi
callq 0xc400
movq -0x1650(%rbp), %rdi
movq %rax, %rsi
callq 0x22f0
movq %rax, -0x1658(%rbp)
jmp 0x5b0e
movq -0x1658(%rbp), %rdi
leaq 0x13fc5(%rip), %rsi     # 0x19ae1
callq 0x21b0
movq %rax, -0x1660(%rbp)
jmp 0x5b2a
movq -0x1660(%rbp), %rdi
movl -0x1530(%rbp), %esi
callq 0x22b0
movq %rax, -0x1668(%rbp)
jmp 0x5b45
movq -0x1668(%rbp), %rdi
leaq 0x13f9e(%rip), %rsi     # 0x19af1
callq 0x21b0
jmp 0x5b5a
movl -0x14e0(%rbp), %eax
cmpl -0x14f0(%rbp), %eax
jne 0x5b75
cmpl $0x0, -0x14f4(%rbp)
je 0x5c31
movq 0xdc45c(%rip), %rdi     # 0xe1fd8
leaq 0x13e86(%rip), %rsi     # 0x19a09
callq 0x21b0
movq %rax, -0x1670(%rbp)
jmp 0x5b91
movq -0x1670(%rbp), %rdi
movl -0x14e0(%rbp), %esi
callq 0x22b0
movq %rax, -0x1678(%rbp)
jmp 0x5bac
movq -0x1678(%rbp), %rdi
leaq 0x13f7a(%rip), %rsi     # 0x19b34
callq 0x21b0
movq %rax, -0x1680(%rbp)
jmp 0x5bc8
movq -0x1680(%rbp), %rdi
movl -0x14f0(%rbp), %esi
callq 0x22b0
movq %rax, -0x1688(%rbp)
jmp 0x5be3
movq -0x1688(%rbp), %rdi
leaq 0x13f1d(%rip), %rsi     # 0x19b0e
callq 0x21b0
movq %rax, -0x1690(%rbp)
jmp 0x5bff
movq -0x1690(%rbp), %rdi
movl -0x14f4(%rbp), %esi
callq 0x22b0
movq %rax, -0x1698(%rbp)
jmp 0x5c1a
movq -0x1698(%rbp), %rdi
leaq 0x13f27(%rip), %rsi     # 0x19b4f
callq 0x21b0
jmp 0x5c2f
jmp 0x5c31
movq 0xdc3a0(%rip), %rdi     # 0xe1fd8
movq 0xdc389(%rip), %rsi     # 0xe1fc8
callq 0x21e0
jmp 0x5c46
cmpl $0x2, -0x14d4(%rbp)
jle 0x5c65
movl -0x14d4(%rbp), %ecx
movb $0x1, %al
cmpl -0x14d8(%rbp), %ecx
movb %al, -0x1699(%rbp)
jg 0x5c99
movl -0x14e0(%rbp), %ecx
xorl %eax, %eax
cmpl -0x14f0(%rbp), %ecx
movb %al, -0x169a(%rbp)
jne 0x5c8d
cmpl $0x0, -0x14f4(%rbp)
setne %al
xorb $-0x1, %al
movb %al, -0x169a(%rbp)
movb -0x169a(%rbp), %al
movb %al, -0x1699(%rbp)
movb -0x1699(%rbp), %al
testb $0x1, %al
jne 0x5ca5
jmp 0x5ca7
jmp 0x5cc6
leaq 0x13eb5(%rip), %rdi     # 0x19b63
leaq 0x13c6a(%rip), %rsi     # 0x1991f
movl $0x91, %edx
leaq 0x1464c(%rip), %rcx     # 0x1a30d
callq 0x2100
movl -0x14e0(%rbp), %eax
cmpl -0x14f0(%rbp), %eax
jne 0x5f87
cmpl $0x0, -0x14f4(%rbp)
jne 0x5f87
movl $0x0, -0x1534(%rbp)
movl $0x0, -0x1538(%rbp)
movl $0x0, -0x153c(%rbp)
leaq -0x14b8(%rbp), %rax
movq %rax, -0x1548(%rbp)
movq -0x1548(%rbp), %rdi
callq 0x2f50
movq %rax, -0x1550(%rbp)
movq -0x1548(%rbp), %rdi
callq 0x2f80
movq %rax, -0x1558(%rbp)
leaq -0x1550(%rbp), %rdi
leaq -0x1558(%rbp), %rsi
callq 0xb750
testb $0x1, %al
jne 0x5d53
jmp 0x5e1a
leaq -0x1550(%rbp), %rdi
callq 0xb7c0
movq %rax, -0x1560(%rbp)
cmpl $0x8, -0x1538(%rbp)
jae 0x5dd5
movq -0x14c8(%rbp), %rax
movl -0x153c(%rbp), %ecx
movl %ecx, %edx
addl $0x1, %edx
movl %edx, -0x153c(%rbp)
movl %ecx, %ecx
movzbl (%rax,%rcx), %eax
movl -0x1538(%rbp), %ecx
shll %cl, %eax
orl -0x1534(%rbp), %eax
movl %eax, -0x1534(%rbp)
movl -0x1538(%rbp), %eax
addl $0x4, %eax
movl %eax, -0x1538(%rbp)
movl -0x153c(%rbp), %eax
movl $0xf, %ecx
xorl %edx, %edx
divl %ecx
cmpl $0xb, %edx
jb 0x5dd3
movl -0x153c(%rbp), %eax
addl $0x4, %eax
movl %eax, -0x153c(%rbp)
jmp 0x5d66
movl -0x1538(%rbp), %eax
subl $0x8, %eax
movl %eax, -0x1538(%rbp)
movl -0x1534(%rbp), %eax
andl $0xff, %eax
movb %al, %cl
movq -0x1560(%rbp), %rax
movb %cl, (%rax)
movl -0x1534(%rbp), %eax
shrl $0x8, %eax
movl %eax, -0x1534(%rbp)
leaq -0x1550(%rbp), %rdi
callq 0xb7e0
jmp 0x5d37
movl $0x0, -0x1564(%rbp)
movl -0x1564(%rbp), %eax
cmpl -0x5c(%rbp), %eax
jge 0x5ed8
movq -0x10(%rbp), %rdi
movq -0x14c8(%rbp), %rsi
movl -0x1564(%rbp), %ecx
movl %ecx, %eax
leal (%rax,%rax,4), %ecx
movl %ecx, %eax
leal (%rax,%rax,2), %eax
cltq
addq %rax, %rsi
leaq -0x1568(%rbp), %rdx
callq 0xec50
movl %eax, -0x16a0(%rbp)
jmp 0x5e67
movl -0x16a0(%rbp), %eax
cmpl $0x0, %eax
je 0x5ec2
movq 0xdc15f(%rip), %rdi     # 0xe1fd8
leaq 0x13ba9(%rip), %rsi     # 0x19a29
callq 0x21b0
movq %rax, -0x16a8(%rbp)
jmp 0x5e8e
movq -0x16a8(%rbp), %rdi
movq 0xdc12c(%rip), %rsi     # 0xe1fc8
callq 0x21e0
jmp 0x5ea3
leaq 0x13bb6(%rip), %rdi     # 0x19a60
leaq 0x13a6e(%rip), %rsi     # 0x1991f
movl $0xa3, %edx
leaq 0x14450(%rip), %rcx     # 0x1a30d
callq 0x2100
jmp 0x5ec4
movl -0x1564(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1564(%rbp)
jmp 0x5e24
movq -0x28(%rbp), %rdi
leaq -0x14b8(%rbp), %rsi
callq 0xc510
movb %al, -0x16a9(%rbp)
jmp 0x5ef0
movb -0x16a9(%rbp), %al
testb $0x1, %al
jne 0x5eff
jmp 0x5f85
movq 0xdc0d2(%rip), %rdi     # 0xe1fd8
leaq 0x13cc4(%rip), %rsi     # 0x19bd1
callq 0x21b0
movq %rax, -0x16b8(%rbp)
jmp 0x5f1b
movq -0x16b8(%rbp), %rdi
movq 0xdc09f(%rip), %rsi     # 0xe1fc8
callq 0x21e0
jmp 0x5f30
xorl %eax, %eax
cmpl $0x2, -0x14d4(%rbp)
movb %al, -0x16b9(%rbp)
jle 0x5f56
movl -0x14d4(%rbp), %eax
cmpl -0x14d8(%rbp), %eax
setg %al
movb %al, -0x16b9(%rbp)
movb -0x16b9(%rbp), %al
testb $0x1, %al
jne 0x5f62
jmp 0x5f64
jmp 0x5f83
leaq 0x13ca2(%rip), %rdi     # 0x19c0d
leaq 0x139ad(%rip), %rsi     # 0x1991f
movl $0xa8, %edx
leaq 0x1438f(%rip), %rcx     # 0x1a30d
callq 0x2100
jmp 0x5f85
jmp 0x5f87
jmp 0x5f89
movl -0x14d8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14d8(%rbp)
jmp 0x55d9
jmp 0x5f9f
movl -0x14d4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14d4(%rbp)
jmp 0x55c2
movq -0x14d0(%rbp), %rax
movq %rax, -0x16c8(%rbp)
cmpq $0x0, %rax
je 0x5fd3
movq -0x16c8(%rbp), %rdi
callq 0x2240
movq -0x14c8(%rbp), %rax
movq %rax, -0x16d0(%rbp)
cmpq $0x0, %rax
je 0x5ff3
movq -0x16d0(%rbp), %rdi
callq 0x2240
movq -0x68(%rbp), %rax
movq %rax, -0x16d8(%rbp)
cmpq $0x0, %rax
je 0x6010
movq -0x16d8(%rbp), %rdi
callq 0x2240
leaq -0x14b8(%rbp), %rdi
callq 0xaab0
leaq -0x1458(%rbp), %rdi
callq 0xab10
addq $0x16e0, %rsp           # imm = 0x16E0
popq %rbp
retq
leaq -0x1458(%rbp), %rdi
callq 0xab10
movq -0x1468(%rbp), %rdi
callq 0x22c0
nopl (%rax)