// File: /workspace/github_cpp_makefile_star2_O3/garrettsickles[P]hgt2png/hgt2png.cpp
// Function: main
int main(int argc, char** argv)
{
    /*
     * Arguement Parsing
     */
    if (argc < 6 || argc > 8 || argc == 7)
    {
        std::printf(HGT2PNG_USAGE_TEXT);
        std::printf("%d\n", argc);
        return 0;
    }

    const auto width = std::atoi(argv[4]);
    const auto height = std::atoi(argv[5]);
    const auto rows = argc == 8 ? std::atoi(argv[6]) : 1;
    const auto cols = argc == 8 ? std::atoi(argv[7]) : 1;
    const auto pixel_count = static_cast<std::size_t>(width * height);

    /*
     * Read in the HGT (.hgt) file
     * 
     * Check that the file opened properly
     */
    char* hgt_filename = argv[2];
    CFile hgt_file = CFile(std::fopen(hgt_filename, "rb"), [](FILE* f)->void { std::fclose(f); });
    if (!hgt_file.get())
    {
        std::printf("Could not open file \"%s\", Exiting...\n", hgt_filename);
        return 1;
    }

    /*
     * Extract the number of samples in the HGT raster
     */
    FSEEK64(hgt_file.get(), 0, SEEK_END);
    const auto hgt_size = FTELL64(hgt_file.get());
    FSEEK64(hgt_file.get(), 0, SEEK_SET);
    std::printf
    (
        "File: \"%s\" (%" PRId64 " bytes)\nSize: %d(w) x %d(h) pixels (%lu samples)\n",
        hgt_filename, hgt_size, width, height, pixel_count
    );

    /*
     * Verify the subdivisions
     */
    if (cols < 1 || rows < 1)
    {
        std::printf("Both row and column must be greater than or equal to 1, Exiting...\n");
        return 1;
    }
    if (cols > 1 && (width - 1) % cols)
    {
        std::printf("One less than the width of %d is not evenly divisible by %d, Exiting...\n", width, cols);
        return 1;
    }
    if (rows > 1 && (height - 1) % rows)
    {
        std::printf("One less than the height of %d is not evenly divisible by %d, Exiting...\n", height, rows);
        return 1;
    }
    const auto subwidth = (width / cols) + (cols > 1 ? 1 : 0);
    const auto subheight = (height / rows) + (rows > 1 ? 1 : 0);

    /*
     * Verify the size of the HGT raster
     */
    const auto data_size   = static_cast<decltype(hgt_size)>(pixel_count * sizeof(std::int16_t));
    if (hgt_size != data_size)
    {
        std::printf("Actual size %" PRId64 ", Expected %" PRId64 ", Exiting...\n", hgt_size, data_size);
        return 1;
    }

    /*
     * Extract the location of the 1 degree raster from the filename
     */
    int  ll[2]       = { -1, -1 };
    char hemi[2]     = {  0,  0 };
    char* last_slash = std::strrchr(argv[2], DIRECTORY_DELIM);
    char* file_name  = last_slash ? last_slash + 1 : hgt_filename;
    std::sscanf(file_name, "%c%2d%c%3d.hgt", &hemi[0], &ll[0], &hemi[1], &ll[1]);
    std::string base_name = std::string(argv[3]) + file_name;
    base_name.erase(base_name.find_last_of("."), std::string::npos);
    
    /*
     * Verify the filename raster coordinates
     */
    const bool valid_hemi[2] = { hemi[0] == 'N' || hemi[0] == 'S', hemi[1] == 'W' || hemi[1] == 'E' };
    if (!valid_hemi[0] || !valid_hemi[1])
    {
        std::printf("Inavlid hemisphere \"%c\" in \"%s\", Exiting...\n", valid_hemi[0] ? hemi[1] : hemi[0], file_name);
        return 1;
    }
    std::printf("Bounds: (%d%c, %d%c) to (%d%c, %d%c)\n",
        ll[0], hemi[0], ll[1], hemi[1], ll[0] + 1, hemi[0], ll[1] + 1, hemi[1]
    );

    /*
     * Extract the raster into memory
     */
    std::vector<std::uint8_t> raster(data_size);
    const auto read_size = std::fread(raster.data(), data_size, 1, hgt_file.get());
    if (read_size != 1)
    {
        std::printf("Read size %" PRId64 ", Expected 1, Exiting...\n", read_size);
        return 1;
    }
    
    /*
     * Swap the byte order from Big to Little Endian
     * if the platform is Little Endian
     */
    if (is_little_endian())
    {
        std::uint8_t swp = 0;
        for (auto i = 0; i < data_size; i += sizeof(std::int16_t))
        {
            swp = raster[i];
            raster[i] = raster[i+1];
            raster[i+1] = swp;
        }
    }

    /*
     * Convert the raster to unsigned 16 bit and
     * accumulate the range of the raster
     */
    int minimum = 32768;
    int maximum = -32768;
    int invalid = 0;

    std::int32_t temp;
    std::int16_t* svalue = nullptr;
    for (auto i = 0; i < data_size; i += sizeof(std::int16_t))
    {
        svalue = reinterpret_cast<std::int16_t*>(raster.data() + i);
        temp = static_cast<std::int32_t>(*svalue);
        if (temp < minimum)
        {
            if (temp != -32768) minimum = temp;
            else invalid++;
        } 
        else if (temp > maximum)
        {
            maximum = temp;
        }
    }
    std::printf("Range: [%d, %d] meters\nMissing: %d pixels\n", minimum, maximum, invalid);

    /*
     *
     */
    double toscale = 0.0;
    const double minf = static_cast<double>(minimum);
    const double deltaf = static_cast<double>(maximum) - minf;

    /*
     * Absolute Mode
     */
    if (argv[1][0] == 'a')
    {
        std::uint16_t* uvalue = nullptr;
        for (auto i = 0; i < data_size; i += sizeof(std::int16_t))
        {
            svalue = reinterpret_cast<std::int16_t*>(raster.data() + i);
            uvalue = reinterpret_cast<std::uint16_t*>(raster.data() + i);
            *uvalue = *svalue == -32768 ? 0xFFFF : static_cast<std::uint16_t>(static_cast<double>(*svalue) + 32767.0);
        }
    }

    /*
     * Relative Mode, By default('r')
     */
    else
    {
        /*
         * Scale the raster to the range such that the minimum height
         * encodes to 0 and the maximum height encodes to 65534
         */
        svalue = nullptr;
        std::uint16_t* uvalue = nullptr;
        for (auto i = 0; i < data_size; i += sizeof(std::int16_t))
        {
            svalue = reinterpret_cast<std::int16_t*>(raster.data() + i);
            uvalue = reinterpret_cast<std::uint16_t*>(raster.data() + i);
            toscale = static_cast<double>(*svalue);
            *uvalue = *svalue == -32768 ? 0xFFFF : static_cast<std::uint16_t>((toscale - minf) * 65534.0 / deltaf);
        }
    }

    /*
     * Swap the byte order from Little to Big Endian
     * if the platform is Little Endian
     */
    if (is_little_endian())
    {
        std::uint8_t swp = 0;
        for (auto i = 0; i < data_size; i += sizeof(std::int16_t))
        {
            swp = raster[i];
            raster[i] = raster[i+1];
            raster[i+1] = swp;
        }
    }

    /*
     * Calculate the physical dimensions of each subraster in radians
     */
    const double upx = deg_to_rad(1.0 / static_cast<double>(subwidth - 1));
    const double upy = deg_to_rad(1.0 / static_cast<double>(subheight - 1));

    /*
     * Write the PNG to a data buffer
     */
    std::vector<std::uint8_t> png_data;
    std::vector<std::uint8_t*> png_rows(subheight);
    size_t total_png_size = 0;

    int row_offset = 0;
    int col_offset = 0;
    for (auto row_index = 0; row_index < rows; row_index++)
    {
        for (auto col_index = 0; col_index < cols; col_index++)
        {
            /*
             * Setup the PNG info
             */
            png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
            png_infop   info = png_create_info_struct(png);
            png_set_IHDR(png, info,
                static_cast<png_uint_32>(subwidth),
                static_cast<png_uint_32>(subheight),
                sizeof(std::uint16_t) * 8,
                PNG_COLOR_TYPE_GRAY,
                PNG_INTERLACE_NONE,
                PNG_COMPRESSION_TYPE_DEFAULT,
                PNG_FILTER_TYPE_DEFAULT
            );

            /*
             * Set the 'sCAL' (Physical Scale)
             * 
             * The dimensions of each pixel in radians
             */
            png_set_sCAL(png, info, 2, upx, upy);

            /*
             * Set the 'pCAL' (Pixel Calibration)
             * 
             * The 1st order function mapping the encoded PNG values to the physical values
             */
            auto decription = std::string("SRTM-HGT");
            auto units = std::string("m");
            auto p0 = std::to_string(minf);
            auto p1 = std::to_string(deltaf);
            png_charp params[2] = { &p0.at(0), &p1.at(0)};
            png_set_pCAL(png, info, &decription.at(0), -32767, 32767, 0, 2, &units.at(0), params);

            /*
             * Setup a vector of pointers to the beginning of each row
             */
            for (auto row_abs = row_offset; row_abs < (row_offset + subheight); row_abs++)
            {
                png_rows[row_abs - row_offset] =
                    raster.data() +
                    row_abs * width * sizeof(std::uint16_t) +
                    (col_offset - 1) * sizeof(std::uint16_t);
            }
                

            /*
             * Write the PNG to a buffer
             */
            png_set_rows(png, info, png_rows.data());
            png_set_write_fn(png, &(png_data), libpng_write_stdvector, NULL);
            png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL);
            png_destroy_write_struct(&png, &info);
            const auto png_size = png_data.size();

            /*
             * Write the PNG buffer out to file
             */
            std::string subname =
                base_name + "." +
                std::to_string(row_offset) + "." + std::to_string(col_offset) + ".png";
            CFile png_file = CFile(std::fopen(subname.c_str(), "wb"), [](FILE* f)->void { std::fclose(f); });
            if (!hgt_file.get())
            {
                std::printf("Could not open file \"%s\", Exiting...\n", subname.c_str());
                return 1;
            }
            const auto write_size = std::fwrite(png_data.data(), png_data.size(), 1, png_file.get());
            png_data.clear();
            
            /*
             * Verify the file write
             */
            if (write_size != 1)
            {
                std::printf("Write size %" PRId64 ", Expected 1, Exiting...\n", write_size);
                return 1;
            }

            total_png_size += png_size;
            col_offset += (subheight - 1);      
        }
        col_offset = 0;
        row_offset += (subwidth - 1);
    }

    /*
     * Show some statistics
     */
    std::printf("Output: Compression: %.2lf%% of original size\n",
        static_cast<double>(total_png_size) / static_cast<double>(data_size) * 100.0
    );
    
    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2b8, %rsp            # imm = 0x2B8
