// File: BenLangmead[P]bowtie/ebwt_search.cpp
// Function: mismatchSearchWorkerFull(void*)
static void mismatchSearchWorkerFull(void *vp){
	thread_tracking_pair *p = (thread_tracking_pair*) vp;
	int tid = p->tid;
#else
static void mismatchSearchWorkerFull(void *vp){
	int tid = *((int*)vp);
#endif
	if(thread_stealing) {
		increment_thread_counter();
	}
	PatternComposer&	_patsrc = *mismatchSearch_patsrc;
	HitSink&		_sink   = *mismatchSearch_sink;
	Ebwt&			ebwtFw  = *mismatchSearch_ebwtFw;
	Ebwt&			ebwtBw  = *mismatchSearch_ebwtBw;
	EList<BTRefString >& os      = *mismatchSearch_os;

	// Per-thread initialization
	PatternSourcePerThreadFactory* patsrcFact = createPatsrcFactory(_patsrc, tid, readsPerBatch);
	PatternSourcePerThread* patsrc = patsrcFact->create();
	HitSinkPerThreadFactory* sinkFact = createSinkFactory(_sink, tid);
	HitSinkPerThread* sink = sinkFact->create();
	EbwtSearchParams params(
	        *sink,      // HitSinkPerThread
	        os,         // reference sequences
	        true,       // read is forward
	        false);     // index is mirror index
	GreedyDFSRangeSource bt(
	        &ebwtFw, params,
	        0xffffffff,     // qualThresh
	        0xffffffff,     // max backtracks (no max)
	        0,              // reportPartials (don't)
	        true,           // reportExacts
	        rangeMode,      // reportRanges
	        NULL,           // seedlings
	        NULL,           // mutations
	        verbose,        // verbose
	        &os,
	        false);         // considerQuals
	bool skipped = false;
	pair<bool, bool> get_read_ret = make_pair(false, false);
#ifdef PER_THREAD_TIMING
	uint64_t ncpu_changeovers = 0;
	uint64_t nnuma_changeovers = 0;

	int current_cpu = 0, current_node = 0;
	get_cpu_and_node(current_cpu, current_node);

	std::stringstream ss;
	std::string msg;
	ss << "thread: " << tid << " time: ";
	msg = ss.str();
	{
		Timer timer(std::cout, msg.c_str());
#endif
		while(true) {
#ifdef PER_THREAD_TIMING
			int cpu = 0, node = 0;
			get_cpu_and_node(cpu, node);
			if(cpu != current_cpu) {
				ncpu_changeovers++;
				current_cpu = cpu;
			}
			if(node != current_node) {
				nnuma_changeovers++;
				current_node = node;
			}
#endif
			FINISH_READ(patsrc);
			GET_READ(patsrc);
			uint32_t plen = (uint32_t)patFw.length();
			uint32_t s = plen;
			uint32_t s3 = s >> 1; // length of 3' half of seed
			uint32_t s5 = (s >> 1) + (s & 1); // length of 5' half of seed
			#define DONEMASK_SET(p)
			#include "search_1mm_phase1.c"
			#include "search_1mm_phase2.c"
			#undef DONEMASK_SET
		} // End read loop
		FINISH_READ(patsrc);
#ifdef PER_THREAD_TIMING
		ss.str("");
		ss.clear();
		ss << "thread: " << tid << " cpu_changeovers: " << ncpu_changeovers << std::endl
		   << "thread: " << tid << " node_changeovers: " << nnuma_changeovers << std::endl;
		std::cout << ss.str();
	}
#endif
#if (__cplusplus >= 201103L)
	p->done->fetch_add(1);
#endif
    	WORKER_EXIT();
}

/**
 * Search through a single (forward) Ebwt index for exact end-to-end
 * hits.  Assumes that index is already loaded into memory.
 */
static void mismatchSearchFull(PatternComposer& _patsrc,
                               HitSink& _sink,
                               Ebwt& ebwtFw,
                               Ebwt& ebwtBw,
                               EList<BTRefString >& os)
{
	mismatchSearch_patsrc       = &_patsrc;
	mismatchSearch_sink         = &_sink;
	mismatchSearch_ebwtFw       = &ebwtFw;
	mismatchSearch_ebwtBw       = &ebwtBw;
	mismatchSearch_doneMask     = NULL;
	mismatchSearch_hitMask      = NULL;
	mismatchSearch_os           = &os;

	assert(!ebwtFw.isInMemory());
	assert(!ebwtBw.isInMemory());
	{
		// Load the other half of the index into memory
		Timer _t(cerr, "Time loading forward index: ", timing);
		ebwtFw.loadIntoMemory(-1, !noRefNames, startVerbose);
	}
	{
		// Load the other half of the index into memory
		Timer _t(cerr, "Time loading mirror index: ", timing);
		ebwtBw.loadIntoMemory(-1, !noRefNames, startVerbose);
	}
	// Create range caches, which are shared among all aligners
	BitPairReference *refs = NULL;
	bool pair = mates1.size() > 0 || mates12.size() > 0;
	if(pair && mixedThresh < 0xffffffff) {
		Timer _t(cerr, "Time loading reference: ", timing);
		refs = new BitPairReference(adjustedEbwtFileBase, sanityCheck, NULL, &os, false, true, useMm, useShmem, mmSweep, verbose, startVerbose);
		if(!refs->loaded()) throw 1;
	}
	mismatchSearch_refs = refs;

	int tids[max(nthreads, thread_ceiling)];
#if (__cplusplus >= 201103L)
	EList<std::thread*> threads;
	EList<thread_tracking_pair> tps;
	tps.resizeExact(max(nthreads, thread_ceiling));
#else
	EList<tthread::thread*> threads;
#endif

#if (__cplusplus >= 201103L)
	std::atomic<int> all_threads_done;
	all_threads_done = 0;
#endif

	CHUD_START();
	{
		Timer _t(cerr, "Time for 1-mismatch full-index search: ", timing);

#ifndef _WIN32
		int pid = 0;
		if(thread_stealing) {
			pid = getpid();
			write_pid(thread_stealing_dir.c_str(), pid);
			thread_counter = 0;
		}
#endif

		for(int i = 0; i < nthreads; i++) {
			tids[i] = i;
#if (__cplusplus >= 201103L)
			tps[i].tid = tids[i];
			tps[i].done = &all_threads_done;
			if (i == nthreads - 1) {
				if(stateful) {
					mismatchSearchWorkerFullStateful((void*)&tps[i]);
				} else {
					mismatchSearchWorkerFull((void*)&tps[i]);
				}
			}
			else {
				if(stateful) {
					threads.push_back(new std::thread(mismatchSearchWorkerFullStateful, (void*)&tps[i]));
				} else {
					threads.push_back(new std::thread(mismatchSearchWorkerFull, (void*)&tps[i]));
				}
				threads[i]->detach();
				SLEEP(10);
			}
#else
			if (i == nthreads - 1) {
				if(stateful) {
					mismatchSearchWorkerFullStateful((void*)(tids + i));
				} else {
					mismatchSearchWorkerFull((void*)(tids + i));
				}
			}
			else {
				if(stateful) {
					threads.push_back(new tthread::thread(mismatchSearchWorkerFullStateful, (void *)(tids + i)));
				} else {
					threads.push_back(new tthread::thread(mismatchSearchWorkerFull, (void *)(tids + i)));
				}
			}
#endif
		}

#ifndef _WIN32
		if(thread_stealing) {
			int orig_threads = nthreads, steal_ctr = 1;
			for(int j = 0; j < 10; j++) {
				sleep(1);
			}
			while(thread_counter > 0) {
				if(steal_thread(pid, orig_threads)) {
					nthreads++;
					tids[nthreads-1] = nthreads;
#if (__cplusplus >= 201103L)
					tps[nthreads-1].tid = nthreads - 1;
					tps[nthreads-1].done = &all_threads_done;
					if(stateful) {
						threads.push_back(new std::thread(mismatchSearchWorkerFullStateful, (void*)&tps[nthreads-1]));
					} else {
						threads.push_back(new std::thread(mismatchSearchWorkerFull, (void*)&tps[nthreads-1]));
					}
					threads[nthreads - 1]->detach();
					SLEEP(10);
#else
					if(stateful) {
						threads.push_back(new tthread::thread(mismatchSearchWorkerFullStateful, (void *)(tids + nthreads - 1)));
					} else {
						threads.push_back(new tthread::thread(mismatchSearchWorkerFull, (void *)(tids + nthreads - 1)));
					}
#endif
					cerr << "pid " << pid << " started new worker # " << nthreads << endl;
				}
				steal_ctr++;
				for(int j = 0; j < 10; j++) {
					sleep(1);
				}
			}
		}
#endif

#if (__cplusplus >= 201103L)
		while(all_threads_done < nthreads) {
			SLEEP(10);
		}
#else
		for (int i = 0; i < nthreads - 1; i++) {
			threads[i]->join();
		}
#endif

#ifndef _WIN32
		if(thread_stealing) {
			del_pid(thread_stealing_dir.c_str(), pid);
		}
#endif
	}
	if(refs != NULL) delete refs;

	for (int i = 0; i < nthreads - 1; i++) {
		if (threads[i] != NULL) {
			delete threads[i];
		}
	}
}

#define SWITCH_TO_FW_INDEX() { \
	/* Evict the mirror index from memory if necessary */ \
	if(ebwtBw.isInMemory()) ebwtBw.evictFromMemory(); \
	assert(!ebwtBw.isInMemory()); \
	/* Load the forward index into memory if necessary */ \
	if(!ebwtFw.isInMemory()) { \
		Timer _t(cerr, "Time loading forward index: ", timing); \
		ebwtFw.loadIntoMemory(-1, !noRefNames, startVerbose); \
	} \
	assert(ebwtFw.isInMemory()); \
	_patsrc.reset(); /* rewind pattern source to first pattern */ \
}

