// File: /workspace/github_cpp_makefile_star2_O1/FreeSlave[P]vhlt/hlbsp/brink.cpp
// Function: SplitTreeLeaf(int&, btreeleaf_s*, plane_t const*, int, double, btreeleaf_s*&, btreeleaf_s*&, bclipnode_s*, bclipnode_s*)
void SplitTreeLeaf (int &numobjects, btreeleaf_t *tl, const dplane_t *plane, int planenum, vec_t epsilon, btreeleaf_t *&front, btreeleaf_t *&back, bclipnode_t *c0, bclipnode_t *c1)
{
	btreeface_l::iterator fi;
	btreeedge_l::iterator ei;
	bool restart = false;

	// clear all the flags
	for (fi = tl->faces->begin (); fi != tl->faces->end (); fi++)
	{
		btreeface_t *tf = fi->f;
		tf->tmp_tested = false;
		for (ei = tf->edges->begin (); ei != tf->edges->end (); ei++)
		{
			btreeedge_t *te = ei->e;
			te->tmp_tested = false;
			for (int side = 0; side < 2; side++)
			{
				btreepoint_t *tp = GetPointFromEdge (te, side);
				tp->tmp_tested = false;
			}
		}
	}

	// split each point
	for (fi = tl->faces->begin (); fi != tl->faces->end (); fi++)
	{
		btreeface_t *tf = fi->f;
		for (ei = tf->edges->begin (); ei != tf->edges->end (); ei++)
		{
			btreeedge_t *te = ei->e;
			for (int side = 0; side < 2; side++)
			{
				btreepoint_t *tp = GetPointFromEdge (te, side);
				if (tp->tmp_tested)
				{
					continue;
				}
				tp->tmp_tested = true;
				vec_t dist = DotProduct (tp->v, plane->normal) - plane->dist;
				tp->tmp_dist = dist;
				if (dist > epsilon)
				{
					tp->tmp_side = SIDE_FRONT;
				}
				else if (dist < -epsilon)
				{
					tp->tmp_side = SIDE_BACK;
				}
				else
				{
					tp->tmp_side = SIDE_ON;
				}
#ifdef HLBSP_BRINKHACK_BUGFIX
#if 0
				// let's mess up something and see whether the code is fragile or robust
				static int randcounter = 0;
				if (randcounter++ % 8 == 0) tp->tmp_side = randcounter % 3;
#endif
#endif
			}
		}
	}

	// split each edge
	for (fi = tl->faces->begin (); fi != tl->faces->end (); fi++)
	{
		btreeface_t *tf = fi->f;
		for (ei = tf->edges->begin (); ei != tf->edges->end (); restart? restart = false, ei = tf->edges->begin (): ei++)
		{
			btreeedge_t *te = ei->e;
			if (te->tmp_tested) // splitted
			{
				continue;
			}
			te->tmp_tested = true;
			te->tmp_side = SIDE_ON;
			for (int side = 0; side < 2; side++)
			{
				btreepoint_t *tp = GetPointFromEdge (te, side);
				if (te->tmp_side == SIDE_ON)
				{
					te->tmp_side = tp->tmp_side;
				}
				else if (tp->tmp_side != SIDE_ON && tp->tmp_side != te->tmp_side)
				{
					te->tmp_side = SIDE_CROSS;
				}
			}
#ifdef HLBSP_BRINKNOTUSEDBYLEAF_FIX
			// The plane does not necessarily split the leaf into two, because of epsilon problem etc., and this will cause "Error: CollectBrinks_r: not leaf" on some maps.
			// In addition, by the time of this step (split edges), the plane has not splitted the leaf yet, so splitting the brink leafs now will break the integrety of the entire geometry. (We want the four steps to be as independent on each other as possible, that is, the entire geometry remains valid after each step.)
#else
			if (!te->infinite)
			{
				if (te->tmp_side == SIDE_ON)
				{
					// since the plane splits the leaf into two, it must also split the brink into two
					BrinkSplitClipnode (te->brink, plane, planenum, tl->clipnode, c0, c1);
				}
				else if (te->tmp_side == SIDE_FRONT)
				{
					BrinkReplaceClipnode (te->brink, tl->clipnode, c0);
				}
				else if (te->tmp_side == SIDE_BACK)
				{
					BrinkReplaceClipnode (te->brink, tl->clipnode, c1);
				}
			}
#endif
			if (te->tmp_side == SIDE_CROSS)
			{
				btreepoint_t *tp0 = GetPointFromEdge (te, false);
				btreepoint_t *tp1 = GetPointFromEdge (te, true);
				btreepoint_t *tpmid = AllocTreepoint (numobjects, te->infinite);
				tpmid->tmp_tested = true;
				tpmid->tmp_dist = 0;
				tpmid->tmp_side = SIDE_ON;
				vec_t frac = tp0->tmp_dist / (tp0->tmp_dist - tp1->tmp_dist);
				for (int k = 0; k < 3; k++)
				{
					tpmid->v[k] = tp0->v[k] + frac * (tp1->v[k] - tp0->v[k]);
				}
				btreeedge_t *te0 = AllocTreeedge (numobjects, te->infinite);
				SetEdgePoints (te0, tp0, tpmid);
				te0->tmp_tested = true;
				te0->tmp_side = tp0->tmp_side;
				if (!te0->infinite)
				{
					te0->brink = CopyBrink (te->brink);
					VectorCopy (tpmid->v, te0->brink->start);
					VectorCopy (tp0->v, te0->brink->stop);
#ifndef HLBSP_BRINKNOTUSEDBYLEAF_FIX
					BrinkReplaceClipnode (te0->brink, tl->clipnode, (tp0->tmp_side == SIDE_BACK? c1: c0));
#endif
				}
				btreeedge_t *te1 = AllocTreeedge (numobjects, te->infinite);
				SetEdgePoints (te1, tpmid, tp1);
				te1->tmp_tested = true;
				te1->tmp_side = tp1->tmp_side;
				if (!te1->infinite)
				{
					te1->brink = CopyBrink (te->brink);
					VectorCopy (tp1->v, te1->brink->start);
					VectorCopy (tpmid->v, te1->brink->stop);
#ifndef HLBSP_BRINKNOTUSEDBYLEAF_FIX
					BrinkReplaceClipnode (te1->brink, tl->clipnode, (tp1->tmp_side == SIDE_BACK? c1: c0));
#endif
				}
				btreeface_l::iterator fj;
				while ((fj = te->faces->begin ()) != te->faces->end ())
				{
					AttachEdgeToFace (fj->f, te0, fj->side);
					AttachEdgeToFace (fj->f, te1, fj->side);
					RemoveEdgeFromFace (fj->f, te, fj->side);
				}
				DeleteEdge (numobjects, te);
				restart = true;
			}
		}
	}

	// split each face
	for (fi = tl->faces->begin (); fi != tl->faces->end (); restart? restart = false, fi = tl->faces->begin (): fi++)
	{
		btreeface_t *tf = fi->f;
		if (tf->tmp_tested)
		{
			continue;
		}
		tf->tmp_tested = true;
		tf->tmp_side = SIDE_ON;
		for (ei = tf->edges->begin (); ei != tf->edges->end (); ei++)
		{
			if (tf->tmp_side == SIDE_ON)
			{
				tf->tmp_side = ei->e->tmp_side;
			}
			else if (ei->e->tmp_side != SIDE_ON && ei->e->tmp_side != tf->tmp_side)
			{
				tf->tmp_side = SIDE_CROSS;
			}
		}
		if (tf->tmp_side == SIDE_CROSS)
		{
			btreeface_t *frontface, *backface;
			frontface = AllocTreeface (numobjects, tf->infinite);
			if (!tf->infinite)
			{
				frontface->plane = tf->plane;
				frontface->planenum = tf->planenum;
				frontface->planeside = tf->planeside;
			}
			SetFaceLeafs (frontface, GetLeafFromFace (tf, false), GetLeafFromFace (tf, true));
			frontface->tmp_tested = true;
			frontface->tmp_side = SIDE_FRONT;
			backface = AllocTreeface (numobjects, tf->infinite);
			if (!tf->infinite)
			{
				backface->plane = tf->plane;
				backface->planenum = tf->planenum;
				backface->planeside = tf->planeside;
			}
			SetFaceLeafs (backface, GetLeafFromFace (tf, false), GetLeafFromFace (tf, true));
			backface->tmp_tested = true;
			backface->tmp_side = SIDE_BACK;

			std::map< btreepoint_t *, int > vertexes;
			std::map< btreepoint_t *, int >::iterator vertex, vertex2;
			for (ei = tf->edges->begin (); ei != tf->edges->end (); ei++)
			{
				if (ei->e->tmp_side != SIDE_BACK)
				{
					AttachEdgeToFace (frontface, ei->e, ei->side);
				}
				else
				{
					AttachEdgeToFace (backface, ei->e, ei->side);

					btreeedge_t *e = ei->e;
					for (int side = 0; side < 2; side++)
					{
						btreepoint_t *p = GetPointFromEdge (e, side);
						vertexes[p] += ((bool)side == ei->side? 1: -1); // the default value is 0 if vertexes[p] does not exist
						vertex = vertexes.find (p);
						if (vertex->second == 0)
						{
							vertexes.erase (vertex);
						}
					}
				}
			}
			if (vertexes.size () != 2)
			{
				Developer (DEVELOPER_LEVEL_WARNING, "SplitTreeLeaf: got invalid edge from split\n");
			}

			while (1)
			{
				for (vertex = vertexes.begin (); vertex != vertexes.end (); vertex++)
				{
					if (vertex->second > 0)
					{
						break;
					}
				}
				for (vertex2 = vertexes.begin (); vertex2 != vertexes.end (); vertex2++)
				{
					if (vertex2->second < 0)
					{
						break;
					}
				}
				if (vertex == vertexes.end () && vertex2 == vertexes.end ())
				{
					break;
				}
				if (vertex == vertexes.end () || vertex2 == vertexes.end ())
				{
					PrintOnce ("SplitTreeLeaf: internal error: couldn't link edges");
					hlassume (false, assume_first);
				}
				if (vertex->second != 1 || vertex2->second != -1)
				{
					Developer (DEVELOPER_LEVEL_WARNING, "SplitTreeLeaf: got deformed edge from split\n");
				}
				if (vertex->first->tmp_side != SIDE_ON || vertex2->first->tmp_side != SIDE_ON)
				{
					PrintOnce ("SplitTreeLeaf: internal error: tmp_side != SIDE_ON");
					hlassume (false, assume_first);
				}

				btreeedge_t *te;
				te = AllocTreeedge (numobjects, tf->infinite);
				SetEdgePoints (te, vertex->first, vertex2->first);
				if (!te->infinite)
				{
					te->brink = CreateBrink (vertex2->first->v, vertex->first->v);
					if (GetLeafFromFace (tf, tf->planeside)->infinite || GetLeafFromFace (tf, !tf->planeside)->infinite)
					{
						PrintOnce ("SplitTreeLeaf: internal error: an infinite object contains a finite object");
						hlassume (false, assume_first);
					}
					BrinkSplitClipnode (te->brink, tf->plane, tf->planenum, NULL, GetLeafFromFace (tf, tf->planeside)->clipnode, GetLeafFromFace (tf, !tf->planeside)->clipnode);
#ifndef HLBSP_BRINKNOTUSEDBYLEAF_FIX
					BrinkSplitClipnode (te->brink, plane, planenum, tl->clipnode, c0, c1);
#endif
				}
				te->tmp_tested = true;
				te->tmp_side = SIDE_ON;
				AttachEdgeToFace (frontface, te, false);
				AttachEdgeToFace (backface, te, true);

				vertex->second--;
				vertex2->second++;
			}

			for (int side = 0; side < 2; side++)
			{
				RemoveFaceFromLeaf (GetLeafFromFace (tf, side), tf, side);
			}
			DeleteFace (numobjects, tf);
			restart = true;
		}
	}

	// split the leaf
	{
		if (tl->infinite)
		{
			PrintOnce ("SplitTreeLeaf: internal error: splitting the infinite leaf");
			hlassume (false, assume_first);
		}
		front = AllocTreeleaf (numobjects, tl->infinite);
		back = AllocTreeleaf (numobjects, tl->infinite);
		front->clipnode = c0;
		back->clipnode = c1;

		int tmp_side = SIDE_ON;
		for (fi = tl->faces->begin (); fi != tl->faces->end (); fi++)
		{
			if (tmp_side == SIDE_ON)
			{
				tmp_side = fi->f->tmp_side;
			}
			else if (fi->f->tmp_side != SIDE_ON && fi->f->tmp_side != tmp_side)
			{
				tmp_side = SIDE_CROSS;
			}
		}
		
		std::map< btreeedge_t *, int > edges;
		std::map< btreeedge_t *, int >::iterator edge;

		while ((fi = tl->faces->begin ()) != tl->faces->end ())
		{
			btreeface_t *tf = fi->f;
			int side = fi->side;
			RemoveFaceFromLeaf (tl, tf, side); // because we can only store 2 leafs for a face
			
			// fi is unusable now
			if (tf->tmp_side == SIDE_FRONT || tf->tmp_side == SIDE_ON && tmp_side != SIDE_BACK)
			{
				AttachFaceToLeaf (front, tf, side);
			}
			else if (tf->tmp_side == SIDE_BACK || tf->tmp_side == SIDE_ON && tmp_side == SIDE_BACK)
			{
				AttachFaceToLeaf (back, tf, side);

				if (tmp_side == SIDE_CROSS)
				{
					for (ei = tf->edges->begin (); ei != tf->edges->end (); ei++)
					{
						edges[ei->e] += (ei->side == (bool)side? 1: -1);
						edge = edges.find (ei->e);
						if (edge->second == 0)
						{
							edges.erase (edge);
						}
					}
				}
			}
		}

		if (tmp_side == SIDE_CROSS)
		{
			btreeface_t *tf;
			tf = AllocTreeface (numobjects, tl->infinite);
			if (!tf->infinite)
			{
				tf->plane = plane;
				tf->planenum = planenum;
				tf->planeside = false;
			}
			tf->tmp_tested = true;
			tf->tmp_side = SIDE_ON;
			SetFaceLeafs (tf, front, back);
			for (edge = edges.begin (); edge != edges.end (); edge++)
			{
				if (edge->first->tmp_side != SIDE_ON)
				{
					PrintOnce ("SplitTreeLeaf: internal error");
					hlassume (false, assume_first);
				}
				while (edge->second > 0)
				{
					AttachEdgeToFace (tf, edge->first, false);
					edge->second--;
				}
				while (edge->second < 0)
				{
					AttachEdgeToFace (tf, edge->first, true);
					edge->second++;
				}
			}
		}

#ifndef HLBSP_BRINKHACK_BUGFIX
		DeleteLeaf (numobjects, tl);
#endif
#ifdef HLBSP_BRINKNOTUSEDBYLEAF_FIX
		btreeleaf_t *(frontback[2]) = {front, back};
		for (int side = 0; side < 2; side++)
		{
			for (fi = frontback[side]->faces->begin (); fi != frontback[side]->faces->end (); fi++)
			{
				for (ei = fi->f->edges->begin (); ei != fi->f->edges->end (); ei++)
				{
					ei->e->tmp_onleaf[0] = ei->e->tmp_onleaf[1] = false;
					ei->e->tmp_tested = false;
				}
			}
		}
		for (int side = 0; side < 2; side++)
		{
			for (fi = frontback[side]->faces->begin (); fi != frontback[side]->faces->end (); fi++)
			{
				for (ei = fi->f->edges->begin (); ei != fi->f->edges->end (); ei++)
				{
					ei->e->tmp_onleaf[side] = true;
				}
			}
		}
		for (int side = 0; side < 2; side++)
		{
			for (fi = frontback[side]->faces->begin (); fi != frontback[side]->faces->end (); fi++)
			{
				for (ei = fi->f->edges->begin (); ei != fi->f->edges->end (); ei++)
				{
					if (ei->e->tmp_tested)
					{
						continue;
					}
					ei->e->tmp_tested = true;
					if (!ei->e->infinite)
					{
						if (ei->e->tmp_onleaf[0] && ei->e->tmp_onleaf[1])
						{
							if (ei->e->tmp_side != SIDE_ON)
							{
								PrintOnce ("SplitTreeLeaf: internal error");
								hlassume (false, assume_first);
							}
							BrinkSplitClipnode (ei->e->brink, plane, planenum, tl->clipnode, c0, c1);
						}
						else if (ei->e->tmp_onleaf[0])
						{
							if (ei->e->tmp_side == SIDE_BACK)
							{
								PrintOnce ("SplitTreeLeaf: internal error");
								hlassume (false, assume_first);
							}
							BrinkReplaceClipnode (ei->e->brink, tl->clipnode, c0);
						}
						else if (ei->e->tmp_onleaf[1])
						{
							if (ei->e->tmp_side == SIDE_FRONT)
							{
								PrintOnce ("SplitTreeLeaf: internal error");
								hlassume (false, assume_first);
							}
							BrinkReplaceClipnode (ei->e->brink, tl->clipnode, c1);
						}
					}
				}
			}
		}
#endif
#ifdef HLBSP_BRINKHACK_BUGFIX
		DeleteLeaf (numobjects, tl);
#endif
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa8, %rsp
movq %r9, 0x40(%rsp)
movq %r8, 0x48(%rsp)
movapd %xmm0, 0x30(%rsp)
movl %ecx, 0x2c(%rsp)
movq %rdx, 0x60(%rsp)
movq %rsi, %r13
movq %rdi, (%rsp)
movq (%rsi), %rax
movq (%rax), %r14
cmpq %rax, %r14
je 0xee3f
movq 0x10(%r14), %r15
movb $0x0, 0x3d(%r15)
movq (%r15), %rax
movq (%rax), %r12
cmpq %rax, %r12
je 0xee36
movq 0x10(%r12), %rbx
movb $0x0, 0x38(%rbx)
movl $0x1, %ebp
xorl %esi, %esi
cmpl $0x1, %ebp
setne %sil
movq %rbx, %rdi
callq 0xe974
movb $0x0, 0x28(%rax)
decl %ebp
je 0xee14
movq (%r12), %r12
cmpq (%r15), %r12
jne 0xee06
movq (%r14), %r14
movq (%r13), %rax
jmp 0xeded
movq (%rax), %r14
movq (%r13), %rax
cmpq %rax, %r14
je 0xef1c
movapd 0x12479(%rip), %xmm0    # 0x212d0
xorpd 0x30(%rsp), %xmm0
movapd %xmm0, 0x10(%rsp)
movq 0x10(%r14), %r15
movq (%r15), %rax
movq (%rax), %r12
cmpq %rax, %r12
je 0xef0c
movq 0x10(%r12), %rbx
movl $0x1, %ebp
xorl %esi, %esi
cmpl $0x1, %ebp
setne %sil
movq %rbx, %rdi
callq 0xe974
cmpb $0x0, 0x28(%rax)
jne 0xeefb
movb $0x1, 0x28(%rax)
movsd (%rax), %xmm1
movsd 0x8(%rax), %xmm2
movq 0x60(%rsp), %rcx
mulsd 0x8(%rcx), %xmm2
mulsd (%rcx), %xmm1
movsd 0x10(%rax), %xmm0
mulsd 0x10(%rcx), %xmm0
addsd %xmm2, %xmm1
addsd %xmm1, %xmm0
subsd 0x30(%rcx), %xmm0
movsd %xmm0, 0x30(%rax)
ucomisd 0x30(%rsp), %xmm0
jbe 0xeedf
movl $0x0, 0x38(%rax)
jmp 0xeefb
movapd 0x10(%rsp), %xmm1
ucomisd %xmm0, %xmm1
jbe 0xeef4
movl $0x1, 0x38(%rax)
jmp 0xeefb
movl $0x2, 0x38(%rax)
decl %ebp
je 0xee80
movq (%r12), %r12
cmpq (%r15), %r12
jne 0xee76
movq (%r14), %r14
movq (%r13), %rax
cmpq %rax, %r14
jne 0xee63
movq (%rax), %rcx
movq (%r13), %rax
cmpq %rax, %rcx
movq %r13, 0x30(%rsp)
je 0xf1e4
xorl %ebx, %ebx
movq %rcx, 0x20(%rsp)
movq 0x10(%rcx), %r15
movq (%r15), %rax
movq (%rax), %r12
cmpq %rax, %r12
je 0xf1cd
movq %r15, 0x8(%rsp)
movq 0x10(%r12), %r14
cmpb $0x0, 0x38(%r14)
jne 0xf1b6
movb $0x1, 0x38(%r14)
movl $0x2, 0x3c(%r14)
movl $0x1, %ebp
xorl %esi, %esi
cmpl $0x1, %ebp
setne %sil
movq %r14, %rdi
callq 0xe974
movl 0x3c(%r14), %ecx
movl 0x38(%rax), %eax
cmpl $0x2, %ecx
je 0xefa3
cmpl $0x2, %eax
sete %dl
cmpl %ecx, %eax
sete %al
orb %dl, %al
movl $0xfffffffe, %eax       # imm = 0xFFFFFFFE
jne 0xefa7
movl %eax, 0x3c(%r14)
decl %ebp
je 0xef72
cmpl $-0x2, 0x3c(%r14)
jne 0xf1b6
movq %r12, 0x10(%rsp)
movq %r14, %rdi
xorl %esi, %esi
callq 0xe974
movq %rax, %rbp
movq %r14, %rdi
movl $0x1, %esi
callq 0xe974
movq %rax, %r12
movzbl 0x20(%r14), %esi
movq (%rsp), %rdi
callq 0xe062
movq %rax, %r13
movb $0x1, 0x28(%rax)
movq $0x0, 0x30(%rax)
movl $0x2, 0x38(%rax)
movsd 0x30(%rbp), %xmm0
movapd %xmm0, %xmm1
subsd 0x30(%r12), %xmm1
divsd %xmm1, %xmm0
xorl %eax, %eax
movsd (%rbp,%rax,8), %xmm1
movsd (%r12,%rax,8), %xmm2
subsd %xmm1, %xmm2
mulsd %xmm0, %xmm2
addsd %xmm1, %xmm2
movsd %xmm2, (%r13,%rax,8)
incq %rax
cmpq $0x3, %rax
jne 0xf012
movzbl 0x20(%r14), %esi
movq (%rsp), %rdi
callq 0xe0bc
movq %rax, %rbx
movq %rax, %rdi
movq %rbp, %rsi
xorl %edx, %edx
callq 0xe125
movq %rbx, %rdi
movq %r13, %rsi
movl $0x1, %edx
callq 0xe125
movb $0x1, 0x38(%rbx)
movl 0x38(%rbp), %eax
movl %eax, 0x3c(%rbx)
cmpb $0x0, 0x20(%rbx)
jne 0xf0b6
movq 0x30(%r14), %rdi
callq 0xdbc4
movq %rax, 0x30(%rbx)
movups (%r13), %xmm0
movups %xmm0, (%rax)
movsd 0x10(%r13), %xmm0
movsd %xmm0, 0x10(%rax)
movsd (%rbp), %xmm0
movsd %xmm0, 0x18(%rax)
movsd 0x8(%rbp), %xmm0
movsd %xmm0, 0x20(%rax)
movsd 0x10(%rbp), %xmm0
movsd %xmm0, 0x28(%rax)
movzbl 0x20(%r14), %esi
movq (%rsp), %rdi
callq 0xe0bc
movq %rax, %rbp
movq %rax, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0xe125
movq %rbp, %rdi
movq %r12, %rsi
movl $0x1, %edx
callq 0xe125
movb $0x1, 0x38(%rbp)
movl 0x38(%r12), %eax
movl %eax, 0x3c(%rbp)
cmpb $0x0, 0x20(%rbp)
jne 0xf18d
movq 0x30(%r14), %rdi
callq 0xdbc4
movq %rax, 0x30(%rbp)
movsd (%r12), %xmm0
movsd %xmm0, (%rax)
movsd 0x8(%r12), %xmm0
movsd %xmm0, 0x8(%rax)
movsd 0x10(%r12), %xmm0
movsd %xmm0, 0x10(%rax)
movups (%r13), %xmm0
movups %xmm0, 0x18(%rax)
movsd 0x10(%r13), %xmm0
movsd %xmm0, 0x28(%rax)
jmp 0xf18d
movq 0x10(%r12), %rdi
movzbl 0x18(%r12), %edx
movq %rbx, %rsi
callq 0xe247
movq 0x10(%r12), %rdi
movzbl 0x18(%r12), %edx
movq %rbp, %rsi
callq 0xe247
movq 0x10(%r12), %r15
movzbl 0x18(%r12), %r12d
movq (%r15), %rdi
movq %r14, %rsi
movl %r12d, %edx
callq 0xe99f
movq 0x28(%r14), %rdi
movq %r15, %rsi
movl %r12d, %edx
callq 0xeab7
movq 0x28(%r14), %rax
movq (%rax), %r12
cmpq %rax, %r12
jne 0xf13f
movq (%rsp), %rdi
movq %r14, %rsi
callq 0xeb2a
movb $0x1, %bl
movq 0x30(%rsp), %r13
movq 0x8(%rsp), %r15
movq 0x10(%rsp), %r12
testb $0x1, %bl
je 0xf1c0
movq (%r15), %r12
xorl %ebx, %ebx
movq (%r12), %r12
cmpq (%r15), %r12
jne 0xef50
movq 0x20(%rsp), %rcx
movq (%rcx), %rcx
movq (%r13), %rax
cmpq %rax, %rcx
jne 0xef33
jmp 0xf1e6
xorl %ebx, %ebx
movq (%rax), %rsi
cmpq (%r13), %rsi
je 0xf6e7
leaq 0x78(%rsp), %r12
movq 0x10(%rsi), %r15
cmpb $0x0, 0x3d(%r15)
jne 0xf6cf
movb $0x1, 0x3d(%r15)
movl $0x2, 0x40(%r15)
movq (%r15), %rcx
movq (%rcx), %rax
cmpq %rcx, %rax
je 0xf24b
movl 0x40(%r15), %ecx
movq 0x10(%rax), %rdx
movl 0x3c(%rdx), %edx
cmpl $0x2, %ecx
je 0xf23d
cmpl $0x2, %edx
je 0xf243
cmpl %ecx, %edx
movl $0xfffffffe, %edx       # imm = 0xFFFFFFFE
je 0xf243
movl %edx, 0x40(%r15)
movl %edx, %ecx
movq (%rax), %rax
cmpq (%r15), %rax
jne 0xf223
cmpl $-0x2, 0x40(%r15)
jne 0xf6cf
movq %rsi, 0xa0(%rsp)
movzbl 0x8(%r15), %esi
movq (%rsp), %rdi
callq 0xe1de
movq %rax, %r13
cmpb $0x0, 0x8(%r15)
jne 0xf28e
movq 0x30(%r15), %rax
movq %rax, 0x30(%r13)
movl 0x38(%r15), %eax
movl %eax, 0x38(%r13)
movb 0x3c(%r15), %al
movb %al, 0x3c(%r13)
movq %r15, %rdi
xorl %esi, %esi
callq 0xebf1
movq %rax, %rbx
movq %r15, %rdi
movl $0x1, %esi
callq 0xebf1
movq %rax, %r14
movq %rbx, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0xe2d5
movq %r14, %rdi
movq %r13, %rsi
movl $0x1, %edx
callq 0xe2d5
movb $0x1, 0x3d(%r13)
movq %r13, 0x8(%rsp)
movl $0x0, 0x40(%r13)
movzbl 0x8(%r15), %esi
movq (%rsp), %rdi
callq 0xe1de
movq %rax, %rbp
cmpb $0x0, 0x8(%r15)
leaq 0x70(%rsp), %r13
jne 0xf30d
movq 0x30(%r15), %rax
movq %rax, 0x30(%rbp)
movl 0x38(%r15), %eax
movl %eax, 0x38(%rbp)
movb 0x3c(%r15), %al
movb %al, 0x3c(%rbp)
movq %r15, %rdi
xorl %esi, %esi
callq 0xebf1
movq %rax, %rbx
movq %r15, %rdi
movl $0x1, %esi
callq 0xebf1
movq %rax, %r14
movq %rbx, %rdi
movq %rbp, %rsi
xorl %edx, %edx
callq 0xe2d5
movq %r14, %rdi
movq %rbp, %rsi
movl $0x1, %edx
callq 0xe2d5
movb $0x1, 0x3d(%rbp)
movq %rbp, 0x20(%rsp)
movl $0x1, 0x40(%rbp)
movl $0x0, 0x78(%rsp)
xorl %eax, %eax
movq %rax, 0x80(%rsp)
movq %r12, 0x88(%rsp)
movq %r12, 0x90(%rsp)
movq %rax, 0x98(%rsp)
movq (%r15), %rax
movq (%rax), %r14
cmpq %rax, %r14
movq %r15, 0x10(%rsp)
je 0xf474
movq 0x10(%r14), %rsi
cmpl $0x1, 0x3c(%rsi)
movzbl 0x18(%r14), %edx
jne 0xf459
movq 0x20(%rsp), %rdi
callq 0xe247
movq 0x10(%r14), %rbx
xorl %r15d, %r15d
xorl %esi, %esi
testl %r15d, %r15d
setne %sil
movq %rbx, %rdi
callq 0xe974
movq %rax, 0x50(%rsp)
movzbl 0x18(%r14), %ebp
movq %r13, %rdi
leaq 0x50(%rsp), %rsi
callq 0x11a30
xorl %ecx, %ecx
cmpl %ebp, %r15d
sete %cl
movl (%rax), %edx
leal -0x1(%rdx,%rcx,2), %ecx
movl %ecx, (%rax)
movq 0x80(%rsp), %rcx
movq %r12, %rax
testq %rcx, %rcx
je 0xf421
movq 0x50(%rsp), %rdx
movq %r12, %rax
xorl %esi, %esi
cmpq %rdx, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0xf409
movq %r12, %rsi
cmpq %r12, %rax
je 0xf439
movq 0x50(%rsp), %rcx
cmpq 0x20(%rax), %rcx
cmovbq %r12, %rax
movq %rax, %rsi
cmpl $0x0, 0x28(%rsi)
jne 0xf447
movq %r13, %rdi
callq 0x1219e
leal 0x1(%r15), %eax
testl %r15d, %r15d
movl %eax, %r15d
je 0xf3b9
jmp 0xf463
movq 0x8(%rsp), %rdi
callq 0xe247
movq (%r14), %r14
movq 0x10(%rsp), %r15
cmpq (%r15), %r14
jne 0xf395
cmpq $0x2, 0x98(%rsp)
je 0xf61b
movl $0x2, %edi
leaq 0x1248c(%rip), %rsi     # 0x2191b
xorl %eax, %eax
callq 0xa496
jmp 0xf61b
cmpq %r12, %r13
jne 0xf4b7
leaq 0x124a0(%rip), %rdi     # 0x21947
xorl %eax, %eax
callq 0xa1f4
xorl %edi, %edi
xorl %esi, %esi
callq 0xa731
cmpl $0x1, 0x28(%r13)
jne 0xf4c5
cmpl $-0x1, 0x28(%r14)
je 0xf4d8
movl $0x2, %edi
leaq 0x124a9(%rip), %rsi     # 0x2197a
xorl %eax, %eax
callq 0xa496
movq 0x20(%r13), %rax
cmpl $0x2, 0x38(%rax)
jne 0xf4ec
movq 0x20(%r14), %rax
cmpl $0x2, 0x38(%rax)
je 0xf503
leaq 0x124b4(%rip), %rdi     # 0x219a7
xorl %eax, %eax
callq 0xa1f4
xorl %edi, %edi
xorl %esi, %esi
callq 0xa731
movzbl 0x8(%r15), %esi
movq (%rsp), %rdi
callq 0xe0bc
movq %rax, %rbx
movq 0x20(%r13), %rsi
movq 0x20(%r14), %r15
movq %rax, %rdi
xorl %edx, %edx
callq 0xe125
movq %rbx, %rdi
movq %r15, %rsi
movl $0x1, %edx
callq 0xe125
cmpb $0x0, 0x20(%rbx)
jne 0xf5dd
movq 0x20(%r14), %rdi
movq 0x20(%r13), %rsi
callq 0xdc9e
movq %rax, 0x30(%rbx)
movq 0x10(%rsp), %rdi
movzbl 0x3c(%rdi), %esi
callq 0xebf1
cmpb $0x0, 0x8(%rax)
jne 0xf57c
movq 0x10(%rsp), %rdi
movzbl 0x3c(%rdi), %esi
xorl $0x1, %esi
callq 0xebf1
cmpb $0x1, 0x8(%rax)
jne 0xf593
leaq 0x12457(%rip), %rdi     # 0x219da
xorl %eax, %eax
callq 0xa1f4
xorl %edi, %edi
xorl %esi, %esi
callq 0xa731
movq 0x30(%rbx), %r12
movq 0x10(%rsp), %rdi
movq 0x30(%rdi), %rbp
movl 0x38(%rdi), %eax
movl %eax, 0x6c(%rsp)
movzbl 0x3c(%rdi), %esi
callq 0xebf1
movq 0x10(%rax), %r15
movq 0x10(%rsp), %rdi
movzbl 0x3c(%rdi), %esi
xorl $0x1, %esi
callq 0xebf1
movq 0x10(%rax), %r9
movq %r12, %rdi
movq %rbp, %rsi
movl 0x6c(%rsp), %edx
xorl %ecx, %ecx
movq %r15, %r8
callq 0xde6f
movb $0x1, 0x38(%rbx)
movl $0x2, 0x3c(%rbx)
movq 0x8(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0xe247
movq 0x20(%rsp), %rdi
movq %rbx, %rsi
movl $0x1, %edx
callq 0xe247
decl 0x28(%r13)
incl 0x28(%r14)
leaq 0x78(%rsp), %r12
movq 0x10(%rsp), %r15
movq 0x88(%rsp), %r14
movq %r14, %r13
cmpq %r12, %r14
je 0xf645
movq %r14, %r13
cmpl $0x0, 0x28(%r13)
jg 0xf645
movq %r13, %rdi
callq 0x4200
movq %rax, %r13
cmpq %r12, %rax
jne 0xf62e
cmpq %r12, %r14
je 0xf661
cmpl $0x0, 0x28(%r14)
js 0xf661
movq %r14, %rdi
callq 0x4200
movq %rax, %r14
cmpq %r12, %rax
jne 0xf64a
cmpq %r12, %r13
je 0xf674
cmpq %r12, %r14
jne 0xf4b7
jmp 0xf4a0
cmpq %r12, %r14
jne 0xf49b
movl $0x1, %ebx
movq 0x30(%rsp), %r13
xorl %esi, %esi
cmpl $0x1, %ebx
setne %sil
movq %r15, %rdi
callq 0xebf1
xorl %edx, %edx
cmpl $0x1, %ebx
setne %dl
movq %rax, %rdi
movq %r15, %rsi
callq 0xec1f
decl %ebx
je 0xf687
movq (%rsp), %rdi
movq %r15, %rsi
callq 0xec77
leaq 0x70(%rsp), %rdi
callq 0x11b80
movb $0x1, %bl
movq 0xa0(%rsp), %rsi
testb $0x1, %bl
je 0xf6da
movq (%r13), %rsi
xorl %ebx, %ebx
movq (%rsi), %rsi
cmpq (%r13), %rsi
jne 0xf1f8
movq 0xe8(%rsp), %r12
cmpb $0x1, 0x8(%r13)
jne 0xf70d
leaq 0x12328(%rip), %rdi     # 0x21a25
xorl %eax, %eax
callq 0xa1f4
xorl %edi, %edi
xorl %esi, %esi
callq 0xa731
movzbl 0x8(%r13), %esi
movq (%rsp), %rbx
movq %rbx, %rdi
callq 0xe395
movq 0x48(%rsp), %r14
movq %rax, (%r14)
movzbl 0x8(%r13), %esi
movq %rbx, %rdi
callq 0xe395
movq 0x40(%rsp), %rcx
movq %rax, (%rcx)
movq (%r14), %rax
movq 0xe0(%rsp), %rdx
movq %rdx, 0x10(%rax)
movq (%rcx), %rax
movq %r12, 0x10(%rax)
movq (%r13), %rax
movq (%rax), %rcx
cmpq %rax, %rcx
je 0xf78b
movl $0x2, %esi
movl $0xfffffffe, %edx       # imm = 0xFFFFFFFE
movq 0x10(%rcx), %rdi
movl 0x40(%rdi), %edi
cmpl $0x2, %esi
je 0xf77f
cmpl $0x2, %edi
je 0xf77d
cmpl %esi, %edi
cmovnel %edx, %esi
movl %esi, %edi
movq (%rcx), %rcx
movl %edi, %esi
cmpq %rax, %rcx
jne 0xf767
jmp 0xf790
movl $0x2, %edi
movl %edi, 0x8(%rsp)
leaq 0x78(%rsp), %r15
movl $0x0, (%r15)
xorl %eax, %eax
movq %rax, 0x8(%r15)
movq %r15, 0x10(%r15)
movq %r15, 0x18(%r15)
movq %rax, 0x20(%r15)
movq (%r13), %rcx
movq (%rcx), %rax
cmpq %rcx, %rax
je 0xf8f2
movl 0x8(%rsp), %ecx
xorl $0x1, %ecx
movl %ecx, 0x20(%rsp)
movq 0x10(%rax), %rbx
movzbl 0x18(%rax), %edx
movq %r13, %rdi
movq %rbx, %rsi
movl %edx, 0x10(%rsp)
callq 0xec1f
movl 0x40(%rbx), %eax
testl %eax, %eax
je 0xf7f7
cmpl $0x2, %eax
jne 0xf821
cmpl $0x1, 0x8(%rsp)
je 0xf821
movq 0x48(%rsp), %rax
movq (%rax), %rdi
movq %rbx, %rsi
movl 0x10(%rsp), %edx
callq 0xe2d5
movq 0x30(%rsp), %r13
movq (%r13), %rcx
movq (%rcx), %rax
cmpq %rcx, %rax
jne 0xf7cd
jmp 0xf8f2
movl %eax, %ecx
xorl $0x2, %ecx
orl 0x20(%rsp), %ecx
sete %cl
cmpl $0x1, %eax
je 0xf836
testb %cl, %cl
je 0xf80b
movq 0x40(%rsp), %rax
movq (%rax), %rdi
movq %rbx, %rsi
movl 0x10(%rsp), %edx
callq 0xe2d5
cmpl $-0x2, 0x8(%rsp)
jne 0xf80b
movq (%rbx), %rax
movq (%rax), %r13
cmpq %rax, %r13
je 0xf80b
movq %r15, %rbp
leaq 0x10(%r13), %r14
movb 0x18(%r13), %r15b
leaq 0x70(%rsp), %rdi
movq %r14, %rsi
callq 0x11a96
xorl %ecx, %ecx
cmpb 0x10(%rsp), %r15b
sete %cl
movl (%rax), %edx
leal -0x1(%rdx,%rcx,2), %ecx
movl %ecx, (%rax)
movq 0x80(%rsp), %rcx
movq %rbp, %rdi
movq %rbp, %rax
testq %rcx, %rcx
je 0xf8b7
movq (%r14), %rdx
movq %rdi, %rax
xorl %esi, %esi
cmpq %rdx, 0x20(%rcx)
setb %sil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rsi,8), %rcx
testq %rcx, %rcx
jne 0xf89f
movq %rdi, %rsi
cmpq %rdi, %rax
je 0xf8cd
movq (%r14), %rcx
cmpq 0x20(%rax), %rcx
cmovbq %rdi, %rax
movq %rax, %rsi
cmpl $0x0, 0x28(%rsi)
jne 0xf8dd
leaq 0x70(%rsp), %rdi
callq 0x123ee
movq (%r13), %r13
cmpq (%rbx), %r13
movq %rbp, %r15
jne 0xf85c
jmp 0xf80b
cmpl $-0x2, 0x8(%rsp)
jne 0xf9ef
movzbl 0x8(%r13), %esi
movq (%rsp), %rdi
callq 0xe1de
movq %rax, %rbx
cmpb $0x0, 0x8(%rax)
jne 0xf928
movq 0x60(%rsp), %rax
movq %rax, 0x30(%rbx)
movl 0x2c(%rsp), %eax
movl %eax, 0x38(%rbx)
movb $0x0, 0x3c(%rbx)
movb $0x1, 0x3d(%rbx)
movl $0x2, 0x40(%rbx)
movq 0x48(%rsp), %rax
movq (%rax), %rdi
movq 0x40(%rsp), %rax
movq (%rax), %r14
movq %rbx, %rsi
xorl %edx, %edx
callq 0xe2d5
movq %r14, %rdi
movq %rbx, %rsi
movl $0x1, %edx
callq 0xe2d5
movq 0x88(%rsp), %r14
cmpq %r15, %r14
je 0xf9ef
leaq 0x120eb(%rip), %rbp     # 0x21a60
movq 0x20(%r14), %rax
cmpl $0x2, 0x3c(%rax)
je 0xf992
movq %rbp, %rdi
xorl %eax, %eax
callq 0xa1f4
xorl %edi, %edi
xorl %esi, %esi
callq 0xa731
cmpl $0x0, 0x28(%r14)
jle 0xf9b7
movq 0x20(%r14), %rsi
movq %rbx, %rdi
xorl %edx, %edx
callq 0xe247
movl 0x28(%r14), %eax
leal -0x1(%rax), %ecx
movl %ecx, 0x28(%r14)
cmpl $0x1, %eax
jg 0xf999
cmpl $0x0, 0x28(%r14)
jns 0xf9df
movq 0x20(%r14), %rsi
movq %rbx, %rdi
movl $0x1, %edx
callq 0xe247
movl 0x28(%r14), %eax
leal 0x1(%rax), %ecx
movl %ecx, 0x28(%r14)
cmpl $-0x1, %eax
jl 0xf9be
movq %r14, %rdi
callq 0x4200
movq %rax, %r14
cmpq %r15, %rax
jne 0xf975
movq 0x48(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x50(%rsp)
movq 0x40(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x58(%rsp)
xorl %eax, %eax
xorl %ecx, %ecx
movq 0x50(%rsp,%rcx,8), %rdx
movq (%rdx), %rdi
movq (%rdi), %rsi
cmpq %rdi, %rsi
je 0xfa58
movq 0x10(%rsi), %rdi
movq (%rdi), %r8
movq (%r8), %rdi
cmpq %r8, %rdi
je 0xfa50
movq 0x10(%rdi), %r8
movb %al, 0x41(%r8)
movq 0x10(%rdi), %r8
movb %al, 0x40(%r8)
movq 0x10(%rdi), %r8
movb %al, 0x38(%r8)
movq (%rdi), %rdi
movq 0x10(%rsi), %r8
cmpq (%r8), %rdi
jne 0xfa2c
movq (%rsi), %rsi
cmpq (%rdx), %rsi
jne 0xfa1d
leaq 0x1(%rcx), %rdx
testq %rcx, %rcx
movq %rdx, %rcx
je 0xfa0d
xorl %eax, %eax
movq 0x50(%rsp,%rax,8), %rcx
movq (%rcx), %rsi
movq (%rsi), %rdx
cmpq %rsi, %rdx
je 0xfaa2
movq 0x10(%rdx), %rsi
movq (%rsi), %rdi
movq (%rdi), %rsi
cmpq %rdi, %rsi
je 0xfa9a
movq 0x10(%rsi), %rdi
movb $0x1, 0x40(%rdi,%rax)
movq (%rsi), %rsi
movq 0x10(%rdx), %rdi
cmpq (%rdi), %rsi
jne 0xfa85
movq (%rdx), %rdx
cmpq (%rcx), %rdx
jne 0xfa76
leaq 0x1(%rax), %rcx
testq %rax, %rax
movq %rcx, %rax
je 0xfa66
leaq 0x11fab(%rip), %r14     # 0x21a60
xorl %ebx, %ebx
movq 0x50(%rsp,%rbx,8), %r15
movq (%r15), %rax
movq (%rax), %rbp
cmpq %rax, %rbp
je 0xfbd9
movq 0x10(%rbp), %rax
movq (%rax), %rax
movq (%rax), %r13
cmpq %rax, %r13
je 0xfbcc
movq 0x10(%r13), %rax
cmpb $0x0, 0x38(%rax)
jne 0xfbbb
movb $0x1, 0x38(%rax)
movq 0x10(%r13), %rax
cmpb $0x0, 0x20(%rax)
jne 0xfbbb
movb 0x40(%rax), %cl
cmpb $0x1, %cl
jne 0xfb80
cmpb $0x1, 0x41(%rax)
jne 0xfb51
cmpl $0x2, 0x3c(%rax)
je 0xfb25
movq %r14, %rdi
xorl %eax, %eax
callq 0xa1f4
xorl %edi, %edi
xorl %esi, %esi
callq 0xa731
movq 0x10(%r13), %rax
movq 0x30(%rax), %rdi
movq 0x30(%rsp), %rax
movq 0x10(%rax), %rcx
movq 0x60(%rsp), %rsi
movl 0x2c(%rsp), %edx
movq 0xe0(%rsp), %r8
movq %r12, %r9
callq 0xde6f
jmp 0xfbbb
testb %cl, %cl
je 0xfb80
cmpl $0x1, 0x3c(%rax)
movq 0xe0(%rsp), %rdx
jne 0xfba5
movq %r14, %rdi
xorl %eax, %eax
callq 0xa1f4
xorl %edi, %edi
xorl %esi, %esi
callq 0xa731
movq 0xe0(%rsp), %rdx
jmp 0xfba5
cmpb $0x1, 0x41(%rax)
jne 0xfbbb
cmpl $0x0, 0x3c(%rax)
movq %r12, %rdx
jne 0xfba5
movq %r14, %rdi
xorl %eax, %eax
callq 0xa1f4
xorl %edi, %edi
xorl %esi, %esi
callq 0xa731
movq %r12, %rdx
movq 0x10(%r13), %rax
movq 0x30(%rax), %rdi
movq 0x30(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0xdfb0
movq (%r13), %r13
movq 0x10(%rbp), %rax
cmpq (%rax), %r13
jne 0xfade
movq (%rbp), %rbp
cmpq (%r15), %rbp
jne 0xfacb
leaq 0x1(%rbx), %rax
testq %rbx, %rbx
movq %rax, %rbx
je 0xfab7
movq (%rsp), %rdi
movq 0x30(%rsp), %rsi
callq 0xed55
leaq 0x70(%rsp), %rdi
callq 0x11bd0
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0xfc3a
jmp 0xfc3a
jmp 0xfc2b
jmp 0xfc3a
jmp 0xfc3a
jmp 0xfc3a
jmp 0xfc2b
jmp 0xfc3a
jmp 0xfc3a
jmp 0xfc2b
jmp 0xfc2b
jmp 0xfc2b
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x11b80
jmp 0xfc47
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x11bd0
movq %rbx, %rdi
callq 0x4540