// File: /workspace/github_cpp_makefile_star2_O2/chhylp123[P]hifiasm/inter.cpp
// Function: hc_shortest_k(void*, asg_t const*, unsigned int, int, mg_path_dst_t*, int, int, st_mt_t*, unsigned long*, vec_sp_node_t*, vec_mg_pathv_t*, unsigned long, unsigned long, float)
void hc_shortest_k(void *km0, const asg_t *g, uint32_t src, int32_t n_dst, mg_path_dst_t *dst, int32_t max_dist, int32_t max_k, 
st_mt_t *dst_done, uint64_t *dst_group, vec_sp_node_t *out, vec_mg_pathv_t *res, uint64_t first_src_ban, 
uint64_t detect_mul_way, float len_dif)
{
    sp_node_t *p, *root = 0;
    sp_topk_t *q;
    khash_t(sp) *h;///
    khash_t(sp2) *h2;///alignment->vertice index
    void *km;
    khint_t k;
    int absent;
    int32_t i, j, n_done, n_found;
    uint32_t id;

    // if (res) res->n = 0;///for us, n_pathv = NULL
    if (n_dst <= 0) return;///n_dst: how many candidate vertices
    for (i = 0; i < n_dst; ++i) { // initialize
        mg_path_dst_t *t = &dst[i];
        ///if src and dest are at the same ref id, there are already one path
        if (t->inner)///if two chains are at the same ref id
            t->dist = 0, t->n_path = 1, t->path_end = -1;
        else
            t->dist = -1, t->n_path = 0, t->path_end = -1;
    }
    if (max_k > MG_MAX_SHORT_K) max_k = MG_MAX_SHORT_K;
    km = km_init2(km0, 0x4000);

    // multiple dst[] may have the same dst[].v. We need to group them first.
    // in other words, one ref id may have multiple dst alignment chains
	dst_done->n = 0; kv_resize(uint64_t, *dst_done, (uint64_t)n_dst);
    for (i = 0; i < n_dst; ++i) {
		dst_group[i] = ((((uint64_t)dst[i].v)<<32)|((uint64_t)i));
		dst_done->a[i] = 0;
	}
        
    radix_sort_gfa64(dst_group, dst_group + n_dst);

    h2 = kh_init2(sp2, km); // (h2+dst_group) keeps all destinations from the same ref id
    kh_resize(sp2, h2, n_dst * 2);
    ///please note that one contig in ref may have multiple alignment chains
    ///so h2 is a index that helps us to query it
    ///key(h2) = ref id; value(h2) = start_idx | occ
    for (i = 1, j = 0; i <= n_dst; ++i) {
        if (i == n_dst || dst_group[i]>>32 != dst_group[j]>>32) {
            k = kh_put(sp2, h2, dst_group[j]>>32, &absent);
            kh_val(h2, k) = (((uint64_t)j)<<32)|((uint64_t)(i-j));
            assert(absent);
            j = i;
        }
    }

    h = kh_init2(sp, km); // h keeps visited vertices; path to each visited vertice
    kh_resize(sp, h, 16);

	out->n = 0; kv_resize(sp_node_t*, *out, 16); ///16 is just the initial size    
    id = 0;
    p = gen_sp_node(km, src, 0, id++);///just malloc a node for src; the distance is 0
    p->hash = __ac_Wang_hash(src);///hash is path hash, instead of node hash
    kavl_insert(sp, &root, p, 0);///should be avl tree; p is a node at avl-tree

    ///each cell in the hash table <h> corresponds to one node in the graph
	///each cell in the AVL tree <root> is a path, corresponds to <MG_MAX_SHORT_K> node in the graph
    k = kh_put(sp, h, src, &absent);
    q = &kh_val(h, k);
    ///for normal graph traversal, one node just has one parental node; here each node has at most 16 parental nodes
    q->k = 1, q->p[0] = p, q->mlen = 0, q->qs = q->qe = -1;

    n_done = 0; first_src_ban = first_src_ban?0:1;
    ///the key of avl tree: #define sp_node_cmp(a, b) (((a)->di > (b)->di) - ((a)->di < (b)->di))
    ///the higher bits of (*)->di is distance to src node
    ///so the key of avl tree is distance
    ///in avl tree <root>, one node might be saved multipe times
    while (kavl_size(head, root) > 0) {///thr first root is src
        int32_t i, nv;
        asg_arc_t *av;
        sp_node_t *r;
        ///note that one node in the graph (sp_node_t->v) might be visited multiple times if there are circles
        ///so there might be multipe cells in the avl-tree with the same (sp_node_t->v)
        ///delete the first cell
        r = kavl_erase_first(sp, &root); // take out the closest vertex in the heap (as a binary tree)
        //fprintf(stderr, "XX\t%d\t%d\t%d\t%c%s[%d]\t%d\n", n_out, kavl_size(head, root), n_finished, "><"[(r->v&1)^1], g->seg[r->v>>1].name, r->v, (int32_t)(r->di>>32));
        
		///higher 32 bits might be the distance to root node
        // lower 32 bits now for position in the out[] array
		///r->pre keep the pre-node in the path; follow the pre it is able to recover the whole path
        r->di = ((r->di>>32)<<32)|((uint64_t)out->n); ///n_out is just the id in out
        ///so one node id in graph might be saved multiple times in avl tree and out[]
		kv_push(sp_node_t*, *out, r);

        ///r->v is the dst vertex id
        ///sometimes k==kh_end(h2). Some nodes are found by graph travesal but not in linear chain alignment
        k = kh_get(sp2, h2, r->v);
        // we have reached one dst vertex
        // note that one dst vertex may have multipe alignment chains
        // we can visit some nodes in graph which are not reachable during chaining
        // h2 is used to determine if one node is reachable or not
		// if(src == 2844) {
		// 	fprintf(stderr, "******src->%u, dst->%u, max_dist->%d\n", src, r->v, max_dist);
		// }
        if (k != kh_end(h2) && first_src_ban) { 
            ///node r->v might be visited multiple times
            int32_t j, dist = r->di>>32, off = kh_val(h2, k) >> 32, cnt = (int32_t)kh_val(h2, k);
			// if(src == 2844) {
			// 	fprintf(stderr, "----src->%u, dst->%u, max_dist->%d, cnt->%d\n", src, r->v, max_dist, cnt);
			// }
            //src can reach ref id r->v; there might be not only one alignment chain in r->v
            //so we need to scan all of them
            for (j = 0; j < cnt; ++j) {
                mg_path_dst_t *t = &dst[(int32_t)dst_group[off + j]];///t is a linear alignment at r->v
                int32_t done = 0;
				// if((src>>1) == 51) {
				// 	fprintf(stderr, "###src->%u, dst->%u, max_dist->%d, dist:%d\n", src, r->v, max_dist, dist);
				// }
                ///the src and dest are at the same ref id, say we directly find the shortest path
                if (t->inner) {
                    done = 1;
                } else {
                    int32_t mlen = 0, copy = 0;
                    ///in the first round, we just check reachability without sequence
                    ///so h_seeds = NULL; we can assume mlen = 0
                    /** //path
                    mlen = h_seeds? path_mlen(out, n_out - 1, h, t->qlen) : 0;
                    **/
				   // means this alignment has never been visited before; keep it anyway
				   // note here is the alignment, instead of node
					
				    // if(src == 2844) {
					// 	fprintf(stderr, ">>src->%u, dst->%u, target_dist->%d, dist->%d, max_dist->%d\n", 
					// 	src, r->v, t->target_dist, dist, max_dist);
					// }
                    if (t->n_path == 0) { 
                        copy = 1;
                     // we have a target distance; choose the closest; 
                     // there is already several paths reaching the linear alignment <t>
                    } else if (t->target_dist >= 0) { 
                        // we found the target path; hash is the path hash including multiple nodes, instead of node hash 
                        if (dist == t->target_dist && t->check_hash && r->hash == t->target_hash) { 
                            copy = 1, done = 1;
                        } else {
                            int32_t d0 = t->dist, d1 = dist;
                            d0 = d0 > t->target_dist? d0 - t->target_dist : t->target_dist - d0;
                            d1 = d1 > t->target_dist? d1 - t->target_dist : t->target_dist - d1;
                            ///if the new distance (d1) is smaller than the old distance (d0), update the results
                            ///the length of new path should be closer to t->target_dist
                            if (d1 - mlen/2 < d0 - t->mlen/2) copy = 1;
                        }
                    }
                    if (copy) {
                        t->path_end = out->n-1, t->dist = dist, t->hash = r->hash, t->mlen = mlen, t->is_0 = r->is_0;
                        if (t->target_dist >= 0) {
                            ///src is from li from li to lj, so the dis is generally increased; dijkstra algorithm
                            ///target_dist should be the distance on query
                            if (dist == t->target_dist && t->check_hash && r->hash == t->target_hash) {
								done = 1;
							} else if ((dist > t->target_dist + MG_SHORT_K_EXT) && (dist > (t->target_dist>>4)) && 
								(dist > (t->target_dist*1.25))) {
								done = 1;
							}
                        }
                    }
                    ++t->n_path;///we found a path to the alignment t
                    if (t->n_path >= max_k) done = 1;
                }
                if (detect_mul_way == 0 && dst_done->a[off + j] == 0 && done)
                    dst_done->a[off + j] = 1, ++n_done;
            }
            ///if all alignments have been settle down
            ///pre-end; accelerate the loop
            if (n_done == n_dst) break;
        }
		first_src_ban = 1;
        ///below is used to push new nodes to avl tree for iteration
        nv = asg_arc_n(g, r->v);
        av = asg_arc_a(g, r->v);
        for (i = 0; i < nv; ++i) { // visit all neighbors
            asg_arc_t *ai = &av[i];
            ///v_lv is the (dest_length - overlap_length); it is a normal path length in string graph
            ///ai->v_lv is the path length from r->v to ai->w
            ///(r->di>>32)
            int32_t d = (r->di>>32) + (uint32_t)ai->ul;
            if (d > max_dist) continue; // don't probe vertices too far away
            // h keeps visited vertices; path to each visited vertice
            ///ai->w is the dest ref id; we insert a new ref id, instead of an alignment chain
            k = kh_put(sp, h, ai->v, &absent);///one node might be visited multiple times
            q = &kh_val(h, k);
            if (absent) { // a new vertex visited
                ///q->k: number of walks from src to ai->w
                q->k = 0, q->qs = q->qe = -1; q->mlen = 0;
                ///h_seeds = NULL; so q->mlen = 0
                /** //path
                q->mlen = h_seeds && d + gfa_arc_lw(g, *ai) <= max_dist? node_mlen(km, g, ai->w, &mini, h_seeds, n_seeds, seeds, &q->qs, &q->qe) : 0;
                **/
                //if (ql && qs) fprintf(stderr, "ql=%d,src=%d\tv=%c%s[%d],n_seeds=%d,mlen=%d\n", ql, src, "><"[ai->w&1], g->seg[ai->w>>1].name, ai->w, n_seeds, q->mlen);
            }
            ///if there are less than <max_k> walks from src to ai->w, directly add
            ///if there are more, keep the smallest <max_k> walks
            if (q->k < max_k) { // enough room: add to the heap
                p = gen_sp_node(km, ai->v, d, id++);
                p->pre = out->n - 1;///the parent node of this one 
                p->hash = r->hash + __ac_Wang_hash(ai->v);
                p->is_0 = r->is_0;
                /** //path
                if (ai->rank > 0) p->is_0 = 0;
                **/
                kavl_insert(sp, &root, p, 0);
                q->p[q->k++] = p;
                ks_heapup_sp(q->k, q->p);///adjust heap by distance
            } else if ((int32_t)(q->p[0]->di>>32) > d) { // shorter than the longest path so far: replace the longest
                p = kavl_erase(sp, &root, q->p[0], 0);
                if (p) {
                    p->di = (uint64_t)d<<32 | (id++);
                    p->pre = out->n - 1;
                    p->hash = r->hash + __ac_Wang_hash(ai->v);
                    p->is_0 = r->is_0;
                    /** //path
                    if (ai->rank > 0) p->is_0 = 0;
                    **/
                    kavl_insert(sp, &root, p, 0);
                    ks_heapdown_sp(0, q->k, q->p);
                } else {
                    fprintf(stderr, "Warning: logical bug in gfa_shortest_k(): q->k=%d,q->p[0]->{d,i}={%d,%d},d=%d,src=%u,max_dist=%d,n_dst=%d\n", q->k, (int32_t)(q->p[0]->di>>32), (int32_t)q->p[0]->di, d, src, max_dist, n_dst);
                    km_destroy(km);
                    return;
                }
            } // else: the path is longer than all the existing paths ended at ai->w
        }
    }
    kh_destroy(sp, h);
    // NB: AVL nodes are not deallocated. When km==0, they are memory leaks.

    for (i = 0, n_found = 0; i < n_dst; ++i)
        if (dst[i].n_path > 0) ++n_found;///n_path might be larger than 16
    ///we can assume n_pathv = NULL for now 
    if (n_found > 0 && res) { // then generate the backtrack array
        int32_t n, n_mpath = 1; dst_done->n = 0; kv_resize(uint64_t, *dst_done, out->n); 
		uint64_t *trans = dst_done->a; memset(dst_done->a, 0, out->n*sizeof(*(dst_done->a)));

		if(detect_mul_way) {
			n_mpath = phase_mul_ways(res, dst_done, out, n_dst, dst, max_k, len_dif);
		}
		
		if(n_mpath == 1) {
			// KCALLOC(km, trans, n_out); // used to squeeze unused elements in out[]
			///n_out: how many times that nodes in graph have been visited 
			///note one node might be visited multiples times
			///n_dst: number of alignment chains
			for (i = 0; i < n_dst; ++i) { // mark dst vertices with a target distance
				mg_path_dst_t *t = &dst[i];
				if (t->n_path > 0 && t->target_dist >= 0 && t->path_end >= 0)
					trans[(uint32_t)out->a[t->path_end]->di] = 1;///(int32_t)out[]->di: traverse track corresponds to the alignment chain dst[]
			}
			// for (i = 0; (uint32_t)i < out->n; ++i) { // mark dst vertices without a target distance
			//     k = kh_get(sp2, h2, out->a[i]->v);
			//     if (k != kh_end(h2)) { // TODO: check if this is correct!
			//         int32_t off = kh_val(h2, k)>>32, cnt = (int32_t)kh_val(h2, k);
			//         for (j = off; j < off + cnt; ++j)
			//             if (dst[j].target_dist < 0)
			//                 trans[i] = 1;
			//     }
			// }
			for (i = (int32_t)(out->n) - 1; i >= 0; --i) // mark all predecessors
				if (trans[i] && out->a[i]->pre >= 0)
					trans[out->a[i]->pre] = 1;
			for (i = n = 0; (uint32_t)i < out->n; ++i) // generate coordinate translations
				if (trans[i]) trans[i] = n++;
				else trans[i] = (uint32_t)-1;
			
			kv_resize(mg_pathv_t, *res, res->n + n); //res->n += n;
			for (i = 0; (uint32_t)i < out->n; ++i) { // generate the backtrack array
				mg_pathv_t *p;
				if (trans[i] == (uint32_t)-1) continue;
				p = &res->a[trans[i]+res->n];
				p->v = out->a[i]->v, p->d = out->a[i]->di >> 32;
				p->pre = out->a[i]->pre < 0? out->a[i]->pre:trans[out->a[i]->pre];
			}
			res->n += n;
			for (i = 0; i < n_dst; ++i) // translate "path_end"
				if (dst[i].path_end >= 0)
					dst[i].path_end = trans[dst[i].path_end];
		}
    }

    km_destroy(km);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb8, %rsp
movss %xmm0, 0x84(%rsp)
movq %r9, 0xa0(%rsp)
movq %rdx, 0x88(%rsp)
movq %rsi, 0xb0(%rsp)
movq 0x120(%rsp), %r14
movq 0x118(%rsp), %rsi
movq 0x110(%rsp), %rbx
movq 0x108(%rsp), %r9
movq 0x100(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0xf8(%rsp), %rdx
movl 0xf0(%rsp), %eax
andq $0x0, 0x20(%rsp)
testl %ecx, %ecx
jle 0x168b67
movq %r8, %r13
movq %rsi, 0x18(%rsp)
movq %rdx, 0x28(%rsp)
movq %rcx, 0x40(%rsp)
movl %ecx, %r12d
imulq $0x30, %r12, %rcx
xorl %edx, %edx
movl $0x80000000, %esi       # imm = 0x80000000
cmpq %rdx, %rcx
je 0x16836b
cmpl $0x0, 0xc(%r13,%rdx)
js 0x168349
orl $-0x1, 0x1c(%r13,%rdx)
movl 0x14(%r13,%rdx), %r8d
andl %esi, %r8d
jmp 0x16835a
andl $0x0, 0x1c(%r13,%rdx)
movl 0x14(%r13,%rdx), %r8d
andl %esi, %r8d
incl %r8d
movl %r8d, 0x14(%r13,%rdx)
orl $-0x1, 0x18(%r13,%rdx)
addq $0x30, %rdx
jmp 0x16832c
movq %r9, 0x8(%rsp)
cmpl $0xf, %eax
pushq $0xf
popq %rcx
cmovll %eax, %ecx
movl %ecx, 0x14(%rsp)
movl $0x4000, %esi           # imm = 0x4000
callq 0x1a3818
movq 0x28(%rsp), %rdx
andq $0x0, (%rdx)
movq %rax, 0x30(%rsp)
cmpq %r12, 0x8(%rdx)
jae 0x1683f3
leaq -0x1(%r12), %rax
movq %rax, %rcx
shrq %rcx
orq %rax, %rcx
movq %rcx, %rax
shrq $0x2, %rax
orq %rcx, %rax
movq %rax, %rcx
shrq $0x4, %rcx
orq %rax, %rcx
movq %rcx, %rax
shrq $0x8, %rax
orq %rcx, %rax
movq %rax, %rcx
shrq $0x10, %rcx
orq %rax, %rcx
leaq 0x1(%rcx), %rax
movq %rax, 0x8(%rdx)
movq 0x10(%rdx), %rdi
leaq 0x8(,%rcx,8), %rsi
callq 0x2370
movq 0x28(%rsp), %rdx
movq %rax, 0x10(%rdx)
movq 0x10(%rdx), %rax
xorl %ecx, %ecx
movq %r13, %rdx
movq 0x38(%rsp), %rdi
cmpq %rcx, %r12
je 0x168421
movl (%rdx), %esi
shlq $0x20, %rsi
addq %rcx, %rsi
movq %rsi, (%rdi,%rcx,8)
andq $0x0, (%rax,%rcx,8)
incq %rcx
addq $0x30, %rdx
jmp 0x168401
movq %r14, 0x98(%rsp)
movq %rbx, 0xa8(%rsp)
movq %r12, 0x48(%rsp)
movq 0x38(%rsp), %rdi
leaq (%rdi,%r12,8), %rsi
callq 0x156b0d
movq 0x30(%rsp), %rdi
callq 0x15c666
movq %rax, %r15
movq 0x40(%rsp), %rbx
leal (%rbx,%rbx), %esi
movq %rax, %rdi
callq 0x15c67b
incl %ebx
xorl %ebp, %ebp
pushq $0x1
popq %r12
leaq 0x10(%rsp), %r14
movq %r13, 0x50(%rsp)
movq %r15, 0x90(%rsp)
cmpq %r12, %rbx
je 0x168504
cmpq %r12, 0x48(%rsp)
jne 0x168499
movslq %ebp, %r13
movq 0x38(%rsp), %rax
movq (%rax,%r13,8), %rsi
jmp 0x1684b9
movslq %ebp, %r13
movq 0x38(%rsp), %rax
movq (%rax,%r13,8), %rsi
movq (%rax,%r12,8), %rax
xorq %rsi, %rax
shrq $0x20, %rax
jne 0x1684b9
movq 0x50(%rsp), %r13
jmp 0x1684fc
shrq $0x20, %rsi
movq %r15, %rdi
movq %r14, %rdx
callq 0x15c8ff
shlq $0x20, %r13
movl %r12d, %ecx
subl %ebp, %ecx
movslq %ecx, %rcx
orq %r13, %rcx
movq 0x20(%r15), %rdx
movl %eax, %eax
movq %rcx, (%rdx,%rax,8)
cmpl $0x0, 0x10(%rsp)
je 0x168d14
movl %r12d, %ebp
movq 0x50(%rsp), %r13
movq 0x90(%rsp), %r15
incq %r12
jmp 0x16847b
movq 0x30(%rsp), %rdi
callq 0x15ca61
pushq $0x10
popq %rsi
movq %rax, 0x68(%rsp)
movq %rax, %rdi
callq 0x15ca76
movq 0x8(%rsp), %rax
andq $0x0, 0x8(%rax)
cmpq $0xf, 0x10(%rax)
ja 0x16854c
movq $0x10, 0x10(%rax)
movq (%rax), %rdi
movl $0x80, %esi
callq 0x2370
movq 0x8(%rsp), %rcx
movq %rax, (%rcx)
movq $0x0, 0x58(%rsp)
movq 0x30(%rsp), %rdi
movq 0x88(%rsp), %r14
movl %r14d, %esi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x15cda2
movq %rax, %rbx
movl %r14d, %edi
callq 0x15cdd5
movl %eax, 0x10(%rbx)
leaq 0x20(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x159bf9
leaq 0x10(%rsp), %rdx
movq 0x68(%rsp), %r15
movq %r15, %rdi
movl %r14d, %esi
callq 0x15ce00
movq 0x20(%r15), %rcx
movl %eax, %eax
imulq $0x88, %rax, %rax
movq %rbx, 0x10(%rcx,%rax)
movapd 0x84b56(%rip), %xmm0    # 0x1ed110
movupd %xmm0, (%rcx,%rax)
cmpq $0x0, 0x18(%rsp)
sete %bpl
pushq $0x1
popq %rax
movq %rax, 0x18(%rsp)
movq 0x20(%rsp), %rax
testq %rax, %rax
je 0x168a15
cmpl $0x0, 0x2c(%rax)
je 0x168a15
leaq 0x20(%rsp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x159e78
movq %rax, %r12
movl 0x4(%rax), %eax
shlq $0x20, %rax
movq 0x8(%rsp), %rdi
movq 0x8(%rdi), %rcx
orq %rcx, %rax
movq %rax, (%r12)
movq (%rdi), %rax
cmpq 0x10(%rdi), %rcx
jne 0x168644
leaq (%rcx,%rcx), %rsi
testq %rcx, %rcx
pushq $0x2
popq %rcx
cmoveq %rcx, %rsi
movq %rsi, 0x10(%rdi)
shlq $0x3, %rsi
movq %rax, %rdi
callq 0x2370
movq 0x8(%rsp), %rdi
movq %rax, (%rdi)
movq 0x8(%rdi), %rcx
leaq 0x1(%rcx), %rdx
movq %rdx, 0x8(%rdi)
movq %r12, (%rax,%rcx,8)
movl 0x8(%r12), %ebx
movq 0x90(%rsp), %r14
movq %r14, %rdi
movl %ebx, %esi
callq 0x15cf62
cmpl (%r14), %eax
sete %cl
notb %bpl
orb %cl, %bpl
testb $0x1, %bpl
jne 0x16882d
movl 0x4(%r12), %ecx
movq 0x20(%r14), %rdx
movl %eax, %eax
movq (%rdx,%rax,8), %rax
cvtsi2sd %ecx, %xmm0
movq %rax, %rsi
sarq $0x20, %rsi
testl %eax, %eax
movl $0x0, %edi
cmovgl %eax, %edi
subq $0x1, %rdi
jb 0x168819
movq 0x38(%rsp), %rax
movslq (%rax,%rsi,8), %rax
imulq $0x30, %rax, %r8
movl 0xc(%r13,%r8), %r10d
testl %r10d, %r10d
js 0x168735
addq %r13, %r8
movl 0x4(%r8), %ebp
movl 0x14(%r8), %r9d
movl %r9d, %r11d
andl $0x7fffffff, %r11d      # imm = 0x7FFFFFFF
je 0x16873c
testl %ebp, %ebp
js 0x1687b6
cmpl $0x40000000, %r10d      # imm = 0x40000000
jb 0x1686fe
cmpl %ecx, %ebp
jne 0x1686fe
movl 0x10(%r12), %eax
movl %ecx, %ebx
pushq $0x1
popq %rdx
cmpl 0x8(%r8), %eax
je 0x168740
movl 0x1c(%r8), %edx
movl 0x20(%r8), %eax
subl %ebp, %edx
movl %edx, %ebx
negl %ebx
cmovsl %edx, %ebx
movl %ebp, %edx
subl %ecx, %edx
movl %edx, %r14d
negl %r14d
cmovsl %edx, %r14d
cltd
pushq $-0x2
popq %r15
idivl %r15d
addl %ebx, %eax
xorl %edx, %edx
movl %ebp, %ebx
cmpl %eax, %r14d
jl 0x168740
jmp 0x1687b8
movb $0x1, %dl
jmp 0x1687d8
xorl %edx, %edx
movl %ebp, %ebx
movq 0x8(%rsp), %rax
movl 0x8(%rax), %eax
decl %eax
movl %eax, 0x18(%r8)
movl %ecx, 0x1c(%r8)
movl 0x10(%r12), %eax
movl %eax, 0x24(%r8)
andl $0x0, 0x20(%r8)
movl 0x14(%r12), %r9d
shll $0x1f, %r9d
orl %r11d, %r9d
movl %r9d, 0x14(%r8)
testl %ebx, %ebx
js 0x1687b8
cmpl $0x40000000, %r10d      # imm = 0x40000000
jb 0x16878c
cmpl %ecx, %ebx
jne 0x16878c
movl 0x10(%r12), %eax
cmpl 0x8(%r8), %eax
je 0x1687b1
leal 0x2710(%rbx), %eax
cmpl %ecx, %eax
jge 0x1687b8
movl %ebx, %eax
shrl $0x4, %eax
cmpl %ecx, %eax
jge 0x1687b8
cvtsi2sd %ebx, %xmm1
mulsd 0x7f4b5(%rip), %xmm1    # 0x1e7c60
ucomisd %xmm1, %xmm0
jbe 0x1687b8
pushq $0x1
popq %rdx
jmp 0x1687b8
xorl %edx, %edx
leal 0x1(%r9), %eax
andl $0x7fffffff, %eax       # imm = 0x7FFFFFFF
andl $0x80000000, %r9d       # imm = 0x80000000
orl %eax, %r9d
movl %r9d, 0x14(%r8)
cmpl 0x14(%rsp), %eax
setge %al
orb %al, %dl
cmpq $0x0, 0x98(%rsp)
jne 0x168811
movq 0x28(%rsp), %rax
movq 0x10(%rax), %rax
cmpq $0x0, (%rax,%rsi,8)
setne %r8b
xorb $0x1, %dl
orb %r8b, %dl
jne 0x168811
movq $0x1, (%rax,%rsi,8)
movq 0x58(%rsp), %rax
incl %eax
movq %rax, 0x58(%rsp)
incq %rsi
jmp 0x1686a1
movq 0x58(%rsp), %rax
cmpl 0x40(%rsp), %eax
je 0x168a15
movl 0x8(%r12), %ebx
movq 0xb0(%rsp), %rcx
movq 0x8(%rcx), %rax
movq 0x28(%rcx), %rcx
movl %ebx, %edx
movq (%rcx,%rdx,8), %rcx
movq %rcx, %rdx
shrq $0x20, %rdx
testl %ecx, %ecx
movl $0x0, %esi
cmovgl %ecx, %esi
imulq $0x18, %rsi, %rsi
imulq $0x18, %rdx, %rcx
leaq (%rax,%rcx), %r13
addq $0x8, %r13
xorl %ebp, %ebp
movq %r12, 0x78(%rsp)
movq %rsi, 0x70(%rsp)
cmpq %rbp, %rsi
je 0x168a08
movl 0x4(%r12), %r14d
addq -0x8(%r13,%rbp), %r14
cmpl 0xa0(%rsp), %r14d
jg 0x1689ff
movl (%r13,%rbp), %esi
movq 0x68(%rsp), %rbx
movq %rbx, %rdi
leaq 0x10(%rsp), %rdx
callq 0x15ce00
movl %eax, %eax
imulq $0x88, %rax, %r15
addq 0x20(%rbx), %r15
cmpl $0x0, 0x10(%rsp)
je 0x1688cd
movapd 0x890cc(%rip), %xmm0    # 0x1f1990
movupd %xmm0, (%r15)
xorl %eax, %eax
jmp 0x1688d0
movl (%r15), %eax
cmpl 0x14(%rsp), %eax
jge 0x16895f
movl (%r13,%rbp), %esi
movq 0x18(%rsp), %rcx
leal 0x1(%rcx), %eax
movl %eax, 0x60(%rsp)
movq 0x30(%rsp), %rdi
movl %r14d, %edx
callq 0x15cda2
movq %rax, %rbx
movq 0x8(%rsp), %rax
movl 0x8(%rax), %eax
decl %eax
movl %eax, 0xc(%rbx)
movq 0x78(%rsp), %r12
movl 0x10(%r12), %r14d
movl (%r13,%rbp), %edi
callq 0x15cdd5
addl %r14d, %eax
movl %eax, 0x10(%rbx)
movl 0x14(%r12), %eax
movl %eax, 0x14(%rbx)
leaq 0x20(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x159bf9
leaq 0x10(%r15), %rsi
movslq (%r15), %rax
leaq 0x1(%rax), %rdi
movl %edi, (%r15)
movq %rbx, 0x10(%r15,%rax,8)
callq 0x15a2cc
movl 0x60(%rsp), %eax
movq %rax, 0x18(%rsp)
jmp 0x1689fa
movq 0x10(%r15), %rsi
cmpl %r14d, 0x4(%rsi)
jle 0x1689f5
leaq 0x20(%rsp), %rdi
xorl %edx, %edx
callq 0x159e78
testq %rax, %rax
je 0x168cb3
movq %rax, %rbx
leaq 0x10(%r15), %rax
movq %rax, 0x60(%rsp)
shlq $0x20, %r14
movq 0x18(%rsp), %rcx
movl %ecx, %eax
incl %ecx
movq %rcx, 0x18(%rsp)
orq %r14, %rax
movq %rax, (%rbx)
movq 0x8(%rsp), %rax
movl 0x8(%rax), %eax
decl %eax
movl %eax, 0xc(%rbx)
movq 0x78(%rsp), %r12
movl 0x10(%r12), %r14d
movl (%r13,%rbp), %edi
callq 0x15cdd5
addl %r14d, %eax
movl %eax, 0x10(%rbx)
movl 0x14(%r12), %eax
movl %eax, 0x14(%rbx)
leaq 0x20(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x159bf9
movslq (%r15), %rsi
xorl %edi, %edi
movq 0x60(%rsp), %rdx
callq 0x15a27c
jmp 0x1689fa
movq 0x78(%rsp), %r12
movq 0x70(%rsp), %rsi
addq $0x18, %rbp
jmp 0x168870
movb $0x1, %bpl
movq 0x50(%rsp), %r13
jmp 0x1685d1
movq 0x68(%rsp), %rdi
callq 0x15cfd3
movq 0x48(%rsp), %rbp
imulq $0x30, %rbp, %rbx
xorl %ecx, %ecx
movl $0x7fffffff, %edx       # imm = 0x7FFFFFFF
xorl %eax, %eax
movq 0xa8(%rsp), %r12
movq 0x8(%rsp), %r8
cmpq %rcx, %rbx
je 0x168a56
movl 0x14(%r13,%rcx), %esi
andl %edx, %esi
cmpl $0x1, %esi
sbbl $-0x1, %eax
addq $0x30, %rcx
jmp 0x168a3e
testq %r12, %r12
je 0x168cf9
testl %eax, %eax
je 0x168cf9
movq 0x28(%rsp), %rsi
andq $0x0, (%rsi)
movq 0x8(%r8), %rdx
movq 0x10(%rsi), %r15
cmpq %rdx, 0x8(%rsi)
jae 0x168ae0
decq %rdx
movq %rdx, %rax
shrq %rax
orq %rdx, %rax
movq %rax, %rcx
shrq $0x2, %rcx
orq %rax, %rcx
movq %rcx, %rax
shrq $0x4, %rax
orq %rcx, %rax
movq %rax, %rcx
shrq $0x8, %rcx
orq %rax, %rcx
movq %rcx, %rax
shrq $0x10, %rax
orq %rcx, %rax
leaq 0x1(%rax), %rcx
movq %rcx, 0x8(%rsi)
movq %rsi, %rbp
leaq 0x8(,%rax,8), %rsi
movq %r15, %rdi
movq %r8, %r14
callq 0x2370
movq %rax, %r15
movq %rax, 0x10(%rbp)
movq 0x48(%rsp), %rbp
movq 0x8(%r14), %rdx
shlq $0x3, %rdx
movq %r15, %rdi
xorl %esi, %esi
callq 0x20e0
cmpq $0x0, 0x98(%rsp)
movq 0x8(%rsp), %rdx
je 0x168b2c
movq %r12, %rdi
movq 0x28(%rsp), %rsi
movl %ebp, %ecx
movq %r13, %r8
movl 0x14(%rsp), %r9d
movss 0x84(%rsp), %xmm0
callq 0x1845fc
movq 0x8(%rsp), %rdx
cmpl $0x1, %eax
jne 0x168cf9
xorl %eax, %eax
cmpq %rax, %rbx
je 0x168b79
testl $0x7fffffff, 0x14(%r13,%rax) # imm = 0x7FFFFFFF
je 0x168b61
cmpl $0x0, 0x4(%r13,%rax)
js 0x168b61
movslq 0x18(%r13,%rax), %rcx
testq %rcx, %rcx
js 0x168b61
movq (%rdx), %rsi
movq (%rsi,%rcx,8), %rcx
movl (%rcx), %ecx
movq $0x1, (%r15,%rcx,8)
addq $0x30, %rax
jmp 0x168b2e
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl 0x8(%rdx), %eax
testl %eax, %eax
jle 0x168ba6
cmpq $0x0, -0x8(%r15,%rax,8)
je 0x168ba1
movq (%rdx), %rcx
movq -0x8(%rcx,%rax,8), %rcx
movslq 0xc(%rcx), %rcx
testq %rcx, %rcx
js 0x168ba1
movq $0x1, (%r15,%rcx,8)
decq %rax
jmp 0x168b7c
xorl %ecx, %ecx
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
xorl %esi, %esi
movq 0x8(%rdx), %rax
movl %esi, %r14d
cmpq %rcx, %rax
jbe 0x168bd4
xorl %eax, %eax
cmpq $0x0, (%r15,%rcx,8)
cmoveq %rdi, %r14
setne %al
addl %eax, %esi
movq %r14, (%r15,%rcx,8)
incq %rcx
jmp 0x168baf
movq 0x8(%r12), %rcx
addq %r14, %rcx
cmpq %rcx, 0x10(%r12)
jae 0x168c39
decq %rcx
movq %rcx, %rax
shrq %rax
orq %rcx, %rax
movq %rax, %rcx
shrq $0x2, %rcx
orq %rax, %rcx
movq %rcx, %rax
shrq $0x4, %rax
orq %rcx, %rax
movq %rax, %rcx
shrq $0x8, %rcx
orq %rax, %rcx
movq %rcx, %rax
shrq $0x10, %rax
orq %rcx, %rax
incq %rax
movq %rax, 0x10(%r12)
movq (%r12), %rdi
imulq $0xc, %rax, %rsi
callq 0x2370
movq 0x8(%rsp), %rdx
movq %rax, (%r12)
movq 0x8(%rdx), %rax
xorl %ecx, %ecx
movl $0xffffffff, %r10d      # imm = 0xFFFFFFFF
cmpq %rcx, %rax
je 0x168c8e
movq (%r15,%rcx,8), %rsi
cmpq %r10, %rsi
je 0x168c89
imulq $0xc, %rsi, %rsi
addq (%r12), %rsi
imulq $0xc, 0x8(%r12), %rdi
movq (%rdx), %r8
movq (%r8,%rcx,8), %r8
movl 0x8(%r8), %r9d
movl %r9d, (%rdi,%rsi)
movl 0x4(%r8), %r9d
movl %r9d, 0x4(%rdi,%rsi)
movslq 0xc(%r8), %r8
testq %r8, %r8
js 0x168c82
movl (%r15,%r8,8), %r8d
addq %rdi, %rsi
movl %r8d, 0x8(%rsi)
incq %rcx
jmp 0x168c41
addq %r14, 0x8(%r12)
xorl %eax, %eax
cmpq %rax, %rbx
je 0x168cf9
movslq 0x18(%r13,%rax), %rcx
testq %rcx, %rcx
js 0x168cad
movl (%r15,%rcx,8), %ecx
movl %ecx, 0x18(%r13,%rax)
addq $0x30, %rax
jmp 0x168c95
movq 0xea326(%rip), %rax     # 0x252fe0
movq (%rax), %rdi
movl (%r15), %edx
movq 0x10(%r15), %rax
movq (%rax), %r8
movq %r8, %rcx
shrq $0x20, %rcx
subq $0x8, %rsp
leaq 0x88fba(%rip), %rsi     # 0x1f1c93
movl %r14d, %r9d
xorl %eax, %eax
pushq 0x48(%rsp)
pushq 0xb0(%rsp)
pushq 0xa0(%rsp)
callq 0x22b0
addq $0x20, %rsp
movq 0x30(%rsp), %rdi
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1a3894
leaq 0x88eff(%rip), %rdi     # 0x1f1c1a
leaq 0x88e01(%rip), %rsi     # 0x1f1b23
leaq 0x8b5cd(%rip), %rcx     # 0x1f42f6
movl $0x3702, %edx           # imm = 0x3702
callq 0x2110