#define SWITCH_TO_BW_INDEX() { \
	/* Evict the forward index from memory if necessary */ \
	if(ebwtFw.isInMemory()) ebwtFw.evictFromMemory(); \
	assert(!ebwtFw.isInMemory()); \
	/* Load the forward index into memory if necessary */ \
	if(!ebwtBw.isInMemory()) { \
		Timer _t(cerr, "Time loading mirror index: ", timing); \
		ebwtBw.loadIntoMemory(-1, !noRefNames, startVerbose);   \
	} \
	assert(ebwtBw.isInMemory()); \
	_patsrc.reset(); /* rewind pattern source to first pattern */ \
}

#define ASSERT_NO_HITS_FW(ebwtfw) \
	if(sanityCheck && os.size() > 0) { \
		EList<Hit> hits; \
		uint32_t threeRevOff = (seedMms <= 3) ? s : 0; \
		uint32_t twoRevOff   = (seedMms <= 2) ? s : 0; \
		uint32_t oneRevOff   = (seedMms <= 1) ? s : 0; \
		uint32_t unrevOff    = (seedMms == 0) ? s : 0; \
		if(hits.size() > 0) { \
			/* Print offending hit obtained by oracle */ \
			::printHit( \
				os, \
				hits[0], \
				patFw, \
				plen, \
				unrevOff, \
				oneRevOff, \
				twoRevOff, \
				threeRevOff, \
				ebwtfw);  /* ebwtFw */ \
		} \
		assert_eq(0, hits.size()); \
	}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x460, %rsp            # imm = 0x460
