// File: /workspace/github_cpp_makefile_star2_O2/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 $0x2a8, %rsp            # imm = 0x2A8
movl %edi, %r14d
leal -0x9(%r14), %eax
cmpl $-0x3, %eax
setae %al
cmpl $0x7, %edi
setne %cl
testb %al, %cl
jne 0x2487
leaq 0x1ef0(%rip), %rdi      # 0x435a
callq 0x2230
leaq 0x1bda(%rip), %rdi      # 0x4050
xorl %ebx, %ebx
movl %r14d, %esi
xorl %eax, %eax
callq 0x2030
jmp 0x27e2
movq %rsi, %r15
movq 0x20(%rsi), %rdi
callq 0x2240
movl %eax, %r13d
movq 0x28(%r15), %rdi
callq 0x2240
movl %eax, %ebx
cmpl $0x8, %r14d
jne 0x24bf
movq 0x30(%r15), %rdi
callq 0x2240
movl %eax, 0x10(%rsp)
movq 0x38(%r15), %rdi
callq 0x2240
jmp 0x24c6
pushq $0x1
popq %rax
movl %eax, 0x10(%rsp)
movl %eax, 0x14(%rsp)
movq 0x10(%r15), %r12
leaq 0x1b7f(%rip), %rsi      # 0x4054
movq %r12, %rdi
callq 0x21d0
movq %rax, %r14
leaq 0xb51(%rip), %rax       # 0x3038
movq %rax, 0xb8(%rsp)
movq %r14, 0xc0(%rsp)
testq %r14, %r14
je 0x2585
movq %r15, 0x20(%rsp)
movl %ebx, %eax
imull %r13d, %eax
movslq %eax, %rbp
pushq $0x2
popq %rdx
movq %r14, %rdi
xorl %esi, %esi
callq 0x20f0
movq %r14, %rdi
callq 0x21e0
movq %r13, %r15
movq %rax, %r13
movq %r14, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x20f0
leaq 0x1b41(%rip), %rdi      # 0x407d
movq %r12, %rsi
movq %r13, 0x60(%rsp)
movq %r13, %rdx
movq %r15, %r13
movl %r13d, %ecx
movl %ebx, %r8d
movq %rbp, %r9
xorl %eax, %eax
callq 0x2030
movl 0x14(%rsp), %r8d
testl %r8d, %r8d
setle %al
cmpl $0x0, 0x10(%rsp)
setle %cl
orb %al, %cl
cmpb $0x1, %cl
jne 0x259b
leaq 0x1d9c(%rip), %rdi      # 0x4317
callq 0x2230
jmp 0x27d2
leaq 0x1acb(%rip), %rdi      # 0x4057
movq %r12, %rsi
xorl %eax, %eax
callq 0x2030
jmp 0x27d2
cmpl $0x2, %r8d
jb 0x25bc
leal -0x1(%r13), %eax
cltd
idivl %r8d
testl %edx, %edx
je 0x25bc
leaq 0x1b0a(%rip), %rdi      # 0x40be
movl %r13d, %esi
movl %r8d, %edx
jmp 0x25db
movl 0x10(%rsp), %ecx
cmpl $0x2, %ecx
jb 0x25e7
movl %ebx, %eax
decl %eax
cltd
idivl %ecx
testl %edx, %edx
je 0x25e7
leaq 0x1b30(%rip), %rdi      # 0x4107
movl %ebx, %esi
movl %ecx, %edx
xorl %eax, %eax
callq 0x2030
jmp 0x27d2
movl %r13d, %eax
cltd
movl 0x14(%rsp), %esi
idivl %esi
cmpl $0x2, %esi
sbbl $-0x1, %eax
movq %rax, 0xb0(%rsp)
movl %ebx, %eax
cltd
idivl %ecx
cmpl $0x2, %ecx
sbbl $-0x1, %eax
addq %rbp, %rbp
movq 0x60(%rsp), %rsi
cmpq %rbp, %rsi
jne 0x27c1
movq %rax, 0x98(%rsp)
leaq 0x6c(%rsp), %r14
orq $-0x1, -0x4(%r14)
leaq 0xb(%rsp), %rbp
andw $0x0, -0x1(%rbp)
movq 0x20(%rsp), %r15
movq 0x10(%r15), %rdi
pushq $0x2f
popq %rsi
callq 0x21b0
leaq 0x1(%rax), %rbx
testq %rax, %rax
cmoveq %r12, %rbx
leaq 0x1b22(%rip), %rsi      # 0x417c
leaq 0xa(%rsp), %rdx
leaq 0x68(%rsp), %rcx
movq %rbx, %rdi
movq %rbp, %r8
movq %r14, %r9
xorl %eax, %eax
callq 0x2180
movq 0x18(%r15), %rsi
leaq 0xc8(%rsp), %rdi
leaq 0x168(%rsp), %rdx
callq 0x20a0
leaq 0x188(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
movq %rbx, %rdx
callq 0x3064
leaq 0xc8(%rsp), %rdi
callq 0x20c0
leaq 0x1c9f(%rip), %rsi      # 0x4358
leaq 0x188(%rsp), %r14
pushq $-0x1
popq %r12
movq %r14, %rdi
movq %r12, %rdx
callq 0x2160
movq %r14, %rdi
movq %rax, %rsi
movq %r12, %rdx
callq 0x2040
movzbl 0xa(%rsp), %esi
cmpl $0x53, %esi
sete %al
cmpl $0x4e, %esi
sete %cl
movsbl %sil, %edx
movsbl 0xb(%rsp), %r8d
cmpl $0x53, %esi
movq 0x60(%rsp), %r14
je 0x270c
cmpl $0x4e, %esi
jne 0x27f6
cmpb $0x45, %r8b
je 0x271f
movzbl %r8b, %esi
cmpl $0x57, %esi
jne 0x27f6
movl 0x68(%rsp), %esi
movl 0x6c(%rsp), %ecx
leal 0x1(%rsi), %r9d
leal 0x1(%rcx), %r10d
subq $0x8, %rsp
leaq 0x1a7e(%rip), %rdi      # 0x41b8
xorl %eax, %eax
pushq %r8
pushq %r10
pushq %rdx
callq 0x2030
addq $0x20, %rsp
leaq 0x80(%rsp), %rdi
leaq 0xc8(%rsp), %rdx
movq %r14, %rsi
callq 0x3084
movq 0x80(%rsp), %rdi
movq 0xc0(%rsp), %rcx
pushq $0x1
popq %rdx
movq %r14, %rsi
callq 0x2210
cmpq $0x1, %rax
jne 0x2817
pushq $0x1
popq %rcx
leal -0x1(%rcx), %eax
movslq %eax, %rdx
movq 0x80(%rsp), %rax
cmpq %rdx, %r14
jle 0x2830
movb (%rax,%rdx), %sil
movslq %ecx, %rdi
movb (%rax,%rdi), %r8b
movb %r8b, (%rax,%rdx)
movq 0x80(%rsp), %rax
movb %sil, (%rax,%rdi)
addl $0x2, %ecx
jmp 0x278a
leaq 0x1989(%rip), %rdi      # 0x4151
movq %rbp, %rdx
xorl %eax, %eax
callq 0x2030
pushq $0x1
popq %rbx
leaq 0xb8(%rsp), %rdi
callq 0x3242
movl %ebx, %eax
addq $0x2a8, %rsp            # imm = 0x2A8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
orb %al, %cl
cmovnel %r8d, %edx
leaq 0x1988(%rip), %rdi      # 0x418b
movl %edx, %esi
movq %rbx, %rdx
xorl %eax, %eax
callq 0x2030
pushq $0x1
popq %rbx
jmp 0x2ef9
leaq 0x19c0(%rip), %rdi      # 0x41de
movq %rax, %rsi
xorl %eax, %eax
callq 0x2030
pushq $0x1
popq %rbx
jmp 0x2eec
movl $0x8000, %ebx           # imm = 0x8000
xorl %ecx, %ecx
movl $0xffff8000, %ebp       # imm = 0xFFFF8000
xorl %edx, %edx
movslq %edx, %rdx
cmpq %r14, %rdx
jge 0x2870
movswl (%rax,%rdx), %esi
cmpl %esi, %ebx
jle 0x2865
xorl %edi, %edi
cmpw $0x8000, %si            # imm = 0x8000
sete %dil
addl %edi, %ecx
movl %esi, %edi
negw %di
cmovnol %esi, %ebx
jmp 0x286a
cmpl %esi, %ebp
cmovlel %esi, %ebp
addq $0x2, %rdx
jmp 0x283e
leaq 0x198e(%rip), %rdi      # 0x4205
movl %ebx, %esi
movl %ebp, %edx
xorl %eax, %eax
callq 0x2030
cvtsi2sd %ebx, %xmm0
cvtsi2sd %ebp, %xmm1
movsd %xmm0, 0xa8(%rsp)
subsd %xmm0, %xmm1
movsd %xmm1, 0xa0(%rsp)
movq 0x8(%r15), %rax
cmpb $0x61, (%rax)
movq 0x80(%rsp), %rax
jne 0x28c7
xorl %ecx, %ecx
movslq %ecx, %rcx
cmpq %r14, %rcx
jge 0x2913
addw $0x7fff, (%rax,%rcx)    # imm = 0x7FFF
addq $0x2, %rcx
jmp 0x28b3
xorl %ecx, %ecx
movsd 0x1747(%rip), %xmm0     # 0x4018
movslq %ecx, %rcx
cmpq %r14, %rcx
jge 0x2913
movzwl (%rax,%rcx), %esi
movw $0xffff, %dx            # imm = 0xFFFF
cmpw $0x8000, %si            # imm = 0x8000
je 0x2909
movswl %si, %edx
cvtsi2sd %edx, %xmm1
subsd 0xa8(%rsp), %xmm1
mulsd %xmm0, %xmm1
divsd 0xa0(%rsp), %xmm1
cvttsd2si %xmm1, %edx
movw %dx, (%rax,%rcx)
addq $0x2, %rcx
jmp 0x28d1
pushq $0x1
popq %rax
leal -0x1(%rax), %ecx
movslq %ecx, %rcx
cmpq %rcx, %r14
jle 0x2949
movq 0x80(%rsp), %rdx
movb (%rdx,%rcx), %sil
movslq %eax, %rdi
movb (%rdx,%rdi), %r8b
movb %r8b, (%rdx,%rcx)
movq 0x80(%rsp), %rcx
movb %sil, (%rcx,%rdi)
addl $0x2, %eax
jmp 0x2916
xorpd %xmm0, %xmm0
movapd %xmm0, 0x30(%rsp)
andq $0x0, 0x40(%rsp)
movq 0x98(%rsp), %rbx
movslq %ebx, %rsi
leaq 0x118(%rsp), %rdi
leaq 0xc8(%rsp), %rdx
movq %rsi, 0xf8(%rsp)
callq 0x30d6
movq 0xb0(%rsp), %rax
decl %eax
cvtsi2sd %eax, %xmm0
movsd 0x1689(%rip), %xmm3     # 0x4020
movapd %xmm3, %xmm2
divsd %xmm0, %xmm2
movsd 0x1661(%rip), %xmm0     # 0x4008
mulsd %xmm0, %xmm2
movsd 0x165d(%rip), %xmm1     # 0x4010
divsd %xmm1, %xmm2
movsd %xmm2, 0x100(%rsp)
leal -0x1(%rbx), %ecx
movl %ecx, 0x78(%rsp)
cvtsi2sd %ecx, %xmm2
divsd %xmm2, %xmm3
mulsd %xmm0, %xmm3
divsd %xmm1, %xmm3
movsd %xmm3, 0x108(%rsp)
cltq
movslq %r13d, %r12
movq %r12, %rcx
movq %rax, 0xf0(%rsp)
imulq %rax, %rcx
addq %rcx, %rcx
movq %rcx, 0xe8(%rsp)
addq %r12, %r12
movq $0x0, 0x58(%rsp)
leaq 0x168(%rsp), %r14
xorl %r15d, %r15d
movq $0x0, 0x50(%rsp)
xorl %ecx, %ecx
movl $0x0, 0xc(%rsp)
movl %ecx, 0x74(%rsp)
cmpl 0x10(%rsp), %ecx
je 0x2e87
movq 0xf8(%rsp), %rax
leaq (%r15,%rax), %r13
movq $0x0, 0x20(%rsp)
xorl %eax, %eax
movl %eax, 0x7c(%rsp)
cmpl 0x14(%rsp), %eax
je 0x2e62
leaq 0x17cd(%rip), %rdi      # 0x4230
xorl %esi, %esi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2070
movq %rax, 0x18(%rsp)
movq %rax, %rdi
callq 0x2280
movq %rax, 0x28(%rsp)
movq 0x18(%rsp), %rdi
subq $0x8, %rsp
movq %rax, %rsi
movq 0xb8(%rsp), %rdx
movq 0xa0(%rsp), %rcx
pushq $0x10
popq %r8
xorl %r9d, %r9d
pushq $0x0
pushq $0x0
pushq $0x0
callq 0x2270
addq $0x20, %rsp
movq 0x18(%rsp), %rdi
movq 0x28(%rsp), %rsi
pushq $0x2
popq %rdx
movsd 0x100(%rsp), %xmm0
movsd 0x108(%rsp), %xmm1
callq 0x2060
leaq 0xc8(%rsp), %rdi
leaq 0x1752(%rip), %rsi      # 0x4237
movq %r14, %rdx
callq 0x20a0
movq %r14, %rdi
leaq 0x1749(%rip), %rsi      # 0x4240
leaq 0x228(%rsp), %rbx
movq %rbx, %rdx
callq 0x20a0
movq %rbx, %rdi
movsd 0xa8(%rsp), %xmm0
callq 0x3127
leaq 0x208(%rsp), %rdi
movsd 0xa0(%rsp), %xmm0
callq 0x3127
leaq 0x228(%rsp), %rdi
xorl %esi, %esi
callq 0x22c0
movq %rax, 0x130(%rsp)
leaq 0x208(%rsp), %rdi
xorl %esi, %esi
callq 0x22c0
movq %rax, 0x138(%rsp)
movq 0x18(%rsp), %rbx
movq 0x28(%rsp), %r14
leaq 0xc8(%rsp), %rdi
xorl %esi, %esi
callq 0x22c0
movq %rax, %rbp
leaq 0x168(%rsp), %rdi
xorl %esi, %esi
callq 0x22c0
subq $0x8, %rsp
movq %rbx, %rdi
movq %r14, %rsi
movq %rbp, %rdx
movl $0xffff8001, %ecx       # imm = 0xFFFF8001
movl $0x7fff, %r8d           # imm = 0x7FFF
xorl %r9d, %r9d
leaq 0x138(%rsp), %r10
pushq %r10
pushq %rax
pushq $0x2
callq 0x2110
addq $0x20, %rsp
movq 0x20(%rsp), %rax
decl %eax
cltq
movq 0x58(%rsp), %rcx
leaq (%rcx,%rax,2), %rax
xorl %ecx, %ecx
leaq (%r15,%rcx), %rdx
cmpq %r13, %rdx
jge 0x2bf4
movq 0x80(%rsp), %rdx
addq %rax, %rdx
movq 0x118(%rsp), %rsi
movq %rdx, (%rsi,%rcx,8)
addq %r12, %rax
incq %rcx
jmp 0x2bcc
movq 0x18(%rsp), %rdi
movq 0x28(%rsp), %rsi
movq 0x118(%rsp), %rdx
callq 0x2220
movq 0x18(%rsp), %rdi
leaq 0x30(%rsp), %rsi
leaq -0x80c(%rip), %rdx      # 0x2410
xorl %ecx, %ecx
callq 0x22e0
movq 0x18(%rsp), %rdi
movq 0x28(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2080
leaq 0x18(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x2120
movq 0x30(%rsp), %rax
movq %rax, 0x110(%rsp)
movq 0x38(%rsp), %r14
leaq 0x1a8(%rsp), %rdi
leaq 0x188(%rsp), %rsi
leaq 0x16ea(%rip), %rdx      # 0x4358
callq 0x31b1
leaq 0x268(%rsp), %rbp
movq %rbp, %rdi
movl %r15d, %esi
callq 0x31e9
leaq 0x288(%rsp), %rbx
movq %rbx, %rdi
leaq 0x1a8(%rsp), %rsi
movq %rbp, %rdx
callq 0x314a
leaq 0x1c8(%rsp), %rdi
movq %rbx, %rsi
leaq 0x16a5(%rip), %rdx      # 0x4358
callq 0x3064
leaq 0x248(%rsp), %rbx
movq %rbx, %rdi
movq 0x20(%rsp), %rsi
callq 0x31e9
leaq 0x148(%rsp), %rbp
movq %rbp, %rdi
leaq 0x1c8(%rsp), %rsi
movq %rbx, %rdx
callq 0x314a
leaq 0x1e8(%rsp), %rdi
movq %rbp, %rsi
leaq 0x1548(%rip), %rdx      # 0x4242
callq 0x3064
movq %rbp, %rdi
callq 0x20c0
leaq 0x248(%rsp), %rdi
callq 0x20c0
leaq 0x1c8(%rsp), %rdi
callq 0x20c0
leaq 0x288(%rsp), %rdi
callq 0x20c0
leaq 0x268(%rsp), %rdi
callq 0x20c0
leaq 0x1a8(%rsp), %rdi
callq 0x20c0
movq 0x1e8(%rsp), %rdi
leaq 0x14f0(%rip), %rsi      # 0x4247
callq 0x21d0
leaq 0x2db(%rip), %rcx       # 0x303e
movq %rcx, 0x148(%rsp)
movq %rax, 0x150(%rsp)
cmpq $0x0, 0xc0(%rsp)
je 0x2dd4
movq 0x30(%rsp), %rdi
movq 0x38(%rsp), %rsi
subq %rdi, %rsi
pushq $0x1
popq %rdx
movq %rax, %rcx
callq 0x22d0
movq 0x30(%rsp), %rcx
cmpq %rcx, 0x38(%rsp)
je 0x2da7
movq %rcx, 0x38(%rsp)
cmpq $0x1, %rax
jne 0x2de7
movq 0x50(%rsp), %rax
addq %r14, %rax
subq 0x110(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0x20(%rsp), %rax
addl 0x78(%rsp), %eax
movq %rax, 0x20(%rsp)
movb $0x1, %bl
jmp 0x2e01
movq 0x1e8(%rsp), %rsi
xorl %ebx, %ebx
leaq 0x1272(%rip), %rdi      # 0x4057
jmp 0x2df3
xorl %ebx, %ebx
leaq 0x145a(%rip), %rdi      # 0x424a
movq %rax, %rsi
xorl %eax, %eax
callq 0x2030
pushq $0x1
popq %rax
movl %eax, 0xc(%rsp)
leaq 0x148(%rsp), %rdi
callq 0x3242
leaq 0x1e8(%rsp), %rdi
callq 0x20c0
leaq 0x208(%rsp), %rdi
callq 0x20c0
leaq 0x228(%rsp), %rdi
callq 0x20c0
leaq 0x168(%rsp), %r14
movq %r14, %rdi
callq 0x20c0
leaq 0xc8(%rsp), %rdi
callq 0x20c0
movl 0x7c(%rsp), %eax
incl %eax
testb %bl, %bl
jne 0x2a4e
jmp 0x2ed1
addq 0xf0(%rsp), %r15
movl 0x74(%rsp), %ecx
incl %ecx
movq 0x58(%rsp), %rax
addq 0xe8(%rsp), %rax
movq %rax, 0x58(%rsp)
jmp 0x2a29
movsd 0x50(%rsp), %xmm1
unpcklps 0x119c(%rip), %xmm1     # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0x11a4(%rip), %xmm1     # 0x4040
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
cvtsi2sdq 0x60(%rsp), %xmm2
addsd %xmm1, %xmm0
divsd %xmm2, %xmm0
mulsd 0x116d(%rip), %xmm0     # 0x4028
leaq 0x13b0(%rip), %rdi      # 0x4272
movb $0x1, %al
callq 0x2030
movl $0x0, 0xc(%rsp)
leaq 0x118(%rsp), %rdi
callq 0x36f0
leaq 0x30(%rsp), %rdi
callq 0x3690
movl 0xc(%rsp), %ebx
leaq 0x80(%rsp), %rdi
callq 0x3690
leaq 0x188(%rsp), %rdi
callq 0x20c0
jmp 0x27d5
movq %rax, %rbx
jmp 0x2fff
jmp 0x2f15
movq %rax, %rbx
jmp 0x3016
movq %rax, %rbx
leaq 0xc8(%rsp), %rdi
jmp 0x301e
movq %rax, %rbx
jmp 0x3023
movq %rax, %rbx
jmp 0x2f63
jmp 0x2fbb
movq %rax, %rbx
jmp 0x2f56
movq %rax, %rbx
jmp 0x2f94
movq %rax, %rbx
leaq 0x148(%rsp), %rdi
callq 0x20c0
leaq 0x248(%rsp), %rdi
callq 0x20c0
leaq 0x1c8(%rsp), %rdi
callq 0x20c0
jmp 0x2f7a
movq %rax, %rbx
jmp 0x2f87
movq %rax, %rbx
leaq 0x288(%rsp), %rdi
callq 0x20c0
leaq 0x268(%rsp), %rdi
callq 0x20c0
leaq 0x1a8(%rsp), %rdi
callq 0x20c0
jmp 0x2fbe
movq %rax, %rbx
jmp 0x2fe5
movq %rax, %rbx
jmp 0x2fcb
jmp 0x2fb6
jmp 0x2fb6
movq %rax, %rbx
jmp 0x2fd8
movq %rax, %rbx
jmp 0x2ff2
movq %rax, %rbx
leaq 0x208(%rsp), %rdi
callq 0x20c0
leaq 0x228(%rsp), %rdi
callq 0x20c0
leaq 0x168(%rsp), %rdi
callq 0x20c0
leaq 0xc8(%rsp), %rdi
callq 0x20c0
leaq 0x118(%rsp), %rdi
callq 0x36f0
leaq 0x30(%rsp), %rdi
callq 0x3690
leaq 0x80(%rsp), %rdi
callq 0x3690
leaq 0x188(%rsp), %rdi
callq 0x20c0
leaq 0xb8(%rsp), %rdi
callq 0x3242
movq %rbx, %rdi
callq 0x2290