// File: VanAndelInstitute[P]intent/src/edlib.cpp
// Function: obtainAlignmentTraceback(int, int, int, AlignmentData const*, unsigned char**, int*)
static int obtainAlignmentTraceback(const int queryLength, const int targetLength,
                                    const int bestScore, const AlignmentData* const alignData,
                                    unsigned char** const alignment, int* const alignmentLength) {
    const int maxNumBlocks = ceilDiv(queryLength, WORD_SIZE);
    const int W = maxNumBlocks * WORD_SIZE - queryLength;

    *alignment = static_cast<unsigned char*>(malloc((queryLength + targetLength - 1) * sizeof(unsigned char)));
    *alignmentLength = 0;
    int c = targetLength - 1; // index of column
    int b = maxNumBlocks - 1; // index of block in column
    int currScore = bestScore; // Score of current cell
    int lScore  = -1; // Score of left cell
    int uScore  = -1; // Score of upper cell
    int ulScore = -1; // Score of upper left cell
    Word currP = alignData->Ps[c * maxNumBlocks + b]; // P of current block
    Word currM = alignData->Ms[c * maxNumBlocks + b]; // M of current block
    // True if block to left exists and is in band
    bool thereIsLeftBlock = c > 0 && b >= alignData->firstBlocks[c-1] && b <= alignData->lastBlocks[c-1];
    // We set initial values of lP and lM to 0 only to avoid compiler warnings, they should not affect the
    // calculation as both lP and lM should be initialized at some moment later (but compiler can not
    // detect it since this initialization is guaranteed by "business" logic).
    Word lP = 0, lM = 0;
    if (thereIsLeftBlock) {
        lP = alignData->Ps[(c - 1) * maxNumBlocks + b]; // P of block to the left
        lM = alignData->Ms[(c - 1) * maxNumBlocks + b]; // M of block to the left
    }
    currP <<= W;
    currM <<= W;
    int blockPos = WORD_SIZE - W - 1; // 0 based index of current cell in blockPos

    // TODO(martin): refactor this whole piece of code. There are too many if-else statements,
    // it is too easy for a bug to hide and to hard to effectively cover all the edge-cases.
    // We need better separation of logic and responsibilities.
    while (true) {
        if (c == 0) {
            thereIsLeftBlock = true;
            lScore = b * WORD_SIZE + blockPos + 1;
            ulScore = lScore - 1;
        }

        // TODO: improvement: calculate only those cells that are needed,
        //       for example if I calculate upper cell and can move up,
        //       there is no need to calculate left and upper left cell
        //---------- Calculate scores ---------//
        if (lScore == -1 && thereIsLeftBlock) {
            lScore = alignData->scores[(c - 1) * maxNumBlocks + b]; // score of block to the left
            for (int i = 0; i < WORD_SIZE - blockPos - 1; i++) {
                if (lP & HIGH_BIT_MASK) lScore--;
                if (lM & HIGH_BIT_MASK) lScore++;
                lP <<= 1;
                lM <<= 1;
            }
        }
        if (ulScore == -1) {
            if (lScore != -1) {
                ulScore = lScore;
                if (lP & HIGH_BIT_MASK) ulScore--;
                if (lM & HIGH_BIT_MASK) ulScore++;
            }
            else if (c > 0 && b-1 >= alignData->firstBlocks[c-1] && b-1 <= alignData->lastBlocks[c-1]) {
                // This is the case when upper left cell is last cell in block,
                // and block to left is not in band so lScore is -1.
                ulScore = alignData->scores[(c - 1) * maxNumBlocks + b - 1];
            }
        }
        if (uScore == -1) {
            uScore = currScore;
            if (currP & HIGH_BIT_MASK) uScore--;
            if (currM & HIGH_BIT_MASK) uScore++;
            currP <<= 1;
            currM <<= 1;
        }
        //-------------------------------------//

        // TODO: should I check if there is upper block?

        //-------------- Move --------------//
        // Move up - insertion to target - deletion from query
        if (uScore != -1 && uScore + 1 == currScore) {
            currScore = uScore;
            lScore = ulScore;
            uScore = ulScore = -1;
            if (blockPos == 0) { // If entering new (upper) block
                if (b == 0) { // If there are no cells above (only boundary cells)
                    (*alignment)[(*alignmentLength)++] = EDLIB_EDOP_INSERT; // Move up
                    for (int i = 0; i < c + 1; i++) // Move left until end
                        (*alignment)[(*alignmentLength)++] = EDLIB_EDOP_DELETE;
                    break;
                } else {
                    blockPos = WORD_SIZE - 1;
                    b--;
                    currP = alignData->Ps[c * maxNumBlocks + b];
                    currM = alignData->Ms[c * maxNumBlocks + b];
                    if (c > 0 && b >= alignData->firstBlocks[c-1] && b <= alignData->lastBlocks[c-1]) {
                        thereIsLeftBlock = true;
                        lP = alignData->Ps[(c - 1) * maxNumBlocks + b]; // TODO: improve this, too many operations
                        lM = alignData->Ms[(c - 1) * maxNumBlocks + b];
                    } else {
                        thereIsLeftBlock = false;
                        // TODO(martin): There may not be left block, but there can be left boundary - do we
                        // handle this correctly then? Are l and ul score set correctly? I should check that / refactor this.
                    }
                }
            } else {
                blockPos--;
                lP <<= 1;
                lM <<= 1;
            }
            // Mark move
            (*alignment)[(*alignmentLength)++] = EDLIB_EDOP_INSERT;
        }
        // Move left - deletion from target - insertion to query
        else if (lScore != -1 && lScore + 1 == currScore) {
            currScore = lScore;
            uScore = ulScore;
            lScore = ulScore = -1;
            c--;
            if (c == -1) { // If there are no cells to the left (only boundary cells)
                (*alignment)[(*alignmentLength)++] = EDLIB_EDOP_DELETE; // Move left
                int numUp = b * WORD_SIZE + blockPos + 1;
                for (int i = 0; i < numUp; i++) // Move up until end
                    (*alignment)[(*alignmentLength)++] = EDLIB_EDOP_INSERT;
                break;
            }
            currP = lP;
            currM = lM;
            if (c > 0 && b >= alignData->firstBlocks[c-1] && b <= alignData->lastBlocks[c-1]) {
                thereIsLeftBlock = true;
                lP = alignData->Ps[(c - 1) * maxNumBlocks + b];
                lM = alignData->Ms[(c - 1) * maxNumBlocks + b];
            } else {
                if (c == 0) { // If there are no cells to the left (only boundary cells)
                    thereIsLeftBlock = true;
                    lScore = b * WORD_SIZE + blockPos + 1;
                    ulScore = lScore - 1;
                } else {
                    thereIsLeftBlock = false;
                }
            }
            // Mark move
            (*alignment)[(*alignmentLength)++] = EDLIB_EDOP_DELETE;
        }
        // Move up left - (mis)match
        else if (ulScore != -1) {
            unsigned char moveCode = ulScore == currScore ? EDLIB_EDOP_MATCH : EDLIB_EDOP_MISMATCH;
            currScore = ulScore;
            uScore = lScore = ulScore = -1;
            c--;
            if (c == -1) { // If there are no cells to the left (only boundary cells)
                (*alignment)[(*alignmentLength)++] = moveCode; // Move left
                int numUp = b * WORD_SIZE + blockPos;
                for (int i = 0; i < numUp; i++) // Move up until end
                    (*alignment)[(*alignmentLength)++] = EDLIB_EDOP_INSERT;
                break;
            }
            if (blockPos == 0) { // If entering upper left block
                if (b == 0) { // If there are no more cells above (only boundary cells)
                    (*alignment)[(*alignmentLength)++] = moveCode; // Move up left
                    for (int i = 0; i < c + 1; i++) // Move left until end
                        (*alignment)[(*alignmentLength)++] = EDLIB_EDOP_DELETE;
                    break;
                }
                blockPos = WORD_SIZE - 1;
                b--;
                currP = alignData->Ps[c * maxNumBlocks + b];
                currM = alignData->Ms[c * maxNumBlocks + b];
            } else { // If entering left block
                blockPos--;
                currP = lP;
                currM = lM;
                currP <<= 1;
                currM <<= 1;
            }
            // Set new left block
            if (c > 0 && b >= alignData->firstBlocks[c-1] && b <= alignData->lastBlocks[c-1]) {
                thereIsLeftBlock = true;
                lP = alignData->Ps[(c - 1) * maxNumBlocks + b];
                lM = alignData->Ms[(c - 1) * maxNumBlocks + b];
            } else {
                if (c == 0) { // If there are no cells to the left (only boundary cells)
                    thereIsLeftBlock = true;
                    lScore = b * WORD_SIZE + blockPos + 1;
                    ulScore = lScore - 1;
                } else {
                    thereIsLeftBlock = false;
                }
            }
            // Mark move
            (*alignment)[(*alignmentLength)++] = moveCode;
        } else {
            // Reached end - finished!
            break;
        }
        //----------------------------------//
    }

    *alignment = static_cast<unsigned char*>(realloc(*alignment, (*alignmentLength) * sizeof(unsigned char)));
    reverse(*alignment, *alignment + (*alignmentLength));
    return EDLIB_STATUS_OK;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movl %edi, -0x4(%rbp)
movl %esi, -0x8(%rbp)
movl %edx, -0xc(%rbp)
movq %rcx, -0x18(%rbp)
movq %r8, -0x20(%rbp)
movq %r9, -0x28(%rbp)
movl -0x4(%rbp), %edi
movl $0x40, %esi
callq 0x655f0
movl %eax, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
shll $0x6, %eax
subl -0x4(%rbp), %eax
movl %eax, -0x30(%rbp)
movl -0x4(%rbp), %eax
addl -0x8(%rbp), %eax
subl $0x1, %eax
movslq %eax, %rdi
shlq $0x0, %rdi
callq 0x8770
movq %rax, %rcx
movq -0x20(%rbp), %rax
movq %rcx, (%rax)
movq -0x28(%rbp), %rax
movl $0x0, (%rax)
movl -0x8(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x34(%rbp)
movl -0x2c(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x38(%rbp)
movl -0xc(%rbp), %eax
movl %eax, -0x3c(%rbp)
movl $0xffffffff, -0x40(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, -0x44(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, -0x48(%rbp) # imm = 0xFFFFFFFF
movq -0x18(%rbp), %rax
movq (%rax), %rax
movl -0x34(%rbp), %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x50(%rbp)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movl -0x34(%rbp), %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x58(%rbp)
xorl %eax, %eax
cmpl $0x0, -0x34(%rbp)
movb %al, -0x95(%rbp)
jle 0x6791a
movl -0x38(%rbp), %ecx
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rdx
movl -0x34(%rbp), %eax
subl $0x1, %eax
movslq %eax, %rsi
xorl %eax, %eax
cmpl (%rdx,%rsi,4), %ecx
movb %al, -0x95(%rbp)
jl 0x6791a
movl -0x38(%rbp), %eax
movq -0x18(%rbp), %rcx
movq 0x20(%rcx), %rcx
movl -0x34(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
cmpl (%rcx,%rdx,4), %eax
setle %al
movb %al, -0x95(%rbp)
movb -0x95(%rbp), %al
andb $0x1, %al
movb %al, -0x59(%rbp)
movq $0x0, -0x68(%rbp)
movq $0x0, -0x70(%rbp)
testb $0x1, -0x59(%rbp)
je 0x6797a
movq -0x18(%rbp), %rax
movq (%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x68(%rbp)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x70(%rbp)
movl -0x30(%rbp), %ecx
movq -0x50(%rbp), %rax
movl %ecx, %ecx
shlq %cl, %rax
movq %rax, -0x50(%rbp)
movl -0x30(%rbp), %ecx
movq -0x58(%rbp), %rax
movl %ecx, %ecx
shlq %cl, %rax
movq %rax, -0x58(%rbp)
movl $0x40, %eax
subl -0x30(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x74(%rbp)
cmpl $0x0, -0x34(%rbp)
jne 0x679ca
movb $0x1, -0x59(%rbp)
movl -0x38(%rbp), %eax
shll $0x6, %eax
addl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x40(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x48(%rbp)
cmpl $-0x1, -0x40(%rbp)
jne 0x67a72
testb $0x1, -0x59(%rbp)
je 0x67a72
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x40(%rbp)
movl $0x0, -0x78(%rbp)
movl -0x78(%rbp), %eax
movl $0x40, %ecx
subl -0x74(%rbp), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jge 0x67a70
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
andq -0x68(%rbp), %rax
cmpq $0x0, %rax
je 0x67a32
movl -0x40(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x40(%rbp)
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
andq -0x70(%rbp), %rax
cmpq $0x0, %rax
je 0x67a4f
movl -0x40(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movq -0x68(%rbp), %rax
shlq %rax
movq %rax, -0x68(%rbp)
movq -0x70(%rbp), %rax
shlq %rax
movq %rax, -0x70(%rbp)
movl -0x78(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x78(%rbp)
jmp 0x67a03
jmp 0x67a72
cmpl $-0x1, -0x48(%rbp)
jne 0x67b27
cmpl $-0x1, -0x40(%rbp)
je 0x67ac4
movl -0x40(%rbp), %eax
movl %eax, -0x48(%rbp)
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
andq -0x68(%rbp), %rax
cmpq $0x0, %rax
je 0x67aa5
movl -0x48(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x48(%rbp)
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
andq -0x70(%rbp), %rax
cmpq $0x0, %rax
je 0x67ac2
movl -0x48(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x48(%rbp)
jmp 0x67b25
cmpl $0x0, -0x34(%rbp)
jle 0x67b23
movl -0x38(%rbp), %eax
subl $0x1, %eax
movq -0x18(%rbp), %rcx
movq 0x18(%rcx), %rcx
movl -0x34(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
cmpl (%rcx,%rdx,4), %eax
jl 0x67b23
movl -0x38(%rbp), %eax
subl $0x1, %eax
movq -0x18(%rbp), %rcx
movq 0x20(%rcx), %rcx
movl -0x34(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
cmpl (%rcx,%rdx,4), %eax
jg 0x67b23
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x48(%rbp)
jmp 0x67b25
jmp 0x67b27
cmpl $-0x1, -0x44(%rbp)
jne 0x67b83
movl -0x3c(%rbp), %eax
movl %eax, -0x44(%rbp)
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
andq -0x50(%rbp), %rax
cmpq $0x0, %rax
je 0x67b50
movl -0x44(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x44(%rbp)
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
andq -0x58(%rbp), %rax
cmpq $0x0, %rax
je 0x67b6d
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
movq -0x50(%rbp), %rax
shlq %rax
movq %rax, -0x50(%rbp)
movq -0x58(%rbp), %rax
shlq %rax
movq %rax, -0x58(%rbp)
cmpl $-0x1, -0x44(%rbp)
je 0x67d2d
movl -0x44(%rbp), %eax
addl $0x1, %eax
cmpl -0x3c(%rbp), %eax
jne 0x67d2d
movl -0x44(%rbp), %eax
movl %eax, -0x3c(%rbp)
movl -0x48(%rbp), %eax
movl %eax, -0x40(%rbp)
movl $0xffffffff, -0x48(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, -0x44(%rbp) # imm = 0xFFFFFFFF
cmpl $0x0, -0x74(%rbp)
jne 0x67cee
cmpl $0x0, -0x38(%rbp)
jne 0x67c20
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rdx
movl (%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, (%rdx)
movslq %ecx, %rcx
movb $0x1, (%rax,%rcx)
movl $0x0, -0x7c(%rbp)
movl -0x7c(%rbp), %eax
movl -0x34(%rbp), %ecx
addl $0x1, %ecx
cmpl %ecx, %eax
jge 0x67c1b
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rdx
movl (%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, (%rdx)
movslq %ecx, %rcx
movb $0x2, (%rax,%rcx)
movl -0x7c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x7c(%rbp)
jmp 0x67be8
jmp 0x68143
movl $0x3f, -0x74(%rbp)
movl -0x38(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x38(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
movl -0x34(%rbp), %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x50(%rbp)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movl -0x34(%rbp), %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x58(%rbp)
cmpl $0x0, -0x34(%rbp)
jle 0x67ce6
movl -0x38(%rbp), %eax
movq -0x18(%rbp), %rcx
movq 0x18(%rcx), %rcx
movl -0x34(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
cmpl (%rcx,%rdx,4), %eax
jl 0x67ce6
movl -0x38(%rbp), %eax
movq -0x18(%rbp), %rcx
movq 0x20(%rcx), %rcx
movl -0x34(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
cmpl (%rcx,%rdx,4), %eax
jg 0x67ce6
movb $0x1, -0x59(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x68(%rbp)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x70(%rbp)
jmp 0x67cea
movb $0x0, -0x59(%rbp)
jmp 0x67cec
jmp 0x67d0d
movl -0x74(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x74(%rbp)
movq -0x68(%rbp), %rax
shlq %rax
movq %rax, -0x68(%rbp)
movq -0x70(%rbp), %rax
shlq %rax
movq %rax, -0x70(%rbp)
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rdx
movl (%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, (%rdx)
movslq %ecx, %rcx
movb $0x1, (%rax,%rcx)
jmp 0x6813e
cmpl $-0x1, -0x40(%rbp)
je 0x67eb6
movl -0x40(%rbp), %eax
addl $0x1, %eax
cmpl -0x3c(%rbp), %eax
jne 0x67eb6
movl -0x40(%rbp), %eax
movl %eax, -0x3c(%rbp)
movl -0x48(%rbp), %eax
movl %eax, -0x44(%rbp)
movl $0xffffffff, -0x48(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, -0x40(%rbp) # imm = 0xFFFFFFFF
movl -0x34(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x34(%rbp)
cmpl $-0x1, -0x34(%rbp)
jne 0x67ddf
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rdx
movl (%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, (%rdx)
movslq %ecx, %rcx
movb $0x2, (%rax,%rcx)
movl -0x38(%rbp), %eax
shll $0x6, %eax
addl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x80(%rbp)
movl $0x0, -0x84(%rbp)
movl -0x84(%rbp), %eax
cmpl -0x80(%rbp), %eax
jge 0x67dda
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rdx
movl (%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, (%rdx)
movslq %ecx, %rcx
movb $0x1, (%rax,%rcx)
movl -0x84(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x84(%rbp)
jmp 0x67da3
jmp 0x68143
movq -0x68(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0x58(%rbp)
cmpl $0x0, -0x34(%rbp)
jle 0x67e6c
movl -0x38(%rbp), %eax
movq -0x18(%rbp), %rcx
movq 0x18(%rcx), %rcx
movl -0x34(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
cmpl (%rcx,%rdx,4), %eax
jl 0x67e6c
movl -0x38(%rbp), %eax
movq -0x18(%rbp), %rcx
movq 0x20(%rcx), %rcx
movl -0x34(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
cmpl (%rcx,%rdx,4), %eax
jg 0x67e6c
movb $0x1, -0x59(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x68(%rbp)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x70(%rbp)
jmp 0x67e96
cmpl $0x0, -0x34(%rbp)
jne 0x67e90
movb $0x1, -0x59(%rbp)
movl -0x38(%rbp), %eax
shll $0x6, %eax
addl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x40(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x48(%rbp)
jmp 0x67e94
movb $0x0, -0x59(%rbp)
jmp 0x67e96
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rdx
movl (%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, (%rdx)
movslq %ecx, %rcx
movb $0x2, (%rax,%rcx)
jmp 0x6813c
cmpl $-0x1, -0x48(%rbp)
je 0x68138
movl -0x48(%rbp), %edx
movl -0x3c(%rbp), %esi
movl $0x3, %eax
xorl %ecx, %ecx
cmpl %esi, %edx
cmovel %ecx, %eax
movb %al, -0x85(%rbp)
movl -0x48(%rbp), %eax
movl %eax, -0x3c(%rbp)
movl $0xffffffff, -0x48(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, -0x40(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, -0x44(%rbp) # imm = 0xFFFFFFFF
movl -0x34(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x34(%rbp)
cmpl $-0x1, -0x34(%rbp)
jne 0x67f7a
movb -0x85(%rbp), %dl
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rsi
movl (%rsi), %ecx
movl %ecx, %edi
addl $0x1, %edi
movl %edi, (%rsi)
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x38(%rbp), %eax
shll $0x6, %eax
addl -0x74(%rbp), %eax
movl %eax, -0x8c(%rbp)
movl $0x0, -0x90(%rbp)
movl -0x90(%rbp), %eax
cmpl -0x8c(%rbp), %eax
jge 0x67f75
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rdx
movl (%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, (%rdx)
movslq %ecx, %rcx
movb $0x1, (%rax,%rcx)
movl -0x90(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x90(%rbp)
jmp 0x67f3b
jmp 0x68143
cmpl $0x0, -0x74(%rbp)
jne 0x68040
cmpl $0x0, -0x38(%rbp)
jne 0x67ff5
movb -0x85(%rbp), %dl
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rsi
movl (%rsi), %ecx
movl %ecx, %edi
addl $0x1, %edi
movl %edi, (%rsi)
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl $0x0, -0x94(%rbp)
movl -0x94(%rbp), %eax
movl -0x34(%rbp), %ecx
addl $0x1, %ecx
cmpl %ecx, %eax
jge 0x67ff0
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rdx
movl (%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, (%rdx)
movslq %ecx, %rcx
movb $0x2, (%rax,%rcx)
movl -0x94(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x94(%rbp)
jmp 0x67fb4
jmp 0x68143
movl $0x3f, -0x74(%rbp)
movl -0x38(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x38(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
movl -0x34(%rbp), %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x50(%rbp)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movl -0x34(%rbp), %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x58(%rbp)
jmp 0x6806f
movl -0x74(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x74(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x50(%rbp), %rax
shlq %rax
movq %rax, -0x50(%rbp)
movq -0x58(%rbp), %rax
shlq %rax
movq %rax, -0x58(%rbp)
cmpl $0x0, -0x34(%rbp)
jle 0x680ec
movl -0x38(%rbp), %eax
movq -0x18(%rbp), %rcx
movq 0x18(%rcx), %rcx
movl -0x34(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
cmpl (%rcx,%rdx,4), %eax
jl 0x680ec
movl -0x38(%rbp), %eax
movq -0x18(%rbp), %rcx
movq 0x20(%rcx), %rcx
movl -0x34(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
cmpl (%rcx,%rdx,4), %eax
jg 0x680ec
movb $0x1, -0x59(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x68(%rbp)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movl -0x34(%rbp), %ecx
subl $0x1, %ecx
imull -0x2c(%rbp), %ecx
addl -0x38(%rbp), %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x70(%rbp)
jmp 0x68116
cmpl $0x0, -0x34(%rbp)
jne 0x68110
movb $0x1, -0x59(%rbp)
movl -0x38(%rbp), %eax
shll $0x6, %eax
addl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x40(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x48(%rbp)
jmp 0x68114
movb $0x0, -0x59(%rbp)
jmp 0x68116
movb -0x85(%rbp), %dl
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq -0x28(%rbp), %rsi
movl (%rsi), %ecx
movl %ecx, %edi
addl $0x1, %edi
movl %edi, (%rsi)
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
jmp 0x6813a
jmp 0x68143
jmp 0x6813c
jmp 0x6813e
jmp 0x679a8
movq -0x20(%rbp), %rax
movq (%rax), %rdi
movq -0x28(%rbp), %rax
movslq (%rax), %rsi
shlq $0x0, %rsi
callq 0x88d0
movq %rax, %rcx
movq -0x20(%rbp), %rax
movq %rcx, (%rax)
movq -0x20(%rbp), %rax
movq (%rax), %rdi
movq -0x20(%rbp), %rax
movq (%rax), %rsi
movq -0x28(%rbp), %rax
movslq (%rax), %rax
addq %rax, %rsi
callq 0x6a050
xorl %eax, %eax
addq $0xa0, %rsp
popq %rbp
retq
nopl (%rax)