movq %rdi, -0x20(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x2c(%rbp)
testb $0x1, 0x8adf5(%rip)     # 0xab3fc
je 0x2060e
callq 0x11970
movq 0x8aed3(%rip), %rax     # 0xab4e8
movq %rax, -0x38(%rbp)
movq 0x8aed0(%rip), %rax     # 0xab4f0
movq %rax, -0x40(%rbp)
movq 0x8aecd(%rip), %rax     # 0xab4f8
movq %rax, -0x48(%rbp)
movq 0x8aeca(%rip), %rax     # 0xab500
movq %rax, -0x50(%rbp)
movq 0x8aed7(%rip), %rax     # 0xab518
movq %rax, -0x58(%rbp)
movq -0x38(%rbp), %rdi
movl -0x2c(%rbp), %esi
movl 0x8adc6(%rip), %edx     # 0xab418
callq 0x1f890
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rdi
movq (%rdi), %rax
movq (%rax), %rax
callq *%rax
movq %rax, -0x68(%rbp)
movq -0x40(%rbp), %rdi
movslq -0x2c(%rbp), %rsi
callq 0x1f910
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rdi
movq (%rdi), %rax
movq 0x10(%rax), %rax
callq *%rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rsi
movq -0x58(%rbp), %rdx
leaq -0x90(%rbp), %rdi
movq %rdi, -0x2f8(%rbp)
movl $0x1, %ecx
xorl %r8d, %r8d
movl %r8d, -0x2ec(%rbp)
callq 0x3db70
movq -0x2f8(%rbp), %rdx
movl -0x2ec(%rbp), %r9d
movq -0x48(%rbp), %rsi
movq -0x58(%rbp), %r8
movzbl 0x8ace1(%rip), %ecx     # 0xab3b5
movzbl 0x8acc5(%rip), %edi     # 0xab3a0
movq %rsp, %rax
movq %rax, -0x2e8(%rbp)
movq %r8, 0x28(%rax)
andl $0x1, %edi
movl %edi, 0x20(%rax)
andl $0x1, %ecx
movl %ecx, 0x8(%rax)
movl $0x1, 0x40(%rax)
movl $0x0, 0x38(%rax)
movl $0x0, 0x30(%rax)
movq $0x0, 0x18(%rax)
movq $0x0, 0x10(%rax)
movl $0x1, (%rax)
leaq -0x270(%rbp), %rdi
movl $0xffffffff, %r8d       # imm = 0xFFFFFFFF
movl %r8d, %ecx
callq 0x65940
movb $0x0, -0x271(%rbp)
movb $0x0, -0x274(%rbp)
movb $0x0, -0x275(%rbp)
leaq -0x274(%rbp), %rdi
leaq -0x275(%rbp), %rsi
callq 0x65c90
movw %ax, -0x2de(%rbp)
jmp 0x20766
movw -0x2de(%rbp), %ax
movw %ax, -0x273(%rbp)
jmp 0x20776
testb $0x1, -0x273(%rbp)
je 0x207d1
movq -0x78(%rbp), %rdi
movq -0x68(%rbp), %rsi
movb -0x271(%rbp), %cl
notb %cl
movq (%rdi), %rax
movq 0x10(%rax), %rax
movzbl %cl, %ecx
andl $0x1, %ecx
movl $0x1, %edx
callq *%rax
jmp 0x207a5
movb $0x0, -0x273(%rbp)
jmp 0x207d1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x280(%rbp)
movl %eax, -0x284(%rbp)
leaq -0x270(%rbp), %rdi
callq 0x669a0
jmp 0x2106d
movb $0x0, -0x271(%rbp)
testb $0x1, -0x272(%rbp)
je 0x207e6
jmp 0x20f07
movq -0x68(%rbp), %rdi
callq 0x7e940
movw %ax, -0x2fa(%rbp)
jmp 0x207f8
movw -0x2fa(%rbp), %ax
movw %ax, -0x286(%rbp)
leaq -0x273(%rbp), %rdi
leaq -0x286(%rbp), %rsi
callq 0x65cc0
movq -0x68(%rbp), %rdi
callq 0x499a0
movq %rax, -0x308(%rbp)
jmp 0x2082b
movq -0x308(%rbp), %rax
movl 0x8ab80(%rip), %ecx     # 0xab3b8
cmpq %rcx, %rax
jb 0x20888
movb $0x0, -0x289(%rbp)
movb $0x1, -0x28a(%rbp)
leaq -0x289(%rbp), %rdi
leaq -0x28a(%rbp), %rsi
callq 0x65c90
movw %ax, -0x30a(%rbp)
jmp 0x20867
movw -0x30a(%rbp), %ax
movw %ax, -0x288(%rbp)
leaq -0x273(%rbp), %rdi
leaq -0x288(%rbp), %rsi
callq 0x65cc0
testb $0x1, -0x273(%rbp)
jne 0x208a4
testb $0x1, -0x272(%rbp)
je 0x2089f
jmp 0x20f07
jmp 0x20774
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x318(%rbp)
jmp 0x208b6
movq -0x318(%rbp), %rax
movq %rax, -0x298(%rbp)
movq -0x298(%rbp), %rdi
callq 0x2ef90
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x320(%rbp)
jmp 0x208e2
movq -0x320(%rbp), %rax
addq $0x30, %rax
movq %rax, -0x2a0(%rbp)
movq -0x2a0(%rbp), %rdi
callq 0x2ef90
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x328(%rbp)
jmp 0x20912
movq -0x328(%rbp), %rax
addq $0x60, %rax
movq %rax, -0x2a8(%rbp)
movq -0x2a8(%rbp), %rdi
callq 0x2ef90
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x330(%rbp)
jmp 0x20942
movq -0x330(%rbp), %rax
addq $0xf0, %rax
movq %rax, -0x2b0(%rbp)
movq -0x2b0(%rbp), %rdi
callq 0x2ef90
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x338(%rbp)
jmp 0x20974
movq -0x338(%rbp), %rax
addq $0x90, %rax
movq %rax, -0x2b8(%rbp)
movq -0x2b8(%rbp), %rdi
callq 0x2ef90
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x340(%rbp)
jmp 0x209a6
movq -0x340(%rbp), %rax
addq $0xc0, %rax
movq %rax, -0x2c0(%rbp)
movq -0x2c0(%rbp), %rdi
callq 0x2ef90
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x348(%rbp)
jmp 0x209d8
movq -0x348(%rbp), %rax
addq $0x150, %rax            # imm = 0x150
movq %rax, -0x2c8(%rbp)
movq -0x2c8(%rbp), %rdi
callq 0x2ef90
movq -0x68(%rbp), %rdi
callq 0x499a0
movq %rax, -0x350(%rbp)
jmp 0x20a0a
movq -0x350(%rbp), %rax
movl %eax, -0x2cc(%rbp)
movl -0x2cc(%rbp), %esi
leaq -0x90(%rbp), %rdi
callq 0x65cf0
movq -0x298(%rbp), %rdi
callq 0x2ef90
movl %eax, -0x2d0(%rbp)
movl -0x2d0(%rbp), %eax
movl %eax, -0x2d4(%rbp)
movl -0x2d4(%rbp), %eax
shrl %eax
movl %eax, -0x2d8(%rbp)
movl -0x2d4(%rbp), %ecx
movl %ecx, %eax
shrl %eax
andl $0x1, %ecx
addl %ecx, %eax
movl %eax, -0x2dc(%rbp)
movq -0x48(%rbp), %rsi
leaq -0x270(%rbp), %rdi
callq 0x70260
jmp 0x20a7c
leaq -0x270(%rbp), %rdi
movl $0x1, %esi
callq 0x65d10
cmpl $0x2, -0x2d0(%rbp)
jae 0x20aef
movq 0x87553(%rip), %rdi     # 0xa7ff0
leaq 0x6c99f(%rip), %rsi     # 0x8d443
callq 0xa5d0
movq %rax, -0x358(%rbp)
jmp 0x20ab2
movq -0x358(%rbp), %rdi
movq 0x874a8(%rip), %rsi     # 0xa7f68
callq 0xa640
jmp 0x20ac7
movl $0x4, %edi
callq 0xa290
movq %rax, %rdi
movl $0x1, (%rdi)
movq 0x8746f(%rip), %rsi     # 0xa7f50
xorl %eax, %eax
movl %eax, %edx
callq 0xab10
jmp 0x21079
testb $0x1, 0x8a96a(%rip)     # 0xab460
jne 0x20b91
leaq -0x90(%rbp), %rdi
movl $0x1, %esi
callq 0x49a40
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x360(%rbp)
jmp 0x20b1f
movq -0x360(%rbp), %rsi
leaq -0x270(%rbp), %rdi
callq 0x65d40
jmp 0x20b34
movl -0x2d4(%rbp), %r9d
movq %rsp, %rax
movl %r9d, (%rax)
leaq -0x270(%rbp), %rdi
movq %rdi, -0x370(%rbp)
xorl %edx, %edx
movl %edx, -0x368(%rbp)
movl %edx, %esi
movl %r9d, %ecx
movl %r9d, %r8d
callq 0x66190
movq -0x370(%rbp), %rdi
movl -0x368(%rbp), %esi
callq 0x661e0
movb %al, -0x361(%rbp)
jmp 0x20b7e
movb -0x361(%rbp), %al
testb $0x1, %al
jne 0x20b8a
jmp 0x20b8f
jmp 0x20774
jmp 0x20b91
testb $0x1, 0x8a8c9(%rip)     # 0xab461
jne 0x20c30
leaq -0x90(%rbp), %rdi
xorl %esi, %esi
callq 0x49a40
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x378(%rbp)
jmp 0x20bbe
movq -0x378(%rbp), %rsi
leaq -0x270(%rbp), %rdi
callq 0x65d40
jmp 0x20bd3
movl -0x2d4(%rbp), %r9d
movq %rsp, %rax
movl %r9d, (%rax)
leaq -0x270(%rbp), %rdi
movq %rdi, -0x388(%rbp)
xorl %edx, %edx
movl %edx, -0x380(%rbp)
movl %edx, %esi
movl %r9d, %ecx
movl %r9d, %r8d
callq 0x66190
movq -0x388(%rbp), %rdi
movl -0x380(%rbp), %esi
callq 0x661e0
movb %al, -0x379(%rbp)
jmp 0x20c1d
movb -0x379(%rbp), %al
testb $0x1, %al
jne 0x20c29
jmp 0x20c2e
jmp 0x20774
jmp 0x20c30
movq -0x78(%rbp), %rdi
xorl %esi, %esi
callq 0x663a0
movb %al, -0x389(%rbp)
jmp 0x20c43
movb -0x389(%rbp), %al
testb $0x1, %al
jne 0x20c4f
jmp 0x20c54
jmp 0x20774
leaq -0x270(%rbp), %rdi
xorl %esi, %esi
callq 0x65d10
testb $0x1, 0x8a7f8(%rip)     # 0xab461
jne 0x20cf6
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x398(%rbp)
jmp 0x20c81
movq -0x398(%rbp), %rsi
leaq -0x270(%rbp), %rdi
callq 0x65d40
jmp 0x20c96
movl -0x2dc(%rbp), %ecx
movl -0x2d4(%rbp), %r9d
movq %rsp, %rax
movl %r9d, (%rax)
leaq -0x270(%rbp), %rdi
movq %rdi, -0x3a8(%rbp)
xorl %edx, %edx
movl %edx, -0x3a0(%rbp)
movl %edx, %esi
movl %r9d, %r8d
callq 0x66190
movq -0x3a8(%rbp), %rdi
movl -0x3a0(%rbp), %esi
callq 0x661e0
movb %al, -0x399(%rbp)
jmp 0x20ce3
movb -0x399(%rbp), %al
testb $0x1, %al
jne 0x20cef
jmp 0x20cf4
jmp 0x20774
jmp 0x20cf6
testb $0x1, 0x8a763(%rip)     # 0xab460
jne 0x20d9b
leaq -0x90(%rbp), %rdi
movl $0x1, %esi
callq 0x49a40
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x3b0(%rbp)
jmp 0x20d26
movq -0x3b0(%rbp), %rsi
leaq -0x270(%rbp), %rdi
callq 0x65d40
jmp 0x20d3b
movl -0x2dc(%rbp), %ecx
movl -0x2d4(%rbp), %r9d
movq %rsp, %rax
movl %r9d, (%rax)
leaq -0x270(%rbp), %rdi
movq %rdi, -0x3c0(%rbp)
xorl %edx, %edx
movl %edx, -0x3b8(%rbp)
movl %edx, %esi
movl %r9d, %r8d
callq 0x66190
movq -0x3c0(%rbp), %rdi
movl -0x3b8(%rbp), %esi
callq 0x661e0
movb %al, -0x3b1(%rbp)
jmp 0x20d88
movb -0x3b1(%rbp), %al
testb $0x1, %al
jne 0x20d94
jmp 0x20d99
jmp 0x20774
jmp 0x20d9b
movq -0x50(%rbp), %rsi
leaq -0x270(%rbp), %rdi
callq 0x70260
jmp 0x20dad
leaq -0x270(%rbp), %rdi
xorl %esi, %esi
callq 0x65d10
testb $0x1, 0x8a69f(%rip)     # 0xab461
jne 0x20e5d
leaq -0x90(%rbp), %rdi
xorl %esi, %esi
callq 0x49a40
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x3c8(%rbp)
jmp 0x20de8
movq -0x3c8(%rbp), %rsi
leaq -0x270(%rbp), %rdi
callq 0x65d40
jmp 0x20dfd
movl -0x2d8(%rbp), %ecx
movl -0x2d4(%rbp), %r9d
movq %rsp, %rax
movl %r9d, (%rax)
leaq -0x270(%rbp), %rdi
movq %rdi, -0x3d8(%rbp)
xorl %edx, %edx
movl %edx, -0x3d0(%rbp)
movl %edx, %esi
movl %r9d, %r8d
callq 0x66190
movq -0x3d8(%rbp), %rdi
movl -0x3d0(%rbp), %esi
callq 0x661e0
movb %al, -0x3c9(%rbp)
jmp 0x20e4a
movb -0x3c9(%rbp), %al
testb $0x1, %al
jne 0x20e56
jmp 0x20e5b
jmp 0x20774
jmp 0x20e5d
testb $0x1, 0x8a5fc(%rip)     # 0xab460
jne 0x20f02
leaq -0x90(%rbp), %rdi
movl $0x1, %esi
callq 0x49a40
movq -0x68(%rbp), %rdi
callq 0x37f00
movq %rax, -0x3e0(%rbp)
jmp 0x20e8d
movq -0x3e0(%rbp), %rsi
leaq -0x270(%rbp), %rdi
callq 0x65d40
jmp 0x20ea2
movl -0x2d8(%rbp), %ecx
movl -0x2d4(%rbp), %r9d
movq %rsp, %rax
movl %r9d, (%rax)
leaq -0x270(%rbp), %rdi
movq %rdi, -0x3f0(%rbp)
xorl %edx, %edx
movl %edx, -0x3e8(%rbp)
movl %edx, %esi
movl %r9d, %r8d
callq 0x66190
movq -0x3f0(%rbp), %rdi
movl -0x3e8(%rbp), %esi
callq 0x661e0
movb %al, -0x3e1(%rbp)
jmp 0x20eef
movb -0x3e1(%rbp), %al
testb $0x1, %al
jne 0x20efb
jmp 0x20f00
jmp 0x20774
jmp 0x20f02
jmp 0x20774
testb $0x1, -0x273(%rbp)
je 0x20f3d
movq -0x78(%rbp), %rdi
movq -0x68(%rbp), %rsi
movb -0x271(%rbp), %cl
notb %cl
movq (%rdi), %rax
movq 0x10(%rax), %rax
movzbl %cl, %ecx
andl $0x1, %ecx
movl $0x1, %edx
callq *%rax
jmp 0x20f36
movb $0x0, -0x273(%rbp)
movb $0x0, -0x271(%rbp)
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x8(%rbp)
movl $0x1, -0xc(%rbp)
movl $0x5, -0x10(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x400(%rbp)
movl -0x10(%rbp), %eax
movl -0xc(%rbp), %ecx
movl %ecx, -0x14(%rbp)
decl %eax
movl %eax, %ecx
movq %rcx, -0x3f8(%rbp)
subl $0x4, %eax
ja 0x20f99
movq -0x3f8(%rbp), %rax
leaq 0x6861c(%rip), %rcx     # 0x895ac
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x400(%rbp), %rcx
movl -0x14(%rbp), %eax
lock
xaddl %eax, (%rcx)
movl %eax, -0x18(%rbp)
jmp 0x20ff6
movq -0x400(%rbp), %rcx
movl -0x14(%rbp), %eax
lock
xaddl %eax, (%rcx)
movl %eax, -0x18(%rbp)
jmp 0x20ff6
movq -0x400(%rbp), %rcx
movl -0x14(%rbp), %eax
lock
xaddl %eax, (%rcx)
movl %eax, -0x18(%rbp)
jmp 0x20ff6
movq -0x400(%rbp), %rcx
movl -0x14(%rbp), %eax
lock
xaddl %eax, (%rcx)
movl %eax, -0x18(%rbp)
jmp 0x20ff6
movq -0x400(%rbp), %rcx
movl -0x14(%rbp), %eax
lock
xaddl %eax, (%rcx)
movl %eax, -0x18(%rbp)
movq -0x60(%rbp), %rdi
movq -0x68(%rbp), %rsi
movq (%rdi), %rax
movq 0x10(%rax), %rax
callq *%rax
jmp 0x21009
movq -0x60(%rbp), %rax
movq %rax, -0x408(%rbp)
cmpq $0x0, %rax
je 0x21027
movq -0x408(%rbp), %rdi
movq (%rdi), %rax
callq *0x28(%rax)
movq -0x70(%rbp), %rdi
movq -0x78(%rbp), %rsi
movq (%rdi), %rax
movq 0x20(%rax), %rax
callq *%rax
jmp 0x2103a
movq -0x70(%rbp), %rax
movq %rax, -0x410(%rbp)
cmpq $0x0, %rax
je 0x21058
movq -0x410(%rbp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
leaq -0x270(%rbp), %rdi
callq 0x669a0
addq $0x460, %rsp            # imm = 0x460
popq %rbp
retq
movq -0x280(%rbp), %rdi
callq 0xab60
nopl (%rax)