// File: /workspace/github_cpp_makefile_star2_O2/2TallTim[P]modern-raytracing/raytrace.cpp
// Function: main
int main(int argc, char **argv) {
    const int nx = 960;
    const int ny = 540;
    const int ns = 1024;
    const int nobj = 500;
    const double tgt_var = 0.005;

    std::vector<hitable::Ptr> oblist;

    for (int a = -11; a < 11; a++) {
        for (int b = -11; b < 11; b++) {
            double choose_mat = rng::gen01();
            vec3 center(a + 0.9 * rng::gen01(), 0.2, b + 0.9 * rng::gen01());
            if ((center - vec3(4, 0.2, 0)).squared_length() > 0.8) {
                material::Ptr mat;
                if (choose_mat < 0.8) { //diffuse
                    mat = std::make_shared<lambert>(vec3(rng::gen01() * rng::gen01(), rng::gen01() * rng::gen01(), rng::gen01() * rng::gen01()));
                } else if (choose_mat < 0.9) { //metal
                    mat = std::make_shared<metal>(vec3(0.5 * (1 + rng::gen01()), 0.5 * (1 + rng::gen01()), 0.5 * (1 + rng::gen01())), 0.5 * rng::gen01());
                } else if (choose_mat < 0.95){
                    mat = std::make_shared<diffuse_light>(vec3(80*rng::gen01(),80*rng::gen01(),80*rng::gen01()));
                } else { //glass
                    mat = std::make_shared<dielectric>(1.5);
                }
                hitable::Ptr sp = std::make_shared<sphere>(center, 0.2, mat);
                oblist.push_back(sp);
            }
        }
    }

    material::Ptr mat = std::make_shared<lambert>(vec3(0.5, 0.5, 0.5));
    hitable::Ptr sp = std::make_shared<sphere>(vec3(0, -1000, 0), 1000, mat);
    oblist.push_back(sp);

    mat = std::make_shared<dielectric>(1.5);
    sp = std::make_shared<sphere>(vec3(0, 1, 0), 1.0, mat);
    oblist.push_back(sp);

    mat = std::make_shared<diffuse_light>(vec3(10, 10, 10));
    sp = std::make_shared<sphere>(vec3(-4, 1, 0), 1.0, mat);
    oblist.push_back(sp);

    mat = std::make_shared<metal>(vec3(0.7, 0.6, 0.5), 0.0);
    sp = std::make_shared<sphere>(vec3(4, 1, 0), 1.0, mat);
    oblist.push_back(sp);

    auto world = std::make_shared<bvh_node>(oblist.begin(), oblist.end());

    vec3 origin(12, 1, 3);
    vec3 aim(0, 1, 0);
    double dist_to_focus = (origin - aim).length();
    double aperture = 0.03;

    camera cam(origin, aim, vec3(0, 1, 0), 30, (double)nx / ny, aperture, dist_to_focus);

    std::mutex result_mutex;
    std::vector<std::string> results(ny);
    std::vector<std::string> smpmap(ny);
    std::atomic_int nextrow(-1);

    auto renderRow = [&]() -> void {
        int j = ++nextrow;
        while (j < ny){
            std::stringstream tmpresults;
            std::stringstream smpcntresults;
            tmpresults << "# ROW " << j << std::endl;
            int t_samples = 0;
            for (int i = 0; i < nx; i++){
                vec3 col, vr;

                //Intialize variance tracking
                int s = 0;
                for (s = 0; s < ns; s++) {
                    double u = (double)(i + rng::gen01()) / nx;
                    double v = (double)(j + rng::gen01()) / ny;
                    ray r = cam.get_ray(u, v);
                    vec3 sample = color(r, world);

                    t_samples++;

                    col += sample;

                    vr += vec3(sample.r() * sample.r(),
                               sample.g() * sample.g(),
                               sample.b() * sample.b());

                    if (s > sqrt((float)ns)) {
                        vec3 musquared_s((col.r() * col.r()) / s,
                                         (col.g() * col.g()) / s,
                                         (col.b() * col.b()) / s);
                        vec3 variance = ((double)s / ((s - 1) * (double)s)) * (vr - musquared_s);
                        variance = vec3(variance.r() * variance.r(),
                                        variance.g() * variance.g(),
                                        variance.b() * variance.b());
                        if ((variance.r()/(col.r()/s) < tgt_var) &&
                            (variance.g()/(col.g()/s) < tgt_var) &&
                            (variance.b()/(col.b()/s) < tgt_var)) break;
                    }
                }
                col = col / (s + 1);
                col = vec3(fmin(sqrt(col.r()),1.0), 
                           fmin(sqrt(col.g()),1.0),
                           fmin( sqrt(col.b()),1.0));
                int ir = int(255.99 * col.r());
                int ig = int(255.99 * col.g());
                int ib = int(255.99 * col.b());

                tmpresults << ir << " " << ig << " " << ib << std::endl;
                int nsgv = int((double)255.99 * ((2 * log(s) / log(ns)) - 1));
                smpcntresults << nsgv << " " << nsgv << " " << nsgv << std::endl;
            }
            std::lock_guard<std::mutex> lock(result_mutex);
            results[j] = tmpresults.str();
            smpmap[j] = smpcntresults.str();
            j = ++nextrow;
            std::cout << j << " / " << ny << " Avg samples in row: " << (double)t_samples / nx << std::endl;
        }
    };
    std::vector<std::thread> threads;
    for (int t = 0; t < std::thread::hardware_concurrency() - 1; t++) {
        threads.push_back(std::thread(renderRow));
    }
    for (auto &t : threads) {
        t.join();
    }

    std::stringstream header;
    header << "P3" << std::endl;
    header << nx << " " << ny << std::endl;
    header << "255" << std::endl;

    results.push_back(header.str());
    smpmap.push_back(header.str());
    if (argc == 1){
        for (auto iter = results.rbegin(); iter != results.rend(); iter++) {
            std::cout << *iter;
        }
    } else {
        std::ofstream out(argv[1], std::ios::out);
        for (auto iter = results.rbegin(); iter != results.rend(); iter++) {
            out << *iter;
        }
    }
    std::ofstream smpout("./samples.ppm", std::ios::out);
    for (auto iter = smpmap.rbegin(); iter != smpmap.rend(); iter++) {
        smpout << *iter;
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x628, %rsp            # imm = 0x628
movq %rsi, 0x120(%rsp)
movl %edi, 0xb4(%rsp)
movabsq $0x3f747ae147ae147b, %rax # imm = 0x3F747AE147AE147B
movq %rax, 0x158(%rsp)
xorpd %xmm0, %xmm0
leaq 0xc0(%rsp), %rax
andq $0x0, 0x10(%rax)
movapd %xmm0, (%rax)
pushq $-0xb
popq %rax
movabsq $0x3fc999999999999a, %rbx # imm = 0x3FC999999999999A
leaq 0xf0(%rsp), %r12
leaq 0x1e0(%rsp), %rbp
leaq 0x570(%rsp), %r14
leaq 0x98(%rsp), %r13
cmpl $0xb, %eax
je 0x48a2
movl %eax, 0xb8(%rsp)
cvtsi2sd %eax, %xmm0
movsd %xmm0, 0x140(%rsp)
pushq $-0xb
popq %r15
cmpl $0xb, %r15d
je 0x4894
callq 0x3d54
movsd %xmm0, 0x80(%rsp)
callq 0x3d54
movsd %xmm0, 0x68(%rsp)
callq 0x3d54
cvtsi2sd %r15d, %xmm1
movsd 0x5b85(%rip), %xmm2     # 0xa0f8
movsd 0x68(%rsp), %xmm3
mulsd %xmm2, %xmm3
addsd 0x140(%rsp), %xmm3
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm3, 0x370(%rsp)
movq %rbx, 0x378(%rsp)
movsd %xmm0, 0x380(%rsp)
addsd 0x5b50(%rip), %xmm3     # 0xa100
mulsd %xmm3, %xmm3
addsd 0x5b8c(%rip), %xmm3     # 0xa148
mulsd %xmm0, %xmm0
addsd %xmm3, %xmm0
ucomisd 0x5b3c(%rip), %xmm0     # 0xa108
jbe 0x4857
xorpd %xmm0, %xmm0
movapd %xmm0, 0x570(%rsp)
movsd 0x5b21(%rip), %xmm0     # 0xa108
movsd 0x80(%rsp), %xmm1
ucomisd %xmm1, %xmm0
jbe 0x46a6
callq 0x3d54
movsd %xmm0, 0x68(%rsp)
callq 0x3d54
movsd %xmm0, 0x80(%rsp)
callq 0x3d54
movsd %xmm0, 0x138(%rsp)
callq 0x3d54
movsd %xmm0, 0x130(%rsp)
callq 0x3d54
movsd %xmm0, 0x128(%rsp)
callq 0x3d54
movsd 0x68(%rsp), %xmm1
mulsd 0x80(%rsp), %xmm1
movsd 0x138(%rsp), %xmm2
mulsd 0x130(%rsp), %xmm2
movsd 0x128(%rsp), %xmm3
mulsd %xmm0, %xmm3
movsd %xmm1, 0x1e0(%rsp)
movsd %xmm2, 0x1e8(%rsp)
movsd %xmm3, 0x1f0(%rsp)
movq %r12, %rdi
movq %rbp, %rsi
callq 0x5767
movq %r14, %rdi
movq %r12, %rsi
callq 0x5e06
jmp 0x47d6
movsd 0x5a4a(%rip), %xmm0     # 0xa0f8
ucomisd %xmm1, %xmm0
jbe 0x474f
callq 0x3d54
addsd 0x599b(%rip), %xmm0     # 0xa060
mulsd 0x5a23(%rip), %xmm0     # 0xa0f0
movsd %xmm0, 0x68(%rsp)
callq 0x3d54
movapd %xmm0, 0x80(%rsp)
callq 0x3d54
movapd 0x80(%rsp), %xmm1
unpcklpd %xmm0, %xmm1            # xmm1 = xmm1[0],xmm0[0]
addpd 0x5ac5(%rip), %xmm1     # 0xa1c0
movsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x1e0(%rsp)
mulpd 0x5abe(%rip), %xmm1     # 0xa1d0
movupd %xmm1, 0x1e8(%rsp)
callq 0x3d54
mulsd 0x59c8(%rip), %xmm0     # 0xa0f0
movsd %xmm0, 0x98(%rsp)
movq %r12, %rdi
movq %rbp, %rsi
movq %r13, %rdx
callq 0x5785
movq %r14, %rdi
movq %r12, %rsi
callq 0x6142
jmp 0x47d6
movsd 0x59b9(%rip), %xmm0     # 0xa110
ucomisd %xmm1, %xmm0
jbe 0x485f
callq 0x3d54
movsd %xmm0, 0x68(%rsp)
movsd 0x68(%rsp), %xmm0
mulsd 0x599e(%rip), %xmm0     # 0xa118
movsd %xmm0, 0x68(%rsp)
callq 0x3d54
movapd %xmm0, 0x80(%rsp)
callq 0x3d54
movapd 0x80(%rsp), %xmm1
unpcklpd %xmm0, %xmm1            # xmm1 = xmm1[0],xmm0[0]
mulpd 0x5a08(%rip), %xmm1     # 0xa1b0
movsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x1e0(%rsp)
movupd %xmm1, 0x1e8(%rsp)
movq %r12, %rdi
movq %rbp, %rsi
callq 0x57a6
movq %r14, %rdi
movq %r12, %rsi
callq 0x62e0
leaq 0xf8(%rsp), %rdi
callq 0x3b4a
movq %rbx, 0x98(%rsp)
movq %r12, %rdi
leaq 0x370(%rsp), %rsi
movq %r13, %rdx
movq %r14, %rcx
callq 0x57e2
movapd 0xf0(%rsp), %xmm0
movapd %xmm0, 0x1e0(%rsp)
xorpd %xmm0, %xmm0
movapd %xmm0, 0xf0(%rsp)
leaq 0xf8(%rsp), %rdi
callq 0x3b4a
leaq 0xc0(%rsp), %rdi
movq %rbp, %rsi
callq 0x3a44
leaq 0x1e8(%rsp), %rdi
callq 0x3b4a
leaq 0x578(%rsp), %rdi
callq 0x3b4a
incl %r15d
jmp 0x453e
movabsq $0x3ff8000000000000, %rax # imm = 0x3FF8000000000000
movq %rax, 0xf0(%rsp)
movq %rbp, %rdi
movq %r12, %rsi
callq 0x57c4
movq %r14, %rdi
movq %rbp, %rsi
callq 0x6890
leaq 0x1e8(%rsp), %rdi
jmp 0x47de
movl 0xb8(%rsp), %eax
incl %eax
jmp 0x451d
movapd 0x5926(%rip), %xmm0     # 0xa1d0
leaq 0x370(%rsp), %rsi
movapd %xmm0, (%rsi)
movabsq $0x3fe0000000000000, %r15 # imm = 0x3FE0000000000000
movq %r15, 0x10(%rsi)
leaq 0x1e0(%rsp), %rdi
callq 0x5767
leaq 0x58(%rsp), %rax
leaq 0x1e8(%rsp), %rdi
movapd -0x8(%rdi), %xmm0
movapd %xmm0, -0x8(%rax)
xorpd %xmm0, %xmm0
movapd %xmm0, -0x8(%rdi)
callq 0x3b4a
xorpd %xmm0, %xmm0
movhpd 0x581e(%rip), %xmm0     # xmm0 = xmm0[0],mem[0]
leaq 0x370(%rsp), %rsi
movapd %xmm0, (%rsi)
andq $0x0, 0x10(%rsi)
leaq 0x570(%rsp), %rdx
movl $0x3e8, (%rdx)          # imm = 0x3E8
leaq 0x1e0(%rsp), %rdi
leaq 0x50(%rsp), %rcx
callq 0x5806
leaq 0x78(%rsp), %rax
leaq 0x1e8(%rsp), %rdi
movapd -0x8(%rdi), %xmm0
movapd %xmm0, -0x8(%rax)
xorpd %xmm0, %xmm0
movapd %xmm0, -0x8(%rdi)
callq 0x3b4a
leaq 0xc0(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x3a44
leaq 0x1e0(%rsp), %rsi
movabsq $0x3ff8000000000000, %rax # imm = 0x3FF8000000000000
movq %rax, (%rsi)
leaq 0x370(%rsp), %rdi
callq 0x57c4
leaq 0x50(%rsp), %rbx
leaq 0x370(%rsp), %rsi
movq %rbx, %rdi
callq 0x6890
leaq 0x378(%rsp), %r14
movq %r14, %rdi
callq 0x3b4a
xorpd %xmm0, %xmm0
movhpd 0x56a3(%rip), %xmm0     # xmm0 = xmm0[0],mem[0]
movapd %xmm0, -0x8(%r14)
andq $0x0, 0x8(%r14)
movabsq $0x3ff0000000000000, %r14 # imm = 0x3FF0000000000000
leaq 0x570(%rsp), %rdx
movq %r14, (%rdx)
leaq 0x1e0(%rsp), %rdi
leaq 0x370(%rsp), %rsi
movq %rbx, %rcx
callq 0x582a
leaq 0x70(%rsp), %rbx
leaq 0x1e0(%rsp), %rsi
movq %rbx, %rdi
callq 0x6dbc
leaq 0x1e8(%rsp), %rdi
callq 0x3b4a
leaq 0xc0(%rsp), %rdi
movq %rbx, %rsi
callq 0x3a44
movapd 0x57b1(%rip), %xmm0     # 0xa1e0
leaq 0x370(%rsp), %rsi
movapd %xmm0, (%rsi)
movabsq $0x4024000000000000, %rax # imm = 0x4024000000000000
movq %rax, 0x10(%rsi)
leaq 0x1e0(%rsp), %rdi
callq 0x57a6
leaq 0x50(%rsp), %rbx
leaq 0x1e0(%rsp), %rsi
movq %rbx, %rdi
callq 0x62e0
leaq 0x1e8(%rsp), %rdi
callq 0x3b4a
movapd 0x5770(%rip), %xmm0     # 0xa1f0
leaq 0x370(%rsp), %rsi
movapd %xmm0, (%rsi)
andq $0x0, 0x10(%rsi)
leaq 0x570(%rsp), %rdx
movq %r14, (%rdx)
leaq 0x1e0(%rsp), %rdi
movq %rbx, %rcx
callq 0x582a
leaq 0x70(%rsp), %rbx
leaq 0x1e0(%rsp), %rsi
movq %rbx, %rdi
callq 0x6dbc
leaq 0x1e8(%rsp), %rdi
callq 0x3b4a
leaq 0xc0(%rsp), %rdi
movq %rbx, %rsi
callq 0x3a44
movapd 0x571a(%rip), %xmm0     # 0xa200
leaq 0x370(%rsp), %rsi
movapd %xmm0, (%rsi)
movq %r15, 0x10(%rsi)
leaq 0x570(%rsp), %rdx
andq $0x0, (%rdx)
leaq 0x1e0(%rsp), %rdi
callq 0x5785
leaq 0x50(%rsp), %rbx
leaq 0x1e0(%rsp), %rsi
movq %rbx, %rdi
callq 0x6142
leaq 0x1e8(%rsp), %rdi
callq 0x3b4a
movapd 0x56d7(%rip), %xmm0     # 0xa210
leaq 0x370(%rsp), %rsi
movapd %xmm0, (%rsi)
andq $0x0, 0x10(%rsi)
leaq 0x570(%rsp), %rdx
movq %r14, (%rdx)
leaq 0x1e0(%rsp), %rdi
movq %rbx, %rcx
callq 0x582a
leaq 0x70(%rsp), %rbx
leaq 0x1e0(%rsp), %rsi
movq %rbx, %rdi
callq 0x6dbc
leaq 0x1e8(%rsp), %rdi
callq 0x3b4a
leaq 0xc0(%rsp), %rdi
movq %rbx, %rsi
callq 0x3a44
movq 0xc0(%rsp), %rax
movq 0xc8(%rsp), %rcx
leaq 0x370(%rsp), %rsi
movq %rax, (%rsi)
leaq 0x1e0(%rsp), %rdx
movq %rcx, (%rdx)
leaq 0x148(%rsp), %rdi
callq 0x584e
movaps 0x564f(%rip), %xmm0     # 0xa220
movaps %xmm0, 0x1c0(%rsp)
movabsq $0x4008000000000000, %rax # imm = 0x4008000000000000
movq %rax, 0x1d0(%rsp)
xorps %xmm0, %xmm0
movhps 0x546b(%rip), %xmm0     # xmm0 = xmm0[0,1],mem[0,1]
movaps %xmm0, 0x1a0(%rsp)
andq $0x0, 0x1b0(%rsp)
movaps %xmm0, 0x180(%rsp)
andq $0x0, 0x190(%rsp)
movq 0x190(%rsp), %rax
movq %rax, 0x40(%rsp)
movaps 0x180(%rsp), %xmm0
movups %xmm0, 0x30(%rsp)
movq 0x1b0(%rsp), %rax
movq %rax, 0x28(%rsp)
movaps 0x1a0(%rsp), %xmm0
movups %xmm0, 0x18(%rsp)
movq 0x1d0(%rsp), %rax
movq %rax, 0x10(%rsp)
movaps 0x1c0(%rsp), %xmm0
movups %xmm0, (%rsp)
leaq 0x570(%rsp), %rdi
movsd 0x54b4(%rip), %xmm0     # 0xa128
movsd 0x54b4(%rip), %xmm1     # 0xa130
movsd 0x54b4(%rip), %xmm2     # 0xa138
movsd 0x54b4(%rip), %xmm3     # 0xa140
callq 0x5870
xorpd %xmm0, %xmm0
movapd %xmm0, 0x100(%rsp)
movapd %xmm0, 0xf0(%rsp)
andq $0x0, 0x110(%rsp)
leaq 0x98(%rsp), %rdi
leaq 0x370(%rsp), %rdx
movl $0x21c, %esi            # imm = 0x21C
callq 0x5a70
leaq 0xd8(%rsp), %rdi
leaq 0x370(%rsp), %rdx
movl $0x21c, %esi            # imm = 0x21C
callq 0x5a70
leaq 0xbc(%rsp), %rax
orl $-0x1, (%rax)
leaq 0x160(%rsp), %r15
andq $0x0, 0x10(%r15)
xorpd %xmm0, %xmm0
movapd %xmm0, (%r15)
xorl %r14d, %r14d
leaq 0x158(%rsp), %rbx
leaq 0x1e0(%rsp), %r13
leaq 0x370(%rsp), %rbp
callq 0x3240
decl %eax
cmpl %eax, %r14d
jae 0x4dd2
andq $0x0, 0x1e0(%rsp)
pushq $0x40
popq %rdi
callq 0x31e0
leaq 0xaff8(%rip), %rcx      # 0xfd40
movq %rcx, (%rax)
leaq 0xbc(%rsp), %rcx
movq %rcx, 0x8(%rax)
leaq 0x570(%rsp), %rcx
movq %rcx, 0x10(%rax)
leaq 0x148(%rsp), %rcx
movq %rcx, 0x18(%rax)
movq %rbx, 0x20(%rax)
movq %r12, 0x28(%rax)
leaq 0x98(%rsp), %rcx
movq %rcx, 0x30(%rax)
leaq 0xd8(%rsp), %rcx
movq %rcx, 0x38(%rax)
movq %rax, 0x370(%rsp)
movq %r13, %rdi
movq %rbp, %rsi
xorl %edx, %edx
callq 0x31b0
movq 0x370(%rsp), %rdi
testq %rdi, %rdi
je 0x4db7
movq (%rdi), %rax
callq *0x8(%rax)
movq %r15, %rdi
movq %r13, %rsi
callq 0x7274
movq %r13, %rdi
callq 0x5ac2
incl %r14d
jmp 0x4d20
movq 0x160(%rsp), %rbx
movq 0x168(%rsp), %r14
cmpq %r14, %rbx
je 0x4df5
movq %rbx, %rdi
callq 0x32d0
addq $0x8, %rbx
jmp 0x4de2
leaq 0x1e0(%rsp), %rdi
callq 0x3100
leaq 0x1f0(%rsp), %rbx
leaq 0x542f(%rip), %rsi      # 0xa240
movq %rbx, %rdi
callq 0x31d0
movq %rax, %rdi
callq 0x3090
movq %rbx, %rdi
movl $0x3c0, %esi            # imm = 0x3C0
callq 0x32e0
leaq 0x545a(%rip), %rsi      # 0xa28f
movq %rax, %rdi
callq 0x31d0
movq %rax, %rdi
movl $0x21c, %esi            # imm = 0x21C
callq 0x32e0
movq %rax, %rdi
callq 0x3090
leaq 0x53ea(%rip), %rsi      # 0xa243
movq %rbx, %rdi
callq 0x31d0
movq %rax, %rdi
callq 0x3090
leaq 0x1f8(%rsp), %rbx
leaq 0x370(%rsp), %rdi
movq %rbx, %rsi
callq 0x32a0
leaq 0x98(%rsp), %rdi
leaq 0x370(%rsp), %rsi
callq 0x744a
leaq 0x370(%rsp), %rdi
callq 0x3070
leaq 0x370(%rsp), %rdi
movq %rbx, %rsi
callq 0x32a0
leaq 0xd8(%rsp), %rdi
leaq 0x370(%rsp), %rsi
callq 0x744a
leaq 0x370(%rsp), %rdi
callq 0x3070
cmpl $0x1, 0xb4(%rsp)
jne 0x4f09
movq 0xa0(%rsp), %rbx
movq 0xb0e2(%rip), %r14      # 0xffd0
cmpq 0x98(%rsp), %rbx
je 0x4f5d
addq $-0x20, %rbx
movq %r14, %rdi
movq %rbx, %rsi
callq 0x31a0
jmp 0x4eee
movq 0x120(%rsp), %rax
movq 0x8(%rax), %rsi
leaq 0x370(%rsp), %rdi
pushq $0x10
popq %rdx
callq 0x3200
movq 0xa0(%rsp), %rbx
leaq 0x370(%rsp), %r14
cmpq 0x98(%rsp), %rbx
je 0x4f50
addq $-0x20, %rbx
movq %r14, %rdi
movq %rbx, %rsi
callq 0x31a0
jmp 0x4f35
leaq 0x370(%rsp), %rdi
callq 0x3280
leaq 0x52e3(%rip), %rsi      # 0xa247
leaq 0x370(%rsp), %rdi
pushq $0x10
popq %rdx
callq 0x3200
movq 0xe0(%rsp), %rbx
leaq 0x370(%rsp), %r14
cmpq 0xd8(%rsp), %rbx
je 0x4f9f
addq $-0x20, %rbx
movq %r14, %rdi
movq %rbx, %rsi
callq 0x31a0
jmp 0x4f84
leaq 0x370(%rsp), %rdi
callq 0x3280
leaq 0x1e0(%rsp), %rdi
callq 0x3130
leaq 0x160(%rsp), %rdi
callq 0x5ad0
leaq 0xd8(%rsp), %rdi
callq 0x5af2
leaq 0x98(%rsp), %rdi
callq 0x5af2
leaq 0x150(%rsp), %rdi
callq 0x3b4a
leaq 0x78(%rsp), %rdi
callq 0x3b4a
leaq 0x58(%rsp), %rdi
callq 0x3b4a
leaq 0xc0(%rsp), %rdi
callq 0x5b14
xorl %eax, %eax
addq $0x628, %rsp            # imm = 0x628
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x5090
jmp 0x5090
jmp 0x502a
jmp 0x5090
movq %rax, %rbx
leaq 0x370(%rsp), %rdi
callq 0x3070
jmp 0x50a5
jmp 0x5090
jmp 0x50e0
movq %rax, %rbx
leaq 0x58(%rsp), %r14
jmp 0x5102
jmp 0x5052
movq %rax, %rbx
leaq 0x58(%rsp), %r14
jmp 0x510f
jmp 0x507f
jmp 0x507f
jmp 0x507f
jmp 0x507f
jmp 0x507f
jmp 0x507f
jmp 0x507f
movq %rax, %rbx
leaq 0x58(%rsp), %r14
jmp 0x5126
jmp 0x515b
movq %rax, %rbx
leaq 0x58(%rsp), %r14
jmp 0x511c
jmp 0x5090
jmp 0x5095
movq %rax, %rbx
jmp 0x50a5
movq %rax, %rbx
leaq 0x370(%rsp), %rdi
callq 0x3280
leaq 0x1e0(%rsp), %rdi
callq 0x3130
jmp 0x50e3
jmp 0x50e0
movq %rax, %rbx
leaq 0x1e0(%rsp), %rdi
callq 0x5ac2
jmp 0x50e3
movq %rax, %rbx
movq 0x370(%rsp), %rdi
testq %rdi, %rdi
je 0x50e3
movq (%rdi), %rax
callq *0x8(%rax)
jmp 0x50e3
movq %rax, %rbx
leaq 0x58(%rsp), %r14
leaq 0x160(%rsp), %rdi
callq 0x5ad0
leaq 0xd8(%rsp), %rdi
callq 0x5af2
leaq 0x98(%rsp), %rdi
callq 0x5af2
leaq 0x150(%rsp), %rdi
callq 0x3b4a
leaq 0x78(%rsp), %rdi
callq 0x3b4a
movq %r14, %rdi
jmp 0x5154
jmp 0x5149
jmp 0x5149
jmp 0x5149
jmp 0x5149
jmp 0x5149
movq %rax, %rbx
leaq 0x1e8(%rsp), %rdi
callq 0x3b4a
jmp 0x514c
jmp 0x515b
movq %rax, %rbx
leaq 0x578(%rsp), %rdi
callq 0x3b4a
jmp 0x515e
movq %rax, %rbx
leaq 0xc0(%rsp), %rdi
callq 0x5b14
movq %rbx, %rdi
callq 0x3300
nop