movl %edi, %ebx
leal -0x9(%rbx), %eax
cmpl $-0x3, %eax
setae %al
cmpl $0x7, %edi
setne %cl
testb %al, %cl
jne 0x2444
leaq 0x1fb6(%rip), %rdi      # 0x43de
callq 0x21f0
leaq 0x1c1c(%rip), %rdi      # 0x4050
xorl %ebp, %ebp
movl %ebx, %esi
xorl %eax, %eax
callq 0x2030
jmp 0x26d8
movq %rsi, %rbp
movq 0x20(%rsi), %rdi
callq 0x2200
movl %eax, %r13d
movq 0x28(%rbp), %rdi
callq 0x2200
movl %eax, %r15d
movl $0x1, %r12d
movl $0x1, %r14d
cmpl $0x8, %ebx
jne 0x2488
movq 0x30(%rbp), %rdi
callq 0x2200
movl %eax, %r12d
movq 0x38(%rbp), %rdi
callq 0x2200
movl %eax, %r14d
movq %rbp, 0x8(%rsp)
movq 0x10(%rbp), %rbx
leaq 0x1bbc(%rip), %rsi      # 0x4054
movq %rbx, %rdi
callq 0x21a0
testq %rax, %rax
je 0x2556
movl %r14d, 0x1c(%rsp)
movl %r15d, %ecx
imull %r13d, %ecx
movl %ecx, 0x18(%rsp)
movl %r15d, %ebp
movslq %ecx, %r15
movl %r12d, 0x3c(%rsp)
movq %rax, %r12
movq %rax, %rdi
xorl %esi, %esi
movl $0x2, %edx
callq 0x20c0
movq %r12, %rdi
callq 0x21b0
movq %r13, %r14
movq %rax, %r13
movq %r12, 0x90(%rsp)
movq %r12, %rdi
movl 0x3c(%rsp), %r12d
xorl %esi, %esi
xorl %edx, %edx
callq 0x20c0
leaq 0x1b79(%rip), %rdi      # 0x407d
movq %rbx, 0x20(%rsp)
movq %rbx, %rsi
movq %r13, 0x1c0(%rsp)
movq %r13, %rdx
movq %r14, %r13
movl 0x1c(%rsp), %r14d
movq %r15, %rbx
movl %r13d, %ecx
movl %ebp, %r8d
movq %r15, %r9
xorl %eax, %eax
callq 0x2030
testl %r14d, %r14d
setle %al
testl %r12d, %r12d
setle %cl
orb %al, %cl
cmpb $0x1, %cl
jne 0x2571
leaq 0x1e4f(%rip), %rdi      # 0x439b
callq 0x21f0
jmp 0x26c6
leaq 0x1afa(%rip), %rdi      # 0x4057
movq %rbx, %rsi
xorl %eax, %eax
callq 0x2030
movl $0x1, %ebp
jmp 0x26d8
cmpl $0x2, %r14d
jb 0x2592
leal -0x1(%r13), %eax
cltd
idivl %r14d
testl %edx, %edx
je 0x2592
leaq 0x1b34(%rip), %rdi      # 0x40be
movl %r13d, %esi
movl %r14d, %edx
jmp 0x25b0
cmpl $0x2, %r12d
jb 0x25bc
movl %ebp, %eax
decl %eax
cltd
idivl %r12d
testl %edx, %edx
je 0x25bc
leaq 0x1b5c(%rip), %rdi      # 0x4107
movl %ebp, %esi
movl %r12d, %edx
xorl %eax, %eax
callq 0x2030
jmp 0x26c6
movl %r13d, %eax
cltd
movl 0x1c(%rsp), %ecx
idivl %ecx
cmpl $0x2, %ecx
sbbl $-0x1, %eax
movq %rax, 0x1b8(%rsp)
movl %ebp, %eax
cltd
idivl %r12d
cmpl $0x2, %r12d
sbbl $-0x1, %eax
addq %rbx, %rbx
movq 0x1c0(%rsp), %r14
cmpq %rbx, %r14
jne 0x26b2
movq %rax, 0x1a0(%rsp)
leaq 0xd4(%rsp), %rbp
movq $-0x1, -0x4(%rbp)
leaq 0x7(%rsp), %rbx
movw $0x0, -0x1(%rbx)
movq 0x8(%rsp), %r12
movq 0x10(%r12), %rdi
movl $0x2f, %esi
callq 0x2170
leaq 0x1(%rax), %r15
testq %rax, %rax
cmoveq 0x20(%rsp), %r15
leaq 0x1b3c(%rip), %rsi      # 0x417c
leaq 0x6(%rsp), %rdx
leaq 0xd0(%rsp), %rcx
movq %r15, %rdi
movq %rbx, %r8
movq %rbp, %r9
xorl %eax, %eax
callq 0x2140
movq 0x18(%r12), %rsi
leaq 0x40(%rsp), %rdi
leaq 0x1c8(%rsp), %rdx
callq 0x2090
leaq 0x40(%rsp), %rdi
movq %r15, %rsi
callq 0x2260
leaq 0x190(%rsp), %r12
movq %r12, -0x10(%r12)
movq (%rax), %rdx
movq %rax, %rcx
addq $0x10, %rcx
cmpq %rcx, %rdx
je 0x26ec
movq %rdx, 0x180(%rsp)
movq (%rcx), %rdx
movq %rdx, 0x190(%rsp)
jmp 0x26f6
leaq 0x1a98(%rip), %rdi      # 0x4151
movq %r14, %rsi
movq %rbx, %rdx
xorl %eax, %eax
callq 0x2030
movl $0x1, %ebp
movq 0x90(%rsp), %rdi
callq 0x2150
movl %ebp, %eax
addq $0x2b8, %rsp            # imm = 0x2B8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movupd (%rcx), %xmm0
movupd %xmm0, (%r12)
movq 0x8(%rax), %rdx
movq %rdx, 0x188(%rsp)
movq %rcx, (%rax)
movq $0x0, 0x8(%rax)
movb $0x0, 0x10(%rax)
leaq 0x50(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x2724
callq 0x2120
leaq 0x1cb1(%rip), %rsi      # 0x43dc
leaq 0x180(%rsp), %rbx
movl $0x1, %ecx
movq %rbx, %rdi
movq $-0x1, %rdx
callq 0x2290
movq 0x8(%rbx), %rcx
cmpq %rax, %rcx
jb 0x3455
movq %rax, 0x188(%rsp)
movq 0x180(%rsp), %rcx
movb $0x0, (%rcx,%rax)
movzbl 0x6(%rsp), %esi
cmpl $0x53, %esi
sete %al
cmpl $0x4e, %esi
sete %cl
movsbl %sil, %edx
movsbl 0x7(%rsp), %r8d
cmpl $0x53, %esi
je 0x2791
cmpl $0x4e, %esi
jne 0x28ae
cmpb $0x45, %r8b
je 0x27a4
movzbl %r8b, %esi
cmpl $0x57, %esi
jne 0x28ae
movl 0xd0(%rsp), %esi
movl 0xd4(%rsp), %ecx
leal 0x1(%rsi), %r9d
leal 0x1(%rcx), %r10d
subq $0x8, %rsp
leaq 0x19f3(%rip), %rdi      # 0x41b8
xorl %eax, %eax
pushq %r8
pushq %r10
pushq %rdx
callq 0x2030
addq $0x20, %rsp
leaq 0xb8(%rsp), %rdi
leaq 0x40(%rsp), %rdx
movq %r14, %rsi
callq 0x3654
movq 0xb8(%rsp), %rdi
movl $0x1, %edx
movq %r14, %rsi
movq 0x90(%rsp), %rcx
callq 0x21c0
cmpq $0x1, %rax
jne 0x28d1
movabsq $0x200000000, %r15      # imm = 0x200000000
movl 0x18(%rsp), %r12d
testl %r12d, %r12d
jle 0x28ec
movl $0x2, %eax
xorl %ecx, %ecx
movq 0xb8(%rsp), %rdx
movb (%rdx,%rcx), %sil
leal -0x1(%rax), %edi
movslq %edi, %rdi
movb (%rdx,%rdi), %r8b
movb %r8b, (%rdx,%rcx)
movq 0xb8(%rsp), %rcx
movb %sil, (%rcx,%rdi)
movslq %eax, %rcx
addl $0x2, %eax
cmpq %rcx, %r14
jg 0x2830
movl $0xffff8000, %ebx       # imm = 0xFFFF8000
xorl %eax, %eax
movl $0x8000, %ebp           # imm = 0x8000
movq 0xb8(%rsp), %rdx
xorl %ecx, %ecx
movswl (%rdx,%rax), %esi
cmpl %esi, %ebp
jle 0x2897
xorl %edi, %edi
cmpl $0xffff8000, %esi       # imm = 0xFFFF8000
sete %dil
addl %edi, %ecx
movl %esi, %edi
negw %di
cmovnol %esi, %ebp
jmp 0x289c
cmpl %esi, %ebx
cmovlel %esi, %ebx
shlq $0x20, %rax
addq %r15, %rax
sarq $0x20, %rax
cmpq %r14, %rax
jl 0x2877
jmp 0x28f8
orb %al, %cl
cmovnel %r8d, %edx
leaq 0x18d0(%rip), %rdi      # 0x418b
movl %edx, %esi
movq %r15, %rdx
xorl %eax, %eax
callq 0x2030
movl $0x1, %ebp
jmp 0x3428
leaq 0x1906(%rip), %rdi      # 0x41de
movq %rax, %rsi
xorl %eax, %eax
callq 0x2030
movl $0x1, %ebp
jmp 0x3416
movl $0x8000, %ebp           # imm = 0x8000
xorl %ecx, %ecx
movl $0xffff8000, %ebx       # imm = 0xFFFF8000
leaq 0x1906(%rip), %rdi      # 0x4205
movl %ebp, %esi
movl %ebx, %edx
xorl %eax, %eax
callq 0x2030
cvtsi2sd %ebp, %xmm0
cvtsi2sd %ebx, %xmm1
movsd %xmm0, 0x1b0(%rsp)
subsd %xmm0, %xmm1
movsd %xmm1, 0x1a8(%rsp)
movq 0x8(%rsp), %rax
movq 0x8(%rax), %rax
cmpb $0x61, (%rax)
jne 0x2961
testl %r12d, %r12d
jle 0x2a01
movq 0xb8(%rsp), %rax
xorl %ecx, %ecx
addw $0x7fff, (%rax,%rcx)    # imm = 0x7FFF
shlq $0x20, %rcx
addq %r15, %rcx
sarq $0x20, %rcx
cmpq %r14, %rcx
jl 0x2949
jmp 0x29c4
testl %r12d, %r12d
jle 0x2a01
movq 0xb8(%rsp), %rax
xorl %ecx, %ecx
movsd 0x169c(%rip), %xmm0     # 0x4018
movzwl (%rax,%rcx), %esi
movw $0xffff, %dx            # imm = 0xFFFF
cmpl $0x8000, %esi           # imm = 0x8000
je 0x29b0
movswl %si, %edx
xorps %xmm1, %xmm1
cvtsi2sd %edx, %xmm1
subsd 0x1b0(%rsp), %xmm1
mulsd %xmm0, %xmm1
divsd 0x1a8(%rsp), %xmm1
cvttsd2si %xmm1, %edx
movw %dx, (%rax,%rcx)
shlq $0x20, %rcx
addq %r15, %rcx
sarq $0x20, %rcx
cmpq %r14, %rcx
jl 0x297c
testl %r12d, %r12d
jle 0x2a01
movl $0x2, %eax
xorl %ecx, %ecx
movq 0xb8(%rsp), %rdx
movb (%rdx,%rcx), %sil
leal -0x1(%rax), %edi
movslq %edi, %rdi
movb (%rdx,%rdi), %r8b
movb %r8b, (%rdx,%rcx)
movq 0xb8(%rsp), %rcx
movb %sil, (%rcx,%rdi)
movslq %eax, %rcx
addl $0x2, %eax
cmpq %rcx, %r14
jg 0x29d0
xorpd %xmm0, %xmm0
movapd %xmm0, 0x60(%rsp)
movq $0x0, 0x70(%rsp)
movq 0x1a0(%rsp), %r15
movslq %r15d, %rbx
leaq 0x288(%rsp), %rdi
leaq 0x40(%rsp), %rdx
movq %rbx, %rsi
callq 0x36b4
movq 0x1b8(%rsp), %rax
decl %eax
xorps %xmm0, %xmm0
cvtsi2sd %eax, %xmm0
movsd 0x15d3(%rip), %xmm3     # 0x4020
movapd %xmm3, %xmm2
divsd %xmm0, %xmm2
movsd 0x15ab(%rip), %xmm0     # 0x4008
mulsd %xmm0, %xmm2
movsd 0x15a7(%rip), %xmm1     # 0x4010
divsd %xmm1, %xmm2
movsd %xmm2, 0x220(%rsp)
leal -0x1(%r15), %ecx
movl %ecx, 0xdc(%rsp)
xorps %xmm2, %xmm2
cvtsi2sd %ecx, %xmm2
divsd %xmm2, %xmm3
mulsd %xmm0, %xmm3
divsd %xmm1, %xmm3
movsd %xmm3, 0x228(%rsp)
cltq
movslq %r13d, %rcx
leaq (%rcx,%rcx), %rbp
movq %rax, 0x210(%rsp)
imulq %rax, %rcx
addq %rcx, %rcx
movq %rcx, 0x208(%rsp)
movq $0x0, 0x80(%rsp)
xorl %r13d, %r13d
movl $0x0, 0x38(%rsp)
movl $0x0, 0x34(%rsp)
movq $0x0, 0x88(%rsp)
movq %rbx, 0x218(%rsp)
leaq (%rbx,%r13), %r14
movl %r13d, %eax
negl %eax
cmovsl %r13d, %eax
movl %eax, 0x20(%rsp)
movl %r13d, %eax
shrl $0x1f, %eax
movq %rax, 0x230(%rsp)
xorl %eax, %eax
movq $0x0, 0x8(%rsp)
movl %eax, 0x18(%rsp)
leaq 0x170b(%rip), %rdi      # 0x4230
xorl %esi, %esi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2060
movq %rax, 0x10(%rsp)
movq %rax, %rdi
callq 0x2230
movq 0x3494(%rip), %rbx      # 0x5fd8
leaq 0x174b(%rip), %r12      # 0x4296
movq %rax, 0x28(%rsp)
movq 0x10(%rsp), %rdi
subq $0x8, %rsp
movq %rax, %rsi
movq 0x1c0(%rsp), %rdx
movl %r15d, %ecx
movl $0x10, %r8d
xorl %r9d, %r9d
xorl %eax, %eax
pushq %rax
pushq %rax
pushq %rax
callq 0x2220
addq $0x20, %rsp
movq 0x10(%rsp), %rdi
movq 0x28(%rsp), %rsi
movl $0x2, %edx
movsd 0x220(%rsp), %xmm0
movsd 0x228(%rsp), %xmm1
callq 0x2050
leaq 0x50(%rsp), %rax
movq %rax, 0x40(%rsp)
movabsq $0x5447482d4d545253, %rax # imm = 0x5447482D4D545253
movq %rax, 0x50(%rsp)
movq $0x8, 0x48(%rsp)
movb $0x0, 0x58(%rsp)
leaq 0x1d8(%rsp), %rax
movq %rax, 0x1c8(%rsp)
movw $0x6d, 0x1d8(%rsp)
movq $0x1, 0x1d0(%rsp)
movl $0x148, %edx            # imm = 0x148
leaq 0x268(%rsp), %rdi
movq %rbx, %rsi
movq %r12, %rcx
movsd 0x1b0(%rsp), %xmm0
movb $0x1, %al
callq 0x3741
movl $0x148, %edx            # imm = 0x148
leaq 0x248(%rsp), %rdi
movq %rbx, %rsi
movq %r12, %rcx
movsd 0x1a8(%rsp), %xmm0
movb $0x1, %al
callq 0x3741
cmpq $0x0, 0x270(%rsp)
je 0x3443
movq 0x268(%rsp), %rax
movq %rax, 0x2a0(%rsp)
cmpq $0x0, 0x250(%rsp)
je 0x3443
movq 0x248(%rsp), %rax
movq %rax, 0x2a8(%rsp)
cmpq $0x0, 0x48(%rsp)
je 0x3443
cmpq $0x0, 0x1d0(%rsp)
je 0x3443
movq 0x28(%rsp), %rsi
movq 0x10(%rsp), %rdi
movq 0x40(%rsp), %rdx
subq $0x8, %rsp
movl $0xffff8001, %ecx       # imm = 0xFFFF8001
movl $0x7fff, %r8d           # imm = 0x7FFF
xorl %r9d, %r9d
leaq 0x2a8(%rsp), %rax
pushq %rax
pushq 0x1d8(%rsp)
pushq $0x2
callq 0x20e0
addq $0x20, %rsp
testl %r15d, %r15d
jle 0x2d11
movq 0x8(%rsp), %rax
decl %eax
cltq
movq 0x80(%rsp), %rcx
leaq (%rcx,%rax,2), %rax
xorl %ecx, %ecx
movq 0xb8(%rsp), %rdx
addq %rax, %rdx
movq 0x288(%rsp), %rsi
movq %rdx, (%rsi,%rcx,8)
addq %rbp, %rax
leaq (%rcx,%r13), %rdx
incq %rdx
incq %rcx
cmpq %r14, %rdx
jl 0x2ce8
movq 0x10(%rsp), %rdi
movq 0x28(%rsp), %rsi
movq 0x288(%rsp), %rdx
callq 0x21e0
movq 0x10(%rsp), %rdi
leaq 0x60(%rsp), %rsi
leaq -0x969(%rip), %rdx      # 0x23d0
xorl %ecx, %ecx
callq 0x2280
movq 0x10(%rsp), %rdi
movq 0x28(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2070
leaq 0x10(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x20f0
movq 0x60(%rsp), %r12
movq 0x68(%rsp), %rax
movq %rax, 0x240(%rsp)
leaq 0x110(%rsp), %rax
movq %rax, 0x100(%rsp)
movq 0x180(%rsp), %rsi
movq 0x188(%rsp), %rdx
addq %rsi, %rdx
leaq 0x100(%rsp), %rbx
movq %rbx, %rdi
callq 0x37f2
movq %rbx, %rdi
leaq 0x162b(%rip), %rsi      # 0x43dc
callq 0x2260
leaq 0x130(%rsp), %r15
movl $0x1, %ebx
cmpl $0xa, 0x20(%rsp)
jb 0x2e0d
movl $0x4, %ebx
movl 0x20(%rsp), %eax
cmpl $0x63, %eax
jbe 0x2e06
cmpl $0x3e7, %eax            # imm = 0x3E7
jbe 0x2e0b
cmpl $0x2710, %eax           # imm = 0x2710
jb 0x2e0d
movl %eax, %ecx
movl $0xd1b71759, %edx       # imm = 0xD1B71759
imulq %rdx, %rcx
shrq $0x2d, %rcx
addl $0x4, %ebx
cmpl $0x1869f, %eax          # imm = 0x1869F
movl %ecx, %eax
ja 0x2dd3
addl $-0x3, %ebx
jmp 0x2e0d
addl $-0x2, %ebx
jmp 0x2e0d
decl %ebx
movq %r12, 0x238(%rsp)
movq 0x230(%rsp), %r12
leal (%r12,%rbx), %esi
leaq 0x170(%rsp), %rax
movq %rax, 0x160(%rsp)
leaq 0x160(%rsp), %rdi
movl $0x2d, %edx
callq 0x2190
movq 0x160(%rsp), %rdi
addq %r12, %rdi
movl %ebx, %esi
movl 0x20(%rsp), %edx
callq 0x3887
movq 0x100(%rsp), %rcx
movl $0xf, %edi
leaq 0x110(%rsp), %rax
cmpq %rax, %rcx
je 0x2e7b
movq 0x110(%rsp), %rdi
movq 0x108(%rsp), %r8
movq 0x160(%rsp), %rsi
movq 0x168(%rsp), %rdx
leaq (%rdx,%r8), %rax
cmpq %rdi, %rax
jbe 0x2ebb
movl $0xf, %edi
leaq 0x170(%rsp), %r9
cmpq %r9, %rsi
je 0x2eb6
movq 0x170(%rsp), %rdi
cmpq %rdi, %rax
jbe 0x2eca
leaq 0x100(%rsp), %rdi
callq 0x2040
jmp 0x2edb
leaq 0x160(%rsp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x2180
movq %r15, 0x120(%rsp)
movq (%rax), %rdx
leaq 0x10(%rax), %rcx
cmpq %rcx, %rdx
je 0x2f04
movq %rdx, 0x120(%rsp)
movq (%rcx), %rdx
movq %rdx, 0x130(%rsp)
jmp 0x2f0d
movupd (%rcx), %xmm0
movupd %xmm0, (%r15)
leaq 0xa8(%rsp), %rbx
movq %rax, %rdx
addq $0x8, %rdx
movq 0x8(%rax), %rsi
movq %rsi, 0x128(%rsp)
movq %rcx, (%rax)
movq $0x0, (%rdx)
movb $0x0, (%rcx)
leaq 0x120(%rsp), %rdi
leaq 0x1498(%rip), %rsi      # 0x43dc
callq 0x2260
movq %rbx, 0x98(%rsp)
movq (%rax), %rdx
movq %rax, %rcx
addq $0x10, %rcx
cmpq %rcx, %rdx
je 0x2f75
movq %rdx, 0x98(%rsp)
movq (%rcx), %rdx
movq %rdx, 0xa8(%rsp)
jmp 0x2f7d
movupd (%rcx), %xmm0
movupd %xmm0, (%rbx)
movq 0x8(%rax), %rdx
movq %rdx, 0xa0(%rsp)
movq %rcx, (%rax)
movq $0x0, 0x8(%rax)
movb $0x0, 0x10(%rax)
movq 0x8(%rsp), %rax
movl %eax, %ebx
negl %ebx
cmovsl %eax, %ebx
movl $0x1, %r15d
cmpl $0xa, %ebx
jb 0x2ff5
movl $0x4, %r15d
movl %ebx, %eax
cmpl $0x63, %eax
jbe 0x2fec
cmpl $0x3e7, %eax            # imm = 0x3E7
jbe 0x2ff2
cmpl $0x2710, %eax           # imm = 0x2710
jb 0x2ff5
movl %eax, %ecx
movl $0xd1b71759, %edx       # imm = 0xD1B71759
imulq %rdx, %rcx
shrq $0x2d, %rcx
addl $0x4, %r15d
cmpl $0x1869f, %eax          # imm = 0x1869F
movl %ecx, %eax
ja 0x2fb7
addl $-0x3, %r15d
jmp 0x2ff5
addl $-0x2, %r15d
jmp 0x2ff5
decl %r15d
movq 0x8(%rsp), %r12
shrl $0x1f, %r12d
leal (%r15,%r12), %esi
leaq 0x150(%rsp), %rax
movq %rax, 0x140(%rsp)
leaq 0x140(%rsp), %rdi
movl $0x2d, %edx
callq 0x2190
movl %r12d, %edi
addq 0x140(%rsp), %rdi
movl %r15d, %esi
movl %ebx, %edx
callq 0x3887
movq 0x98(%rsp), %rcx
movl $0xf, %edi
leaq 0xa8(%rsp), %r15
cmpq %r15, %rcx
je 0x305b
movq 0xa8(%rsp), %rdi
movq 0xa0(%rsp), %r8
movq 0x140(%rsp), %rsi
movq 0x148(%rsp), %rdx
leaq (%rdx,%r8), %rax
cmpq %rdi, %rax
movl 0x3c(%rsp), %r12d
leaq 0x130(%rsp), %rbx
jbe 0x30a8
movl $0xf, %edi
leaq 0x150(%rsp), %r9
cmpq %r9, %rsi
je 0x30a3
movq 0x150(%rsp), %rdi
cmpq %rdi, %rax
jbe 0x30b7
leaq 0x98(%rsp), %rdi
callq 0x2040
jmp 0x30c8
leaq 0x140(%rsp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x2180
leaq 0xf0(%rsp), %rsi
movq %rsi, 0xe0(%rsp)
movq (%rax), %rdx
leaq 0x10(%rax), %rcx
cmpq %rcx, %rdx
je 0x30f9
movq %rdx, 0xe0(%rsp)
movq (%rcx), %rdx
movq %rdx, 0xf0(%rsp)
jmp 0x3101
movupd (%rcx), %xmm0
movupd %xmm0, (%rsi)
movq %rax, %rdx
addq $0x8, %rdx
movq 0x8(%rax), %rsi
movq %rsi, 0xe8(%rsp)
movq %rcx, (%rax)
movq $0x0, (%rdx)
movb $0x0, (%rcx)
leaq 0xe0(%rsp), %rdi
leaq 0x1107(%rip), %rsi      # 0x4237
callq 0x2260
leaq 0x1f8(%rsp), %rsi
movq %rsi, 0x1e8(%rsp)
movq (%rax), %rdx
movq %rax, %rcx
addq $0x10, %rcx
cmpq %rcx, %rdx
je 0x3169
movq %rdx, 0x1e8(%rsp)
movq (%rcx), %rdx
movq %rdx, 0x1f8(%rsp)
jmp 0x3171
movupd (%rcx), %xmm0
movupd %xmm0, (%rsi)
movq 0x8(%rax), %rdx
movq %rdx, 0x1f0(%rsp)
movq %rcx, (%rax)
movq $0x0, 0x8(%rax)
movb $0x0, 0x10(%rax)
movq 0xe0(%rsp), %rdi
leaq 0xf0(%rsp), %rax
cmpq %rax, %rdi
je 0x31a6
callq 0x2120
movq 0x140(%rsp), %rdi
leaq 0x150(%rsp), %rax
cmpq %rax, %rdi
je 0x31c0
callq 0x2120
movq 0x98(%rsp), %rdi
cmpq %r15, %rdi
je 0x31d2
callq 0x2120
movq 0x120(%rsp), %rdi
cmpq %rbx, %rdi
je 0x31e4
callq 0x2120
movq 0x160(%rsp), %rdi
leaq 0x170(%rsp), %rax
cmpq %rax, %rdi
je 0x31fe
callq 0x2120
movq 0x100(%rsp), %rdi
leaq 0x110(%rsp), %rax
cmpq %rax, %rdi
je 0x3218
callq 0x2120
movq 0x1e8(%rsp), %rdi
leaq 0x1015(%rip), %rsi      # 0x423c
callq 0x21a0
movq %rax, %r15
movq 0x60(%rsp), %rdi
movq 0x68(%rsp), %rsi
subq %rdi, %rsi
movl $0x1, %edx
movq %rax, %rcx
callq 0x2270
movq %rax, %rbx
movq 0x60(%rsp), %rax
cmpq %rax, 0x68(%rsp)
je 0x325d
movq %rax, 0x68(%rsp)
cmpq $0x1, %rbx
jne 0x3296
movq 0x88(%rsp), %rax
addq 0x240(%rsp), %rax
subq 0x238(%rsp), %rax
movq %rax, 0x88(%rsp)
movq 0x8(%rsp), %rax
addl 0xdc(%rsp), %eax
movq %rax, 0x8(%rsp)
jmp 0x32af
leaq 0xfa2(%rip), %rdi       # 0x423f
movq %rbx, %rsi
xorl %eax, %eax
callq 0x2030
movl $0x1, 0x38(%rsp)
leaq 0x1f8(%rsp), %rax
testq %r15, %r15
je 0x32cc
movq %r15, %rdi
callq 0x2150
leaq 0x1f8(%rsp), %rax
movq 0x1e8(%rsp), %rdi
cmpq %rax, %rdi
je 0x32de
callq 0x2120
movq 0x248(%rsp), %rdi
leaq 0x258(%rsp), %rax
cmpq %rax, %rdi
movq 0x1a0(%rsp), %r15
je 0x3300
callq 0x2120
movq 0x268(%rsp), %rdi
leaq 0x278(%rsp), %rax
cmpq %rax, %rdi
je 0x331a
callq 0x2120
movq 0x1c8(%rsp), %rdi
leaq 0x1d8(%rsp), %rax
cmpq %rax, %rdi
je 0x3334
callq 0x2120
movq 0x40(%rsp), %rdi
leaq 0x50(%rsp), %rax
cmpq %rax, %rdi
je 0x3348
callq 0x2120
cmpq $0x1, %rbx
movl 0x18(%rsp), %eax
jne 0x33e9
incl %eax
cmpl 0x1c(%rsp), %eax
jne 0x2b1a
addq 0x210(%rsp), %r13
movl 0x34(%rsp), %ecx
incl %ecx
movq 0x80(%rsp), %rax
addq 0x208(%rsp), %rax
movq %rax, 0x80(%rsp)
movl %ecx, 0x34(%rsp)
cmpl %r12d, %ecx
movq 0x218(%rsp), %rbx
jne 0x2af0
movsd 0x88(%rsp), %xmm1
unpcklps 0xc83(%rip), %xmm1      # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0xc8b(%rip), %xmm1      # 0x4040
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
cvtsi2sdq 0x1c0(%rsp), %xmm2
addsd %xmm1, %xmm0
divsd %xmm2, %xmm0
mulsd 0xc51(%rip), %xmm0      # 0x4028
leaq 0xe89(%rip), %rdi       # 0x4267
movb $0x1, %al
callq 0x2030
xorl %ebp, %ebp
jmp 0x33ed
movl 0x38(%rsp), %ebp
movq 0x288(%rsp), %rdi
testq %rdi, %rdi
leaq 0x190(%rsp), %r12
je 0x3407
callq 0x2120
movq 0x60(%rsp), %rdi
testq %rdi, %rdi
je 0x3416
callq 0x2120
movq 0xb8(%rsp), %rdi
testq %rdi, %rdi
je 0x3428
callq 0x2120
movq 0x180(%rsp), %rdi
cmpq %r12, %rdi
je 0x26cb
callq 0x2120
jmp 0x26cb
leaq 0xf0d(%rip), %rdi       # 0x4357
xorl %esi, %esi
xorl %edx, %edx
xorl %eax, %eax
callq 0x21d0
leaq 0xe93(%rip), %rdi       # 0x42ef
leaq 0xe78(%rip), %rsi       # 0x42db
movq %rax, %rdx
xorl %eax, %eax
callq 0x21d0
movq %rax, %r14
jmp 0x3604
jmp 0x3477
movq %rax, %r14
jmp 0x3625
movq %rax, %r14
leaq 0x50(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x363f
jmp 0x363a
movq %rax, %r14
jmp 0x363f
movq %rax, %r14
jmp 0x34d2
movq %rax, %r14
jmp 0x3506
movq %rax, %r14
jmp 0x34ec
jmp 0x3588
movq %rax, %r14
movq 0xe0(%rsp), %rdi
leaq 0xf0(%rsp), %rax
cmpq %rax, %rdi
je 0x34d2
callq 0x2120
movq 0x140(%rsp), %rdi
leaq 0x150(%rsp), %rax
cmpq %rax, %rdi
je 0x34ec
callq 0x2120
movq 0x98(%rsp), %rdi
leaq 0xa8(%rsp), %rax
cmpq %rax, %rdi
je 0x3506
callq 0x2120
movq 0x120(%rsp), %rdi
leaq 0x130(%rsp), %rax
cmpq %rax, %rdi
je 0x3531
callq 0x2120
jmp 0x3531
jmp 0x358d
movq %rax, %r14
jmp 0x354b
movq %rax, %r14
jmp 0x35aa
movq %rax, %r14
movq 0x160(%rsp), %rdi
leaq 0x170(%rsp), %rax
cmpq %rax, %rdi
je 0x354b
callq 0x2120
movq 0x100(%rsp), %rdi
leaq 0x110(%rsp), %rax
cmpq %rax, %rdi
je 0x3590
callq 0x2120
jmp 0x3590
movq %rax, %r14
movq 0x100(%rsp), %rdi
leaq 0x110(%rsp), %rax
cmpq %rax, %rdi
je 0x3590
jmp 0x3560
movq %rax, %r14
jmp 0x35c4
jmp 0x358d
movq %rax, %r14
jmp 0x35f2
movq %rax, %r14
movq 0x248(%rsp), %rdi
leaq 0x258(%rsp), %rax
cmpq %rax, %rdi
je 0x35aa
callq 0x2120
movq 0x268(%rsp), %rdi
leaq 0x278(%rsp), %rax
cmpq %rax, %rdi
je 0x35c4
callq 0x2120
movq 0x1c8(%rsp), %rdi
leaq 0x1d8(%rsp), %rax
cmpq %rax, %rdi
je 0x35de
callq 0x2120
movq 0x40(%rsp), %rdi
leaq 0x50(%rsp), %rax
cmpq %rax, %rdi
je 0x35f2
callq 0x2120
movq 0x288(%rsp), %rdi
testq %rdi, %rdi
je 0x3604
callq 0x2120
movq 0x60(%rsp), %rdi
testq %rdi, %rdi
je 0x3613
callq 0x2120
movq 0xb8(%rsp), %rdi
testq %rdi, %rdi
je 0x3625
callq 0x2120
movq 0x180(%rsp), %rdi
leaq 0x190(%rsp), %rax
cmpq %rax, %rdi
je 0x363f
callq 0x2120
movq 0x90(%rsp), %rdi
callq 0x2150
movq %r14, %rdi
callq 0x2240