// File: /workspace/github_cpp_makefile_star2_O1/VanAndelInstitute[P]intent/src/edlib.cpp
// Function: myersCalcEditDistanceNW(unsigned long const*, int, int, int, unsigned char const*, int, int, int*, int*, bool, AlignmentData**, int)
static int myersCalcEditDistanceNW(const Word* const Peq, const int W, const int maxNumBlocks,
                                   const int queryLength,
                                   const unsigned char* const target, const int targetLength,
                                   int k, int* const bestScore_,
                                   int* const position_, const bool findAlignment,
                                   AlignmentData** const alignData, const int targetStopPosition) {
    if (targetStopPosition > -1 && findAlignment) {
        // They can not be both set at the same time!
        return EDLIB_STATUS_ERROR;
    }

    // Each STRONG_REDUCE_NUM column is reduced in more expensive way.
    const int STRONG_REDUCE_NUM = 2048; // TODO: Choose this number dinamically (based on query and target lengths?), so it does not affect speed of computation

    if (k < abs(targetLength - queryLength)) {
        *bestScore_ = *position_ = -1;
        return EDLIB_STATUS_OK;
    }

    k = min(k, max(queryLength, targetLength));  // Upper bound for k

    // firstBlock is 0-based index of first block in Ukkonen band.
    // lastBlock is 0-based index of last block in Ukkonen band.
    int firstBlock = 0;
    // This is optimal now, by my formula.
    int lastBlock = min(maxNumBlocks, ceilDiv(min(k, (k + queryLength - targetLength) / 2) + 1, WORD_SIZE)) - 1;
    Block* bl; // Current block

    Block* blocks = new Block[maxNumBlocks];

    // Initialize P, M and score
    bl = blocks;
    for (int b = 0; b <= lastBlock; b++) {
        bl->score = (b + 1) * WORD_SIZE;
        bl->P = static_cast<Word>(-1); // All 1s
        bl->M = static_cast<Word>(0);
        bl++;
    }

    // If we want to find alignment, we have to store needed data.
    if (findAlignment)
        *alignData = new AlignmentData(maxNumBlocks, targetLength);
    else if (targetStopPosition > -1)
        *alignData = new AlignmentData(maxNumBlocks, 1);
    else
        *alignData = NULL;

    const unsigned char* targetChar = target;
    for (int c = 0; c < targetLength; c++) { // for each column
        const Word* Peq_c = Peq + *targetChar * maxNumBlocks;

        //----------------------- Calculate column -------------------------//
        int hout = 1;
        bl = blocks + firstBlock;
        for (int b = firstBlock; b <= lastBlock; b++) {
            hout = calculateBlock(bl->P, bl->M, Peq_c[b], hout, bl->P, bl->M);
            bl->score += hout;
            bl++;
        }
        bl--;
        //------------------------------------------------------------------//
        // bl now points to last block

        // Update k. I do it only on end of column because it would slow calculation too much otherwise.
        // NOTICE: I add W when in last block because it is actually result from W cells to the left and W cells up.
        k = min(k, bl->score
                + max(targetLength - c - 1, queryLength - ((1 + lastBlock) * WORD_SIZE - 1) - 1)
                + (lastBlock == maxNumBlocks - 1 ? W : 0));

        //---------- Adjust number of blocks according to Ukkonen ----------//
        //--- Adjust last block ---//
        // If block is not beneath band, calculate next block. Only next because others are certainly beneath band.
        if (lastBlock + 1 < maxNumBlocks
            && !(//score[lastBlock] >= k + WORD_SIZE ||  // NOTICE: this condition could be satisfied if above block also!
                 ((lastBlock + 1) * WORD_SIZE - 1
                  > k - bl->score + 2 * WORD_SIZE - 2 - targetLength + c + queryLength))) {
            lastBlock++; bl++;
            bl->P = static_cast<Word>(-1); // All 1s
            bl->M = static_cast<Word>(0);
            int newHout = calculateBlock(bl->P, bl->M, Peq_c[lastBlock], hout, bl->P, bl->M);
            bl->score = (bl - 1)->score - hout + WORD_SIZE + newHout;
            hout = newHout;
        }

        // While block is out of band, move one block up.
        // NOTE: Condition used here is more loose than the one from the article, since I simplified the max() part of it.
        // I could consider adding that max part, for optimal performance.
        while (lastBlock >= firstBlock
               && (bl->score >= k + WORD_SIZE
                   || ((lastBlock + 1) * WORD_SIZE - 1 >
                       // TODO: Does not work if do not put +1! Why???
                       k - bl->score + 2 * WORD_SIZE - 2 - targetLength + c + queryLength + 1))) {
            lastBlock--; bl--;
        }
        //-------------------------//

        //--- Adjust first block ---//
        // While outside of band, advance block
        while (firstBlock <= lastBlock
               && (blocks[firstBlock].score >= k + WORD_SIZE
                   || ((firstBlock + 1) * WORD_SIZE - 1 <
                       blocks[firstBlock].score - k - targetLength + queryLength + c))) {
            firstBlock++;
        }
        //--------------------------/


        // TODO: consider if this part is useful, it does not seem to help much
        if (c % STRONG_REDUCE_NUM == 0) { // Every some columns do more expensive but more efficient reduction
            while (lastBlock >= firstBlock) {
                // If all cells outside of band, remove block
                vector<int> scores = getBlockCellValues(*bl);
                int numCells = lastBlock == maxNumBlocks - 1 ? WORD_SIZE - W : WORD_SIZE;
                int r = lastBlock * WORD_SIZE + numCells - 1;
                bool reduce = true;
                for (int i = WORD_SIZE - numCells; i < WORD_SIZE; i++) {
                    // TODO: Does not work if do not put +1! Why???
                    if (scores[i] <= k && r <= k - scores[i] - targetLength + c + queryLength + 1) {
                        reduce = false;
                        break;
                    }
                    r--;
                }
                if (!reduce) break;
                lastBlock--; bl--;
            }

            while (firstBlock <= lastBlock) {
                // If all cells outside of band, remove block
                vector<int> scores = getBlockCellValues(blocks[firstBlock]);
                int numCells = firstBlock == maxNumBlocks - 1 ? WORD_SIZE - W : WORD_SIZE;
                int r = firstBlock * WORD_SIZE + numCells - 1;
                bool reduce = true;
                for (int i = WORD_SIZE - numCells; i < WORD_SIZE; i++) {
                    if (scores[i] <= k && r >= scores[i] - k - targetLength + c + queryLength) {
                        reduce = false;
                        break;
                    }
                    r--;
                }
                if (!reduce) break;
                firstBlock++;
            }
        }


        // If band stops to exist finish
        if (lastBlock < firstBlock) {
            *bestScore_ = *position_ = -1;
            delete[] blocks;
            return EDLIB_STATUS_OK;
        }
        //------------------------------------------------------------------//


        //---- Save column so it can be used for reconstruction ----//
        if (findAlignment && c < targetLength) {
            bl = blocks + firstBlock;
            for (int b = firstBlock; b <= lastBlock; b++) {
                (*alignData)->Ps[maxNumBlocks * c + b] = bl->P;
                (*alignData)->Ms[maxNumBlocks * c + b] = bl->M;
                (*alignData)->scores[maxNumBlocks * c + b] = bl->score;
                (*alignData)->firstBlocks[c] = firstBlock;
                (*alignData)->lastBlocks[c] = lastBlock;
                bl++;
            }
        }
        //----------------------------------------------------------//
        //---- If this is stop column, save it and finish ----//
        if (c == targetStopPosition) {
            for (int b = firstBlock; b <= lastBlock; b++) {
                (*alignData)->Ps[b] = (blocks + b)->P;
                (*alignData)->Ms[b] = (blocks + b)->M;
                (*alignData)->scores[b] = (blocks + b)->score;
                (*alignData)->firstBlocks[0] = firstBlock;
                (*alignData)->lastBlocks[0] = lastBlock;
            }
            *bestScore_ = -1;
            *position_ = targetStopPosition;
            delete[] blocks;
            return EDLIB_STATUS_OK;
        }
        //----------------------------------------------------//

        targetChar++;
    }

    if (lastBlock == maxNumBlocks - 1) { // If last block of last column was calculated
        // Obtain best score from block -> it is complicated because query is padded with W cells
        int bestScore = getBlockCellValues(blocks[lastBlock])[W];
        if (bestScore <= k) {
            *bestScore_ = bestScore;
            *position_ = targetLength - 1;
            delete[] blocks;
            return EDLIB_STATUS_OK;
        }
    }

    *bestScore_ = *position_ = -1;
    delete[] blocks;
    return EDLIB_STATUS_OK;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb8, %rsp
movq %r8, 0x88(%rsp)
movl %ecx, %r15d
movl %esi, 0x30(%rsp)
movq %rdi, 0x80(%rsp)
movl 0x118(%rsp), %ebp
testl %ebp, %ebp
setns %cl
movl $0x1, %eax
testb %cl, 0x108(%rsp)
jne 0x2c14d
movl %r9d, %ebx
movl %edx, %r14d
movq 0x100(%rsp), %rsi
movq 0xf8(%rsp), %rdi
movl 0xf0(%rsp), %eax
movl %r9d, %ecx
subl %r15d, %ecx
movl %ecx, %edx
negl %edx
cmovsl %ecx, %edx
cmpl %eax, %edx
jle 0x2b70b
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movl %eax, (%rsi)
movl %eax, (%rdi)
jmp 0x2c14b
movl %r15d, %ecx
subl %ebx, %ecx
movl %ebx, %r12d
cmovgl %r15d, %r12d
cmpl %r12d, %eax
cmovll %eax, %r12d
movq %rcx, 0x58(%rsp)
addl %r12d, %ecx
movl %ecx, %eax
shrl $0x1f, %eax
addl %ecx, %eax
sarl %eax
cmpl %eax, %r12d
cmovll %r12d, %eax
incl %eax
testb $0x3f, %al
je 0x2b74f
leal 0x3f(%rax), %r13d
testl %eax, %eax
cmovnsl %eax, %r13d
sarl $0x6, %r13d
incl %r13d
jmp 0x2b755
sarl $0x6, %eax
movl %eax, %r13d
cmpl %r13d, %r14d
cmovll %r14d, %r13d
movslq %r14d, %rax
movl $0x18, %ecx
movq %rax, 0x78(%rsp)
mulq %rcx
movq $-0x1, %rdi
cmovnoq %rax, %rdi
callq 0x6030
movq %r13, %r9
movq %rax, 0x10(%rsp)
testl %r9d, %r9d
jle 0x2b7b7
movq 0x10(%rsp), %rax
addq $0x10, %rax
movl $0x40, %ecx
movl %r9d, %edx
movl %ecx, (%rax)
movq $-0x1, -0x10(%rax)
movq $0x0, -0x8(%rax)
addl $0x40, %ecx
addq $0x18, %rax
decl %edx
jne 0x2b79a
cmpb $0x0, 0x108(%rsp)
movq %rbx, 0x38(%rsp)
movq %r14, 0x20(%rsp)
movq %r15, 0x48(%rsp)
je 0x2b7ec
movl $0x28, %edi
callq 0x63b0
movq %rax, %rbp
movq %rax, %rdi
movl %r14d, %esi
movl %ebx, %edx
callq 0x2d8be
jmp 0x2b813
testl %ebp, %ebp
js 0x2c124
movl $0x28, %edi
callq 0x63b0
movq %rax, %rbp
movq %rax, %rdi
movq 0x20(%rsp), %rsi
movl $0x1, %edx
callq 0x2d8be
movq %r13, %r9
movq 0x110(%rsp), %rax
decl %r9d
movq %rbp, (%rax)
movq 0x38(%rsp), %rsi
testl %esi, %esi
setg %dil
jle 0x2c047
movq 0x20(%rsp), %r13
leal -0x1(%r13), %ecx
movl %ecx, 0x34(%rsp)
movq 0x48(%rsp), %rax
addl $0x7e, %eax
movq %rax, 0x98(%rsp)
subl %esi, %eax
movq %rax, 0x90(%rsp)
movl $0x40, %eax
subl 0x30(%rsp), %eax
movl %eax, 0x44(%rsp)
movq 0x58(%rsp), %rax
incl %eax
movq %rax, 0x58(%rsp)
movl %esi, %eax
movq %rax, 0xa8(%rsp)
movq 0x10(%rsp), %rax
addq $0x10, %rax
movq %rax, 0x70(%rsp)
movq 0x78(%rsp), %rax
leaq (,%rax,4), %rax
movq %rax, 0xa0(%rsp)
movq $0x0, 0x68(%rsp)
movq $0x0, 0x60(%rsp)
xorl %ebx, %ebx
xorl %r14d, %r14d
movb %dil, 0x7(%rsp)
movq 0x88(%rsp), %rax
movzbl (%rax), %eax
imull %r13d, %eax
movslq %eax, %r8
movslq %r14d, %rax
leaq (%rax,%rax,2), %rdx
movq 0x10(%rsp), %rcx
movq %rdx, 0x50(%rsp)
leaq (%rcx,%rdx,8), %rdx
movl $0x1, %edi
cmpl %r9d, %eax
movq %r9, 0x8(%rsp)
movq %rbx, 0x18(%rsp)
movq %r8, 0xb0(%rsp)
jg 0x2b9c6
movq %r12, %rcx
leaq (,%r8,8), %rdi
leaq (%rdi,%rax,8), %r8
addq 0x80(%rsp), %r8
subl %eax, %r9d
incl %r9d
movl $0x1, %edi
xorl %r10d, %r10d
movl %edi, %r11d
movq (%rdx), %rdi
movq 0x8(%rdx), %r13
movq (%r8,%r10,8), %rbp
movl %r11d, %ebx
shrl $0x2, %ebx
andl $0x1, %ebx
movq %rbp, %r15
orq %r13, %r15
orq %rbx, %rbp
movq %rbp, %r12
andq %rdi, %r12
addq %rdi, %r12
xorq %rdi, %r12
orq %rbp, %r12
movq %r12, %rbp
orq %rdi, %rbp
notq %rbp
orq %r13, %rbp
andq %rdi, %r12
movq %rbp, %rdi
shrq $0x3f, %rdi
movq %r12, %r13
sarq $0x3f, %r13
addl %r13d, %edi
addq %rbp, %rbp
addq %r12, %r12
incl %r11d
shrl %r11d
orq %rbp, %r11
movq %r11, %r13
orq %r15, %r13
notq %r13
orq %rbx, %r12
orq %r13, %r12
movq %r12, (%rdx)
andq %r15, %r11
movq %r11, 0x8(%rdx)
addl %edi, 0x10(%rdx)
addq $0x18, %rdx
incq %r10
cmpl %r10d, %r9d
jne 0x2b92a
movq 0x38(%rsp), %rsi
movq %rcx, %r12
movq 0x20(%rsp), %r13
movq 0x18(%rsp), %rbx
leaq -0x18(%rdx), %r15
movl -0x8(%rdx), %r8d
movl %ebx, %r11d
notl %r11d
addl %esi, %r11d
movq 0x8(%rsp), %rbp
leal 0x1(%rbp), %r9d
movl %r9d, %r10d
shll $0x6, %r10d
movq 0x48(%rsp), %rcx
movl %ecx, %ebx
subl %r10d, %ebx
cmpl %ebx, %r11d
cmovgl %r11d, %ebx
cmpl 0x34(%rsp), %ebp
movl $0x0, %r11d
cmovel 0x30(%rsp), %r11d
addl %ebx, %r11d
addl %r8d, %r11d
cmpl %r11d, %r12d
cmovgel %r11d, %r12d
cmpl %r13d, %r9d
movq %r12, 0x28(%rsp)
jge 0x2badb
movq %r8, %rbx
decl %r10d
movq 0x98(%rsp), %rcx
movq 0x18(%rsp), %r8
leal (%rcx,%r8), %r11d
movq %rbx, %r8
addl %esi, %ebx
subl %ebx, %r11d
addl %r12d, %r11d
cmpl %r11d, %r10d
movq 0x8(%rsp), %r11
jg 0x2bae0
movq 0x80(%rsp), %rcx
movq 0xb0(%rsp), %rsi
leaq (%rcx,%rsi,8), %rsi
movq $-0x1, (%rdx)
movq $0x0, 0x8(%rdx)
movslq %r9d, %r10
movq (%rsi,%r10,8), %rsi
movl %edi, %r10d
shrl $0x2, %r10d
andl $0x1, %r10d
movq %rsi, %r11
orq %r10, %r11
movq %r11, %rbx
negq %rbx
orq %r11, %rbx
movq %rbx, %r11
sarq $0x3f, %r11
addq %rbx, %rbx
leal 0x1(%rdi), %r15d
shrl %r15d
movq %r15, %r12
orq %rsi, %r12
notq %r12
orq %r10, %r12
orq %rbx, %r12
movq %r12, (%rdx)
movq 0x28(%rsp), %r12
andl %r15d, %esi
movq %rsi, 0x8(%rdx)
subl %edi, %r8d
leal (%r8,%r11), %esi
addl $0x40, %esi
movl %esi, 0x10(%rdx)
movq %rdx, %r15
movl %r9d, %r11d
jmp 0x2bae0
movq 0x8(%rsp), %r11
cmpl %r14d, %r11d
jge 0x2baec
movq 0x18(%rsp), %rbx
jmp 0x2bb3e
leal 0x40(%r12), %edx
movq 0x90(%rsp), %rcx
movq 0x18(%rsp), %rbx
leal (%rcx,%rbx), %esi
addl %r12d, %esi
leal -0x1(%r14), %edi
movl %r11d, %r8d
shll $0x6, %r8d
orl $0x3e, %r8d
movl 0x10(%r15), %r9d
cmpl %edx, %r9d
jge 0x2bb27
movl %esi, %r10d
subl %r9d, %r10d
cmpl %r10d, %r8d
jle 0x2bb3e
leal -0x1(%r11), %r9d
addq $-0x18, %r15
addl $-0x40, %r8d
cmpl %r14d, %r11d
movl %r9d, %r11d
jg 0x2bb13
movl %edi, %r11d
cmpl %r11d, %r14d
jg 0x2bba3
leal 0x40(%r12), %edx
movq 0x48(%rsp), %rcx
leal (%rbx,%rcx), %esi
movq 0x38(%rsp), %rcx
subl %r12d, %esi
subl %ecx, %esi
movslq %r11d, %rdi
leal 0x1(%r11), %r8d
decq %rax
movq 0x70(%rsp), %rcx
movq 0x50(%rsp), %r9
leaq (%rcx,%r9,8), %rcx
movl %r14d, %r9d
shll $0x6, %r9d
orl $0x3f, %r9d
movl (%rcx), %r10d
cmpl %edx, %r10d
jge 0x2bb8d
addl %esi, %r10d
cmpl %r10d, %r9d
jge 0x2bba3
incl %r14d
incq %rax
addq $0x18, %rcx
addl $0x40, %r9d
cmpq %rdi, %rax
jl 0x2bb7d
movl %r8d, %r14d
movq %rbx, %rax
shlq $0x35, %rax
jne 0x2be81
cmpl %r14d, %r11d
jl 0x2bd15
movq 0x58(%rsp), %rax
addl %ebx, %eax
addl %r12d, %eax
movl %eax, 0x50(%rsp)
movq %r11, 0x8(%rsp)
movq (%r15), %rbx
movq 0x8(%r15), %r13
movl 0x10(%r15), %r12d
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %rbp
movl $0x100, %edx            # imm = 0x100
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
xorl %eax, %eax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
movl %r12d, (%rbp,%rax,4)
movq %rcx, %rdx
andq %rbx, %rdx
cmpq $0x1, %rdx
adcl $-0x1, %r12d
movq %rcx, %rdx
andq %r13, %rdx
cmpq $0x1, %rdx
sbbl $-0x1, %r12d
shrq %rcx
incq %rax
cmpq $0x3f, %rax
jne 0x2bbff
movl %r12d, 0xfc(%rbp)
movq 0x8(%rsp), %r11
cmpl 0x34(%rsp), %r11d
movl $0x40, %ecx
cmovel 0x44(%rsp), %ecx
testl %ecx, %ecx
setle %bl
jle 0x2bcd2
movl $0x40, %eax
subl %ecx, %eax
movl %r11d, %edx
shll $0x6, %edx
cltq
movl (%rbp,%rax,4), %esi
movq 0x28(%rsp), %r12
cmpl %r12d, %esi
jg 0x2bc81
leal (%rcx,%rdx), %edi
decl %edi
movl 0x50(%rsp), %r8d
subl %esi, %r8d
cmpl %r8d, %edi
jle 0x2bcef
addl %ecx, %edx
addl $-0x2, %edx
movslq %ecx, %rcx
movl $0x41, %esi
subq %rcx, %rsi
xorl %r8d, %r8d
movl 0x50(%rsp), %ebx
movq %r8, %rdi
cmpl $0x40, %esi
je 0x2bcd9
movl (%rbp,%rsi,4), %r9d
leaq -0x1(%rdi), %r8
incq %rsi
cmpl %r12d, %r9d
jg 0x2bc98
addl %edx, %edi
movl %ebx, %r10d
subl %r9d, %r10d
cmpl %r10d, %edi
jg 0x2bc98
addq %r8, %rcx
movl $0x3f, %eax
subq %rcx, %rax
cmpq $0x3f, %rax
setge %bl
jmp 0x2bcef
movq 0x28(%rsp), %r12
jmp 0x2bce3
subq %rdi, %rax
cmpq $0x3f, %rax
setge %bl
decl %r11d
movq %r11, 0x8(%rsp)
addq $-0x18, %r15
movl $0x100, %esi            # imm = 0x100
movq %rbp, %rdi
callq 0x63c0
testb %bl, %bl
je 0x2bd10
movq 0x8(%rsp), %r11
cmpl %r14d, %r11d
jge 0x2bbc7
jmp 0x2bd15
movq 0x8(%rsp), %r11
cmpl %r11d, %r14d
jg 0x2be6b
movq 0x48(%rsp), %rax
movq 0x18(%rsp), %rcx
leal (%rcx,%rax), %r15d
movq 0x38(%rsp), %rax
addl %r12d, %eax
subl %eax, %r15d
movq %r11, 0x8(%rsp)
movslq %r14d, %rax
leaq (%rax,%rax,2), %rax
movq 0x10(%rsp), %rcx
movq (%rcx,%rax,8), %rbx
movq 0x8(%rcx,%rax,8), %r13
movl 0x10(%rcx,%rax,8), %r12d
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %rbp
movl $0x100, %edx            # imm = 0x100
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
xorl %eax, %eax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
movl %r12d, (%rbp,%rax,4)
movq %rcx, %rdx
andq %rbx, %rdx
cmpq $0x1, %rdx
adcl $-0x1, %r12d
movq %rcx, %rdx
andq %r13, %rdx
cmpq $0x1, %rdx
sbbl $-0x1, %r12d
shrq %rcx
incq %rax
cmpq $0x3f, %rax
jne 0x2bd7e
movl %r12d, 0xfc(%rbp)
cmpl 0x34(%rsp), %r14d
movl $0x40, %ecx
cmovel 0x44(%rsp), %ecx
testl %ecx, %ecx
setle %bl
jle 0x2be38
movl $0x40, %eax
subl %ecx, %eax
movl %r14d, %edx
shll $0x6, %edx
cltq
movl (%rbp,%rax,4), %esi
movq 0x28(%rsp), %r12
cmpl %r12d, %esi
jg 0x2bdef
leal (%rcx,%rdx), %edi
addl %r15d, %esi
cmpl %esi, %edi
jg 0x2be4c
addl %ecx, %edx
decl %edx
movslq %ecx, %rcx
movl $0x41, %esi
subq %rcx, %rsi
xorl %r8d, %r8d
movq %r8, %rdi
cmpl $0x40, %esi
je 0x2be3f
movl (%rbp,%rsi,4), %r9d
leaq -0x1(%rdi), %r8
incq %rsi
cmpl %r12d, %r9d
jg 0x2be01
addl %edx, %edi
addl %r15d, %r9d
cmpl %r9d, %edi
jle 0x2be01
addq %r8, %rcx
movl $0x3f, %eax
subq %rcx, %rax
cmpq $0x3f, %rax
setge %bl
jmp 0x2be4c
movq 0x28(%rsp), %r12
jmp 0x2be49
subq %rdi, %rax
cmpq $0x3f, %rax
setge %bl
incl %r14d
movl $0x100, %esi            # imm = 0x100
movq %rbp, %rdi
callq 0x63c0
testb %bl, %bl
je 0x2be72
movq 0x8(%rsp), %r11
cmpl %r11d, %r14d
jle 0x2bd3c
movq 0x20(%rsp), %r13
jmp 0x2be7c
movq 0x20(%rsp), %r13
movq 0x8(%rsp), %r11
movq 0x18(%rsp), %rbx
movq %r11, %rbp
movl %r11d, %eax
subl %r14d, %eax
jge 0x2beb6
movq 0x100(%rsp), %rax
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
movl %ecx, (%rax)
movq 0xf8(%rsp), %rax
movl %ecx, (%rax)
movq 0x10(%rsp), %rdi
callq 0x64f0
xorl %eax, %eax
jmp 0x2bffd
cmpb $0x0, 0x108(%rsp)
je 0x2bf3f
movq %rbp, %r15
movslq %r14d, %r9
leaq (%r9,%r9,2), %rcx
movq 0x10(%rsp), %rdx
leaq (%rdx,%rcx,8), %rcx
movq 0x110(%rsp), %rdx
movq (%rdx), %r10
movq 0x18(%r10), %rdx
movq 0x20(%r10), %rsi
movq 0x60(%rsp), %rdi
addq %r9, %rdi
shlq $0x3, %rdi
movq (%r10), %r8
addq %rdi, %r8
addq 0x8(%r10), %rdi
movq 0x68(%rsp), %r11
leaq (%r11,%r9,4), %r9
addq 0x10(%r10), %r9
leal 0x1(%rax), %r10d
xorl %r11d, %r11d
movq (%rcx), %rbx
movq %rbx, (%r8,%r11,8)
movq 0x8(%rcx), %rbx
movq %rbx, (%rdi,%r11,8)
movl 0x10(%rcx), %ebx
movl %ebx, (%r9,%r11,4)
movq 0x18(%rsp), %rbx
movl %r14d, (%rdx,%rbx,4)
movl %r15d, (%rsi,%rbx,4)
incq %r11
addq $0x18, %rcx
cmpl %r11d, %r10d
jne 0x2bf10
movl 0x118(%rsp), %ecx
cmpq %rcx, %rbx
jne 0x2bff3
movq %rbp, %rbx
cmpl %ebx, %r14d
jg 0x2bfc1
movq 0x110(%rsp), %rcx
movq (%rcx), %r10
movq 0x18(%r10), %rcx
movq 0x20(%r10), %rdx
movslq %r14d, %rsi
leaq (%rsi,%rsi,2), %rdi
movq 0x70(%rsp), %r8
leaq (%r8,%rdi,8), %rdi
leaq (,%rsi,8), %r8
movq (%r10), %r9
addq %r8, %r9
addq 0x8(%r10), %r8
shlq $0x2, %rsi
addq 0x10(%r10), %rsi
incl %eax
xorl %r10d, %r10d
movq -0x10(%rdi), %r11
movq %r11, (%r9,%r10,8)
movq -0x8(%rdi), %r11
movq %r11, (%r8,%r10,8)
movl (%rdi), %r11d
movl %r11d, (%rsi,%r10,4)
movl %r14d, (%rcx)
movl %ebx, (%rdx)
addq $0x18, %rdi
incq %r10
cmpl %r10d, %eax
jne 0x2bf99
movq 0xf8(%rsp), %rax
movl $0xffffffff, (%rax)     # imm = 0xFFFFFFFF
movq 0x100(%rsp), %rax
movl 0x118(%rsp), %ecx
movl %ecx, (%rax)
movq 0x10(%rsp), %rdi
callq 0x64f0
xorl %eax, %eax
movq 0x18(%rsp), %rbx
jmp 0x2bffd
incq 0x88(%rsp)
movb $0x1, %al
testb %al, %al
je 0x2c04e
incq %rbx
movq 0xa8(%rsp), %rcx
cmpq %rcx, %rbx
setb %dil
movq 0x60(%rsp), %rdx
addq 0x78(%rsp), %rdx
movq %rdx, 0x60(%rsp)
movq 0x68(%rsp), %rdx
addq 0xa0(%rsp), %rdx
movq %rdx, 0x68(%rsp)
cmpq %rcx, %rbx
movq %rbp, %r9
movq 0x38(%rsp), %rsi
jne 0x2b8b9
jmp 0x2c056
movq 0x20(%rsp), %r13
jmp 0x2c056
movq %rbp, %r9
movb 0x7(%rsp), %dil
xorl %eax, %eax
testb $0x1, %dil
jne 0x2c14d
decl %r13d
cmpl %r13d, %r9d
jne 0x2c109
movq %r12, 0x28(%rsp)
movabsq $-0x8000000000000000, %rbx # imm = 0x8000000000000000
movslq %r9d, %rax
leaq (%rax,%rax,2), %rax
movq 0x10(%rsp), %rcx
movq (%rcx,%rax,8), %r15
movq 0x8(%rcx,%rax,8), %r13
movl 0x10(%rcx,%rax,8), %r12d
movl $0x100, %edi            # imm = 0x100
callq 0x63b0
movq %rax, %r14
xorl %ebp, %ebp
movl $0x100, %edx            # imm = 0x100
movq %rax, %rdi
xorl %esi, %esi
callq 0x6240
movl %r12d, (%r14,%rbp,4)
movq %rbx, %rax
andq %r15, %rax
cmpq $0x1, %rax
adcl $-0x1, %r12d
movq %rbx, %rax
andq %r13, %rax
cmpq $0x1, %rax
sbbl $-0x1, %r12d
shrq %rbx
incq %rbp
cmpq $0x3f, %rbp
jne 0x2c0b5
movl %r12d, 0xfc(%r14)
movslq 0x30(%rsp), %rax
movl (%r14,%rax,4), %ebx
movl $0x100, %esi            # imm = 0x100
movq %r14, %rdi
callq 0x63c0
cmpl 0x28(%rsp), %ebx
movq 0x38(%rsp), %rax
jle 0x2c12b
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq 0x100(%rsp), %rcx
movl %eax, (%rcx)
movq 0xf8(%rsp), %rcx
movl %eax, (%rcx)
jmp 0x2c141
xorl %ebp, %ebp
jmp 0x2b816
movq 0xf8(%rsp), %rcx
movl %ebx, (%rcx)
decl %eax
movq 0x100(%rsp), %rcx
movl %eax, (%rcx)
movq 0x10(%rsp), %rdi
callq 0x64f0
xorl %eax, %eax
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2c161
movq %rax, %rbx
movl $0x28, %esi
movq %rbp, %rdi
callq 0x63c0
movq %rbx, %rdi
callq 0x6660