// File: JMMackenzie[P]binary_to_jass/bin_to_jass.cpp
// Function: score_index(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, double, char)
void score_index(std::string ds2i_prefix,
                 std::string lex_file,
                 const double quant_level,
                 char compression){

	  // Tell JASS that we're using QMX-D1: we need to compute our own deltas
    ANT_compress *compression_scheme;
    if (compression == 'q')
        compression_scheme = new ANT_compress_qmx();
    else if (compression == 'G')
        compression_scheme = new JASS::compress_integer_elias_gamma_simd();
    else if (compression == 'g')
        compression_scheme = new JASS::compress_integer_elias_gamma_simd_vb();
    else
         compression_scheme = nullptr;
    ANT_compress &compressor = *compression_scheme;


    uint32_t sse_alignment = 16;
    std::vector<plist_t> m_postings_lists;

    // 1. Read lexicon file and start building posting metadata
    std::ifstream lex_data(lex_file);
    std::string term;
    uint32_t term_id = 0;
    while (lex_data >> term) {
      m_postings_lists.emplace_back(term, term_id);
      ++term_id;
    }
    std::cerr << "Read " << m_postings_lists.size() << " terms.\n";

    std::string docs_file = ds2i_prefix + ".docs";
    std::string freqs_file = ds2i_prefix + ".freqs";
    std::string sizes_file = ds2i_prefix + ".sizes";

    auto df = fopen(docs_file.c_str(), "rb");
    auto ff = fopen(freqs_file.c_str(), "rb");
    auto sf = fopen(sizes_file.c_str(), "rb");

    std::vector<uint32_t> doc_list;
    std::vector<uint32_t> freq_list;
    std::vector<uint32_t> size_list;

    double global_maximum = 0.0;

    // Get no. docs    
    read_uint32_list(doc_list,df);
    uint32_t no_docs = doc_list[0];

    // Read sizes
    read_uint32_list(size_list,sf);
  
    // validate sizes
    if (size_list.size() != no_docs) {
      std::cerr << "Something went wrong: Sizes not matched with no. docs." 
                << std::endl;
      exit(EXIT_FAILURE);
    }

    std::cerr << "Processing " << no_docs << " documents." << std::endl;

    // Compute mean document length
    float average_len = std::accumulate(size_list.begin(), size_list.end(), 0.0)/no_docs; 

    bm25_t ranker(float(no_docs), average_len);

    term_id = 0;
    while (!feof(df)) {
      read_uint32_list(doc_list,df);
      read_uint32_list(freq_list,ff);
      size_t doc_n = doc_list.size();
      size_t freq_n = freq_list.size();
      if (doc_n != freq_n) {
        std::cerr << "Files are not aligned.\n";
        exit(EXIT_FAILURE);
      }
      // Exhausted our lists
      if (doc_n == 0) {
        // Ensure validity
        if (term_id != m_postings_lists.size()) {
          std::cerr << "Error: Should have read more data. Exit." << std::endl;
          exit(EXIT_FAILURE);
        }
        break;
      }

      // Query term weight (compute once)
      float w_qt = ranker.query_term_weight(doc_n);

      // Resize our PL
      m_postings_lists[term_id].postings_list.resize(doc_list.size());

      // Score the PL and dump it
      for (size_t i = 0; i < doc_list.size(); ++i) {
        uint32_t doc_id = doc_list[i];
        uint32_t freq = freq_list[i];
        double impact = w_qt * ranker.doc_term_weight(float(freq), float(size_list[doc_id]));
        global_maximum = std::max(global_maximum, impact);
        m_postings_lists[term_id].postings_list[i].docid = doc_id;
        m_postings_lists[term_id].postings_list[i].score = impact;
      }
      ++term_id;
    }

    // We have scored all postings, now we must quantize them
    std::cerr << "Maximum score = " << global_maximum << std::endl;
    std::cerr << "Quantization range = [1, " << quant_level << "]" << std::endl;
    for(size_t i = 0; i < m_postings_lists.size(); ++i) {
      for (size_t j = 0; j < m_postings_lists[i].postings_list.size(); ++j) {
        double score = m_postings_lists[i].postings_list[j].score;
        m_postings_lists[i].postings_list[j].q_score = (uint32_t) std::ceil(quant_level * score / global_maximum);
      }
    }


    // prepare output
    std::ofstream vocab_terms("CIvocab_terms.bin");
    std::ofstream vocab("CIvocab.bin", std::ofstream::binary);
    std::ofstream postings("CIpostings.bin", std::ofstream::binary);
    size_t terms_offset = 0;
    size_t pl_offset = 0;





    postings.write((char *)&compression, sizeof(uint8_t));
    pl_offset = postings.tellp();

    // Now we need to get them out in the expected JASS format
    for(size_t i = 0; i < m_postings_lists.size(); ++i) {

      // Currently processing this list
      std::string current_term = m_postings_lists[i].term;

      // Write the offset in the vocab file
      vocab.write((char *)&terms_offset, sizeof(size_t));
      vocab.write((char *)&pl_offset, sizeof(size_t));

      // Write term to the terms file
      vocab_terms << current_term << '\0';
    
      // Update offsets
      terms_offset = vocab_terms.tellp();

      // Deal with postings
     
      uint32_t max_quant = uint32_t(quant_level);
      std::vector<std::vector<uint32_t>> pl_segments(max_quant);
      for(size_t j = 0; j < m_postings_lists[i].postings_list.size(); ++j) {
        uint32_t score = m_postings_lists[i].postings_list[j].q_score - 1;
        uint32_t docid = m_postings_lists[i].postings_list[j].docid;
        pl_segments[score].push_back(docid + 1); // DocID in JASS is 1->N, 0 is sentinel. Create this offset now.
        // Can now remove this PL...
      }
    
      std::vector<compressed_segment_t> jass_pl;

      // Count non-zero segments and compress them
      uint64_t valid_segments = 0;
      for (size_t j = 0; j < pl_segments.size(); ++j) {
        if (pl_segments[j].size() == 0)
          continue;
      
        // Give the buffer double + some incase of overflow
        std::vector<uint32_t> compressed_segment (2 * pl_segments[j].size() + 1024);
        uint64_t used = compressed_segment.size() * sizeof(compressed_segment[0]);
       
        // Delta encode the document identifiers
        fastDelta(pl_segments[j].data(), pl_segments[j].size()); 
        compressor.encodeArray(pl_segments[j].data(), pl_segments[j].size(), compressed_segment.data(), &used);

        uint64_t used_padded = ((used + sse_alignment - 1) / sse_alignment) * sse_alignment;  // SSE alignment
        // Resize to padded size
        size_t elements = used_padded/sizeof(uint32_t);
        compressed_segment.resize(elements);
        uint16_t impact = j + 1;
        uint32_t frequency = pl_segments[j].size();
        
        jass_pl.emplace_back(impact, frequency, used, used_padded, std::move(compressed_segment));
           
      } 
      // Tell vocab how many segments are here
      valid_segments = jass_pl.size();
      vocab.write((char *)&valid_segments, sizeof(uint64_t));
 
      // We can now write our PL's to file
      // 1. Write the k pointers to headers via arithmetic
      uint32_t header_size = sizeof(uint16_t) + sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint32_t);
      // Address of the first header is the (number of headers * size of the pointer) + current postings offset.
      uint64_t header_pointer = valid_segments * sizeof(uint64_t) + pl_offset;
      for (size_t i = 0; i < valid_segments; ++i) {
        postings.write((char *)&header_pointer, sizeof(uint64_t));
        header_pointer += header_size;
      }


      uint64_t posting_offset = header_size * (valid_segments + 1) + valid_segments * sizeof(uint64_t) + pl_offset;
      // Ensure SSE alignment is OK
      size_t sse_offset = ((posting_offset + sse_alignment - 1)/sse_alignment) * sse_alignment;
      size_t sse_padding = sse_offset - posting_offset;
      posting_offset = sse_offset;

      // 2. Let's write the header quads now
      for (size_t i = 0; i < jass_pl.size(); ++i) {
        uint16_t impact = jass_pl[i].impact;
        uint32_t frequency = jass_pl[i].frequency;
        uint64_t length = jass_pl[i].length;
        uint64_t length_with_padding = jass_pl[i].length_with_padding;
        uint64_t end = posting_offset + length;
      
        // Write the data
        postings.write((char *)&impact, sizeof(uint16_t));
        postings.write((char *)&posting_offset, sizeof(uint64_t));
        postings.write((char *)&end, sizeof(uint64_t));
        postings.write((char *)&frequency, sizeof(uint32_t));

        // Update offsets for next round
        posting_offset += length_with_padding;

      }

      // Don't forget the zero block
      uint8_t zero_block[] = {0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0};
      postings.write((char *)&zero_block, header_size);

      // More SSE checks
      if (sse_padding != 0) {
        if (sse_padding > sizeof(zero_block)) {
          std::cerr << "Padding is too large (sorry). Fix the code." << std::endl;
          exit(EXIT_FAILURE);
        }
        // Pad some more zeros
        postings.write((char *)zero_block, sse_padding);
      }

      // 4.  Now we write the actual postings lists
      for (size_t i = 0; i < jass_pl.size(); ++i) {
        postings.write((char *)jass_pl[i].compressed_ids.data(), jass_pl[i].length_with_padding);
      }
  
      pl_offset = postings.tellp();

    } 
}

// Assembly:
subq $0xd78, %rsp            # imm = 0xD78
movq %rsi, 0x218(%rsp)
movq %rdi, 0x220(%rsp)
movb %dl, %al
movq %rdi, 0xd70(%rsp)
movq %rsi, 0xd68(%rsp)
vmovsd %xmm0, 0xd60(%rsp)
movb %al, 0xd5f(%rsp)
movsbl 0xd5f(%rsp), %eax
cmpl $0x71, %eax
jne 0x29e5
movl $0x18, %edi
callq 0x2180
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x210(%rsp)
callq 0xa580
jmp 0x29a5
movq 0x210(%rsp), %rax
movq %rax, 0xd50(%rsp)
jmp 0x2ad8
movq 0x210(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
movl $0x18, %esi
callq 0x2190
jmp 0x42eb
movsbl 0xd5f(%rsp), %eax
cmpl $0x47, %eax
jne 0x2a58
movl $0x8, %edi
callq 0x2180
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x208(%rsp)
movq $0x0, (%rdi)
callq 0x4f00
jmp 0x2a18
movq 0x208(%rsp), %rax
movq %rax, 0xd50(%rsp)
jmp 0x2ad6
movq 0x208(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
movl $0x8, %esi
callq 0x2190
jmp 0x42eb
movsbl 0xd5f(%rsp), %eax
cmpl $0x67, %eax
jne 0x2ac8
movl $0x8, %edi
callq 0x2180
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x200(%rsp)
movq $0x0, (%rdi)
callq 0x4f30
jmp 0x2a8b
movq 0x200(%rsp), %rax
movq %rax, 0xd50(%rsp)
jmp 0x2ad4
movq 0x200(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
movl $0x8, %esi
callq 0x2190
jmp 0x42eb
movq $0x0, 0xd50(%rsp)
jmp 0x2ad6
jmp 0x2ad8
movq 0xd50(%rsp), %rax
movq %rax, 0xd38(%rsp)
movl $0x10, 0xd34(%rsp)
leaq 0xd18(%rsp), %rdi
callq 0x4f60
movq 0x218(%rsp), %rsi
leaq 0xb10(%rsp), %rdi
movl $0x8, %edx
callq 0x22d0
jmp 0x2b1c
leaq 0xaf0(%rsp), %rdi
callq 0x2270
movl $0x0, 0xaec(%rsp)
leaq 0xb10(%rsp), %rdi
leaq 0xaf0(%rsp), %rsi
callq 0x2220
movq %rax, 0x1f8(%rsp)
jmp 0x2b53
movq 0x1f8(%rsp), %rdi
movq (%rdi), %rax
movq -0x18(%rax), %rax
addq %rax, %rdi
callq 0x2210
movb %al, 0x1f7(%rsp)
jmp 0x2b73
movb 0x1f7(%rsp), %al
testb $0x1, %al
jne 0x2b80
jmp 0x2be4
leaq 0xd18(%rsp), %rdi
leaq 0xaf0(%rsp), %rsi
leaq 0xaec(%rsp), %rdx
callq 0x4f70
jmp 0x2b9f
movl 0xaec(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xaec(%rsp)
jmp 0x2b34
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x42de
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x42c4
movq 0x3083fd(%rip), %rdi    # 0x30afe8
leaq 0x301433(%rip), %rsi    # 0x304025
callq 0x2170
movq %rax, 0x1e8(%rsp)
jmp 0x2c01
leaq 0xd18(%rsp), %rdi
callq 0x4ff0
movq 0x1e8(%rsp), %rdi
movq %rax, %rsi
callq 0x2050
movq %rax, 0x1e0(%rsp)
jmp 0x2c28
movq 0x1e0(%rsp), %rdi
leaq 0x3013f4(%rip), %rsi    # 0x30402b
callq 0x2170
jmp 0x2c3e
movq 0x220(%rsp), %rsi
leaq 0x3013e7(%rip), %rdx    # 0x304034
leaq 0xac8(%rsp), %rdi
callq 0x5010
jmp 0x2c5c
movq 0x220(%rsp), %rsi
leaq 0x3013cf(%rip), %rdx    # 0x30403a
leaq 0xaa8(%rsp), %rdi
callq 0x5010
jmp 0x2c7a
movq 0x220(%rsp), %rsi
leaq 0x3013b8(%rip), %rdx    # 0x304041
leaq 0xa88(%rsp), %rdi
callq 0x5010
jmp 0x2c98
leaq 0xac8(%rsp), %rdi
callq 0x20b0
movq %rax, %rdi
leaq 0x301399(%rip), %rsi    # 0x304048
callq 0x21e0
movq %rax, 0x1d8(%rsp)
jmp 0x2cbe
movq 0x1d8(%rsp), %rax
movq %rax, 0xa80(%rsp)
leaq 0xaa8(%rsp), %rdi
callq 0x20b0
movq %rax, %rdi
leaq 0x301363(%rip), %rsi    # 0x304048
callq 0x21e0
movq %rax, 0x1d0(%rsp)
jmp 0x2cf4
movq 0x1d0(%rsp), %rax
movq %rax, 0xa78(%rsp)
leaq 0xa88(%rsp), %rdi
callq 0x20b0
movq %rax, %rdi
leaq 0x30132d(%rip), %rsi    # 0x304048
callq 0x21e0
movq %rax, 0x1c8(%rsp)
jmp 0x2d2a
movq 0x1c8(%rsp), %rax
movq %rax, 0xa70(%rsp)
leaq 0xa58(%rsp), %rdi
movq %rdi, 0x1c0(%rsp)
callq 0x50a0
leaq 0xa40(%rsp), %rdi
callq 0x50a0
leaq 0xa28(%rsp), %rdi
callq 0x50a0
movq 0x1c0(%rsp), %rdi
movq $0x0, 0xa20(%rsp)
movq 0xa80(%rsp), %rsi
callq 0x25f0
jmp 0x2d8c
xorl %eax, %eax
movl %eax, %esi
leaq 0xa58(%rsp), %rdi
callq 0x50b0
movl (%rax), %eax
movl %eax, 0xa1c(%rsp)
movq 0xa70(%rsp), %rsi
leaq 0xa28(%rsp), %rdi
callq 0x25f0
jmp 0x2dbd
leaq 0xa28(%rsp), %rdi
callq 0x50d0
movl 0xa1c(%rsp), %ecx
cmpq %rcx, %rax
je 0x2e7b
movq 0x308207(%rip), %rdi    # 0x30afe8
leaq 0x301263(%rip), %rsi    # 0x30404b
callq 0x2170
movq %rax, 0x1b8(%rsp)
jmp 0x2df7
movq 0x1b8(%rsp), %rdi
movq 0x3081b2(%rip), %rsi    # 0x30afb8
callq 0x21a0
jmp 0x2e0d
movl $0x1, %edi
callq 0x21f0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x42b7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x42aa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x429d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x4276
movq 0x308166(%rip), %rdi    # 0x30afe8
leaq 0x3011f9(%rip), %rsi    # 0x304082
callq 0x2170
movq %rax, 0x1b0(%rsp)
jmp 0x2e98
movq 0x1b0(%rsp), %rdi
movl 0xa1c(%rsp), %esi
callq 0x2250
movq %rax, 0x1a8(%rsp)
jmp 0x2eb6
movq 0x1a8(%rsp), %rdi
leaq 0x3011c9(%rip), %rsi    # 0x30408e
callq 0x2170
movq %rax, 0x1a0(%rsp)
jmp 0x2ed4
movq 0x1a0(%rsp), %rdi
movq 0x3080d5(%rip), %rsi    # 0x30afb8
callq 0x21a0
jmp 0x2eea
leaq 0xa28(%rsp), %rdi
movq %rdi, 0x190(%rsp)
callq 0x5160
movq 0x190(%rsp), %rdi
movq %rax, 0xa10(%rsp)
callq 0x5190
movq %rax, 0xa08(%rsp)
movq 0xa10(%rsp), %rdi
movq 0xa08(%rsp), %rsi
vxorps %xmm0, %xmm0, %xmm0
callq 0x50f0
vmovsd %xmm0, 0x198(%rsp)
jmp 0x2f40
vmovsd 0x198(%rsp), %xmm0
movl 0xa1c(%rsp), %eax
vcvtsi2sd %rax, %xmm1, %xmm1
vdivsd %xmm1, %xmm0, %xmm1
vcvtsd2ss %xmm1, %xmm0, %xmm0
vmovss %xmm0, 0xa18(%rsp)
movl 0xa1c(%rsp), %eax
vcvtsi2ss %rax, %xmm0, %xmm0
vmovss 0xa18(%rsp), %xmm1
leaq 0xa00(%rsp), %rdi
callq 0x51c0
jmp 0x2f8a
movl $0x0, 0xaec(%rsp)
movq 0xa80(%rsp), %rdi
callq 0x22c0
cmpl $0x0, %eax
setne %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x2fb3
jmp 0x3365
movq 0xa80(%rsp), %rsi
leaq 0xa58(%rsp), %rdi
callq 0x25f0
jmp 0x2fca
movq 0xa78(%rsp), %rsi
leaq 0xa40(%rsp), %rdi
callq 0x25f0
jmp 0x2fe1
leaq 0xa58(%rsp), %rdi
callq 0x50d0
movq %rax, 0x9f8(%rsp)
leaq 0xa40(%rsp), %rdi
callq 0x50d0
movq %rax, 0x9f0(%rsp)
movq 0x9f8(%rsp), %rax
cmpq 0x9f0(%rsp), %rax
je 0x303c
movq 0x307fc4(%rip), %rdi    # 0x30afe8
leaq 0x30106f(%rip), %rsi    # 0x30409a
callq 0x2170
jmp 0x3032
movl $0x1, %edi
callq 0x21f0
cmpq $0x0, 0x9f8(%rsp)
jne 0x30b5
movl 0xaec(%rsp), %eax
movq %rax, 0x188(%rsp)
leaq 0xd18(%rsp), %rdi
callq 0x4ff0
movq %rax, %rcx
movq 0x188(%rsp), %rax
cmpq %rcx, %rax
je 0x30b0
movq 0x307f6e(%rip), %rdi    # 0x30afe8
leaq 0x301031(%rip), %rsi    # 0x3040b2
callq 0x2170
movq %rax, 0x180(%rsp)
jmp 0x3090
movq 0x180(%rsp), %rdi
movq 0x307f19(%rip), %rsi    # 0x30afb8
callq 0x21a0
jmp 0x30a6
movl $0x1, %edi
callq 0x21f0
jmp 0x3365
movq 0x9f8(%rsp), %rax
vcvtsi2ss %rax, %xmm0, %xmm0
vmovss %xmm0, 0x178(%rsp)
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
vcvtsi2ss %rcx, %xmm0, %xmm0
vaddss %xmm0, %xmm0, %xmm0
testq %rax, %rax
vmovss %xmm0, 0x17c(%rsp)
js 0x3102
vmovss 0x178(%rsp), %xmm0
vmovss %xmm0, 0x17c(%rsp)
vmovss 0x17c(%rsp), %xmm0
leaq 0xa00(%rsp), %rdi
callq 0x51f0
vmovss %xmm0, 0x174(%rsp)
jmp 0x3123
vmovss 0x174(%rsp), %xmm0
vmovss %xmm0, 0x9ec(%rsp)
movl 0xaec(%rsp), %eax
movl %eax, %esi
leaq 0xd18(%rsp), %rdi
callq 0x5260
addq $0x28, %rax
movq %rax, 0x168(%rsp)
leaq 0xa58(%rsp), %rdi
callq 0x50d0
movq 0x168(%rsp), %rdi
movq %rax, %rsi
callq 0x5280
jmp 0x3176
movq $0x0, 0x9e0(%rsp)
movq 0x9e0(%rsp), %rax
movq %rax, 0x160(%rsp)
leaq 0xa58(%rsp), %rdi
callq 0x50d0
movq %rax, %rcx
movq 0x160(%rsp), %rax
cmpq %rcx, %rax
jae 0x334f
movq 0x9e0(%rsp), %rsi
leaq 0xa58(%rsp), %rdi
callq 0x50b0
movl (%rax), %eax
movl %eax, 0x9dc(%rsp)
movq 0x9e0(%rsp), %rsi
leaq 0xa40(%rsp), %rdi
callq 0x50b0
movl (%rax), %eax
movl %eax, 0x9d8(%rsp)
vmovss 0x9ec(%rsp), %xmm0
vmovss %xmm0, 0x154(%rsp)
movl 0x9d8(%rsp), %eax
vcvtsi2ss %rax, %xmm0, %xmm0
vmovss %xmm0, 0x158(%rsp)
movl 0x9dc(%rsp), %eax
movl %eax, %esi
leaq 0xa28(%rsp), %rdi
callq 0x50b0
vmovss 0x158(%rsp), %xmm0
movl (%rax), %eax
vcvtsi2ss %rax, %xmm1, %xmm1
leaq 0xa00(%rsp), %rdi
callq 0x5320
vmovss %xmm0, 0x15c(%rsp)
jmp 0x3254
vmovss 0x154(%rsp), %xmm0
vmovss 0x15c(%rsp), %xmm1
vmulss %xmm1, %xmm0, %xmm1
vcvtss2sd %xmm1, %xmm0, %xmm0
vmovsd %xmm0, 0x9d0(%rsp)
leaq 0xa20(%rsp), %rdi
leaq 0x9d0(%rsp), %rsi
callq 0x5390
movq %rax, 0x148(%rsp)
jmp 0x3296
movq 0x148(%rsp), %rax
vmovsd (%rax), %xmm0
vmovsd %xmm0, 0xa20(%rsp)
movl 0x9dc(%rsp), %eax
movl %eax, 0x13c(%rsp)
movl 0xaec(%rsp), %eax
movl %eax, %esi
leaq 0xd18(%rsp), %rdi
callq 0x5260
movq %rax, %rdi
addq $0x28, %rdi
movq 0x9e0(%rsp), %rsi
callq 0x53d0
movl 0x13c(%rsp), %ecx
movl %ecx, (%rax)
vmovsd 0x9d0(%rsp), %xmm0
vmovsd %xmm0, 0x140(%rsp)
movl 0xaec(%rsp), %eax
movl %eax, %esi
leaq 0xd18(%rsp), %rdi
callq 0x5260
movq %rax, %rdi
addq $0x28, %rdi
movq 0x9e0(%rsp), %rsi
callq 0x53d0
vmovsd 0x140(%rsp), %xmm0
vmovsd %xmm0, 0x8(%rax)
movq 0x9e0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x9e0(%rsp)
jmp 0x3182
movl 0xaec(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xaec(%rsp)
jmp 0x2f95
movq 0x307c7c(%rip), %rdi    # 0x30afe8
leaq 0x300d68(%rip), %rsi    # 0x3040db
callq 0x2170
movq %rax, 0x130(%rsp)
jmp 0x3382
movq 0x130(%rsp), %rdi
vmovsd 0xa20(%rsp), %xmm0
callq 0x2340
movq %rax, 0x128(%rsp)
jmp 0x33a2
movq 0x128(%rsp), %rdi
movq 0x307c07(%rip), %rsi    # 0x30afb8
callq 0x21a0
jmp 0x33b8
movq 0x307c29(%rip), %rdi    # 0x30afe8
leaq 0x300d26(%rip), %rsi    # 0x3040ec
callq 0x2170
movq %rax, 0x120(%rsp)
jmp 0x33d5
movq 0x120(%rsp), %rdi
vmovsd 0xd60(%rsp), %xmm0
callq 0x2340
movq %rax, 0x118(%rsp)
jmp 0x33f5
movq 0x118(%rsp), %rdi
leaq 0x300d02(%rip), %rsi    # 0x304106
callq 0x2170
movq %rax, 0x110(%rsp)
jmp 0x3413
movq 0x110(%rsp), %rdi
movq 0x307b96(%rip), %rsi    # 0x30afb8
callq 0x21a0
jmp 0x3429
movq $0x0, 0x9c8(%rsp)
movq 0x9c8(%rsp), %rax
movq %rax, 0x108(%rsp)
leaq 0xd18(%rsp), %rdi
callq 0x4ff0
movq %rax, %rcx
movq 0x108(%rsp), %rax
cmpq %rcx, %rax
jae 0x358a
movq $0x0, 0x9c0(%rsp)
movq 0x9c0(%rsp), %rax
movq %rax, 0x100(%rsp)
movq 0x9c8(%rsp), %rsi
leaq 0xd18(%rsp), %rdi
callq 0x5260
movq %rax, %rdi
addq $0x28, %rdi
callq 0x53f0
movq %rax, %rcx
movq 0x100(%rsp), %rax
cmpq %rcx, %rax
jae 0x356f
movq 0x9c8(%rsp), %rsi
leaq 0xd18(%rsp), %rdi
callq 0x5260
movq %rax, %rdi
addq $0x28, %rdi
movq 0x9c0(%rsp), %rsi
callq 0x53d0
vmovsd 0x8(%rax), %xmm0
vmovsd %xmm0, 0x9b8(%rsp)
vmovsd 0xd60(%rsp), %xmm0
vmovsd 0x9b8(%rsp), %xmm1
vmulsd %xmm1, %xmm0, %xmm0
vmovsd 0xa20(%rsp), %xmm1
vdivsd %xmm1, %xmm0, %xmm1
vroundsd $0xa, %xmm1, %xmm0, %xmm0
vcvttsd2si %xmm0, %rax
movl %eax, 0xfc(%rsp)
movq 0x9c8(%rsp), %rsi
leaq 0xd18(%rsp), %rdi
callq 0x5260
movq %rax, %rdi
addq $0x28, %rdi
movq 0x9c0(%rsp), %rsi
callq 0x53d0
movl 0xfc(%rsp), %ecx
movl %ecx, 0x10(%rax)
movq 0x9c0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x9c0(%rsp)
jmp 0x3472
jmp 0x3571
movq 0x9c8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x9c8(%rsp)
jmp 0x3435
leaq 0x300b77(%rip), %rsi    # 0x304108
leaq 0x7b8(%rsp), %rdi
movl $0x10, %edx
callq 0x21c0
jmp 0x35a5
leaq 0x300b6e(%rip), %rsi    # 0x30411a
leaq 0x5b8(%rsp), %rdi
movl $0x4, %edx
callq 0x21c0
jmp 0x35c0
leaq 0x300b5f(%rip), %rsi    # 0x304126
leaq 0x3b8(%rsp), %rdi
movl $0x4, %edx
callq 0x21c0
jmp 0x35db
movq $0x0, 0x3b0(%rsp)
movq $0x0, 0x3a8(%rsp)
leaq 0x3b8(%rsp), %rdi
leaq 0xd5f(%rsp), %rsi
movl $0x1, %edx
callq 0x2240
jmp 0x360f
leaq 0x3b8(%rsp), %rdi
callq 0x2140
movq %rdx, 0xe8(%rsp)
movq %rax, 0xf0(%rsp)
jmp 0x362e
movq 0xe8(%rsp), %rax
movq 0xf0(%rsp), %rcx
movq %rcx, 0x398(%rsp)
movq %rax, 0x3a0(%rsp)
leaq 0x398(%rsp), %rdi
callq 0x4e50
movq %rax, 0xe0(%rsp)
jmp 0x3665
movq 0xe0(%rsp), %rax
movq %rax, 0x3a8(%rsp)
movq $0x0, 0x390(%rsp)
movq 0x390(%rsp), %rax
movq %rax, 0xd8(%rsp)
leaq 0xd18(%rsp), %rdi
callq 0x4ff0
movq %rax, %rcx
movq 0xd8(%rsp), %rax
cmpq %rcx, %rax
jae 0x41ab
movq 0x390(%rsp), %rsi
leaq 0xd18(%rsp), %rdi
callq 0x5260
movq %rax, %rsi
leaq 0x370(%rsp), %rdi
callq 0x20c0
jmp 0x36d9
leaq 0x5b8(%rsp), %rdi
leaq 0x3b0(%rsp), %rsi
movl $0x8, %edx
callq 0x2240
jmp 0x36f5
leaq 0x5b8(%rsp), %rdi
leaq 0x3a8(%rsp), %rsi
movl $0x8, %edx
callq 0x2240
jmp 0x3711
leaq 0x7b8(%rsp), %rdi
leaq 0x370(%rsp), %rsi
callq 0x2160
movq %rax, 0xd0(%rsp)
jmp 0x3730
movq 0xd0(%rsp), %rdi
xorl %esi, %esi
callq 0x21d0
jmp 0x3741
leaq 0x7b8(%rsp), %rdi
callq 0x2140
movq %rdx, 0xc0(%rsp)
movq %rax, 0xc8(%rsp)
jmp 0x3760
movq 0xc0(%rsp), %rax
movq 0xc8(%rsp), %rcx
movq %rcx, 0x360(%rsp)
movq %rax, 0x368(%rsp)
leaq 0x360(%rsp), %rdi
callq 0x4e50
movq %rax, 0xb8(%rsp)
jmp 0x3797
movq 0xb8(%rsp), %rax
movq %rax, 0x3b0(%rsp)
vcvttsd2si 0xd60(%rsp), %rax
movl %eax, 0x35c(%rsp)
movl 0x35c(%rsp), %eax
movq %rax, 0xa8(%rsp)
leaq 0x33f(%rsp), %rdi
movq %rdi, 0xb0(%rsp)
callq 0x5410
movq 0xa8(%rsp), %rsi
movq 0xb0(%rsp), %rdx
leaq 0x340(%rsp), %rdi
callq 0x5420
jmp 0x37fb
leaq 0x33f(%rsp), %rdi
callq 0x54a0
movq $0x0, 0x330(%rsp)
movq 0x330(%rsp), %rax
movq %rax, 0xa0(%rsp)
movq 0x390(%rsp), %rsi
leaq 0xd18(%rsp), %rdi
callq 0x5260
movq %rax, %rdi
addq $0x28, %rdi
callq 0x53f0
movq %rax, %rcx
movq 0xa0(%rsp), %rax
cmpq %rcx, %rax
jae 0x39be
movq 0x390(%rsp), %rsi
leaq 0xd18(%rsp), %rdi
movq %rdi, 0x98(%rsp)
callq 0x5260
movq %rax, %rdi
addq $0x28, %rdi
movq 0x330(%rsp), %rsi
callq 0x53d0
movq 0x98(%rsp), %rdi
movl 0x10(%rax), %eax
decl %eax
movl %eax, 0x32c(%rsp)
movq 0x390(%rsp), %rsi
callq 0x5260
movq %rax, %rdi
addq $0x28, %rdi
movq 0x330(%rsp), %rsi
callq 0x53d0
movl (%rax), %eax
movl %eax, 0x328(%rsp)
movl 0x32c(%rsp), %eax
movl %eax, %esi
leaq 0x340(%rsp), %rdi
callq 0x54b0
movq %rax, %rdi
movl 0x328(%rsp), %eax
incl %eax
movl %eax, 0x324(%rsp)
leaq 0x324(%rsp), %rsi
callq 0x54d0
jmp 0x3900
jmp 0x3902
movq 0x330(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x330(%rsp)
jmp 0x3814
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x4269
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x425c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x424f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x4199
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
leaq 0x33f(%rsp), %rdi
callq 0x54a0
jmp 0x4199
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x418c
leaq 0x308(%rsp), %rdi
callq 0x5500
movq $0x0, 0x300(%rsp)
movq $0x0, 0x2f8(%rsp)
movq 0x2f8(%rsp), %rax
movq %rax, 0x90(%rsp)
leaq 0x340(%rsp), %rdi
callq 0x5510
movq %rax, %rcx
movq 0x90(%rsp), %rax
cmpq %rcx, %rax
jae 0x3cc6
movq 0x2f8(%rsp), %rsi
leaq 0x340(%rsp), %rdi
callq 0x54b0
movq %rax, %rdi
callq 0x50d0
cmpq $0x0, %rax
jne 0x3a3c
jmp 0x3c61
movq 0x2f8(%rsp), %rsi
leaq 0x340(%rsp), %rdi
callq 0x54b0
movq %rax, %rdi
callq 0x50d0
leaq 0x400(%rax,%rax), %rax
movq %rax, 0x80(%rsp)
leaq 0x2df(%rsp), %rdi
movq %rdi, 0x88(%rsp)
callq 0x5530
movq 0x80(%rsp), %rsi
movq 0x88(%rsp), %rdx
leaq 0x2e0(%rsp), %rdi
callq 0x5540
jmp 0x3a9d
leaq 0x2df(%rsp), %rdi
callq 0x55c0
leaq 0x2e0(%rsp), %rdi
callq 0x50d0
shlq $0x2, %rax
movq %rax, 0x2d0(%rsp)
movq 0x2f8(%rsp), %rsi
leaq 0x340(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x54b0
movq %rax, %rdi
callq 0x4df0
movq 0x70(%rsp), %rdi
movq %rax, 0x78(%rsp)
movq 0x2f8(%rsp), %rsi
callq 0x54b0
movq %rax, %rdi
callq 0x50d0
movq 0x78(%rsp), %rdi
movq %rax, %rsi
callq 0x4300
jmp 0x3b13
movq 0xd38(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x2f8(%rsp), %rsi
leaq 0x340(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x54b0
movq %rax, %rdi
callq 0x4df0
movq 0x50(%rsp), %rdi
movq %rax, 0x60(%rsp)
movq 0x2f8(%rsp), %rsi
callq 0x54b0
movq %rax, %rdi
callq 0x50d0
movq %rax, 0x68(%rsp)
leaq 0x2e0(%rsp), %rdi
callq 0x4df0
movq 0x58(%rsp), %rdi
movq 0x60(%rsp), %rsi
movq 0x68(%rsp), %rdx
movq %rax, %rcx
movq (%rdi), %rax
movq 0x10(%rax), %rax
leaq 0x2d0(%rsp), %r8
callq *%rax
jmp 0x3b98
movq 0x2d0(%rsp), %rax
movl 0xd34(%rsp), %ecx
leaq -0x1(%rax,%rcx), %rax
xorl %edx, %edx
divq %rcx
imulq %rcx, %rax
movq %rax, 0x2c8(%rsp)
movq 0x2c8(%rsp), %rax
shrq $0x2, %rax
movq %rax, 0x2c0(%rsp)
movq 0x2c0(%rsp), %rsi
leaq 0x2e0(%rsp), %rdi
callq 0x4d50
jmp 0x3be8
movl 0x2f8(%rsp), %eax
incl %eax
movw %ax, 0x2be(%rsp)
movq 0x2f8(%rsp), %rsi
leaq 0x340(%rsp), %rdi
callq 0x54b0
movq %rax, %rdi
callq 0x50d0
movl %eax, 0x2b8(%rsp)
leaq 0x308(%rsp), %rdi
leaq 0x2be(%rsp), %rsi
leaq 0x2b8(%rsp), %rdx
leaq 0x2d0(%rsp), %rcx
leaq 0x2c8(%rsp), %r8
leaq 0x2e0(%rsp), %r9
callq 0x55d0
jmp 0x3c54
leaq 0x2e0(%rsp), %rdi
callq 0x5690
movq 0x2f8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x2f8(%rsp)
jmp 0x39e3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
leaq 0x2df(%rsp), %rdi
callq 0x55c0
jmp 0x417f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
leaq 0x2e0(%rsp), %rdi
callq 0x5690
jmp 0x417f
leaq 0x308(%rsp), %rdi
callq 0x56f0
movq %rax, 0x300(%rsp)
leaq 0x5b8(%rsp), %rdi
leaq 0x300(%rsp), %rsi
movl $0x8, %edx
callq 0x2240
jmp 0x3cf7
movl $0x16, 0x2b4(%rsp)
movq 0x300(%rsp), %rax
shlq $0x3, %rax
addq 0x3a8(%rsp), %rax
movq %rax, 0x2a8(%rsp)
movq $0x0, 0x2a0(%rsp)
movq 0x2a0(%rsp), %rax
cmpq 0x300(%rsp), %rax
jae 0x3d9e
leaq 0x3b8(%rsp), %rdi
leaq 0x2a8(%rsp), %rsi
movl $0x8, %edx
callq 0x2240
jmp 0x3d58
movl 0x2b4(%rsp), %eax
addq 0x2a8(%rsp), %rax
movq %rax, 0x2a8(%rsp)
movq 0x2a0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x2a0(%rsp)
jmp 0x3d2a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd48(%rsp)
movl %eax, 0xd44(%rsp)
jmp 0x417f
movl 0x2b4(%rsp), %eax
movq 0x300(%rsp), %rcx
addq $0x1, %rcx
imulq %rcx, %rax
movq 0x300(%rsp), %rcx
shlq $0x3, %rcx
addq %rcx, %rax
addq 0x3a8(%rsp), %rax
movq %rax, 0x298(%rsp)
movq 0x298(%rsp), %rax
movl 0xd34(%rsp), %ecx
addq %rcx, %rax
subq $0x1, %rax
movl 0xd34(%rsp), %ecx
xorl %edx, %edx
divq %rcx
movl 0xd34(%rsp), %ecx
imulq %rcx, %rax
movq %rax, 0x290(%rsp)
movq 0x290(%rsp), %rax
subq 0x298(%rsp), %rax
movq %rax, 0x288(%rsp)
movq 0x290(%rsp), %rax
movq %rax, 0x298(%rsp)
movq $0x0, 0x280(%rsp)
movq 0x280(%rsp), %rax
movq %rax, 0x48(%rsp)
leaq 0x308(%rsp), %rdi
callq 0x56f0
movq %rax, %rcx
movq 0x48(%rsp), %rax
cmpq %rcx, %rax
jae 0x3fa1
movq 0x280(%rsp), %rsi
leaq 0x308(%rsp), %rdi
movq %rdi, 0x40(%rsp)
callq 0x5710
movq 0x40(%rsp), %rdi
movw (%rax), %ax
movw %ax, 0x27e(%rsp)
movq 0x280(%rsp), %rsi
callq 0x5710
movq 0x40(%rsp), %rdi
movl 0x4(%rax), %eax
movl %eax, 0x278(%rsp)
movq 0x280(%rsp), %rsi
callq 0x5710
movq 0x40(%rsp), %rdi
movq 0x8(%rax), %rax
movq %rax, 0x270(%rsp)
movq 0x280(%rsp), %rsi
callq 0x5710
movq 0x10(%rax), %rax
movq %rax, 0x268(%rsp)
movq 0x298(%rsp), %rax
movq 0x270(%rsp), %rcx
addq %rcx, %rax
movq %rax, 0x260(%rsp)
leaq 0x3b8(%rsp), %rdi
leaq 0x27e(%rsp), %rsi
movl $0x2, %edx
callq 0x2240
jmp 0x3f1c
leaq 0x3b8(%rsp), %rdi
leaq 0x298(%rsp), %rsi
movl $0x8, %edx
callq 0x2240
jmp 0x3f38
leaq 0x3b8(%rsp), %rdi
leaq 0x260(%rsp), %rsi
movl $0x8, %edx
callq 0x2240
jmp 0x3f54
leaq 0x3b8(%rsp), %rdi
leaq 0x278(%rsp), %rsi
movl $0x4, %edx
callq 0x2240
jmp 0x3f70
movq 0x268(%rsp), %rax
addq 0x298(%rsp), %rax
movq %rax, 0x298(%rsp)
movq 0x280(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x280(%rsp)
jmp 0x3e3d
vxorps %xmm0, %xmm0, %xmm0
vmovdqa %xmm0, 0x240(%rsp)
movq $0x0, 0x24e(%rsp)
movl 0x2b4(%rsp), %eax
movl %eax, %edx
leaq 0x3b8(%rsp), %rdi
leaq 0x240(%rsp), %rsi
callq 0x2240
jmp 0x3fda
cmpq $0x0, 0x288(%rsp)
je 0x4048
cmpq $0x16, 0x288(%rsp)
jbe 0x4027
movq 0x306ff1(%rip), %rdi    # 0x30afe8
leaq 0x300137(%rip), %rsi    # 0x304135
callq 0x2170
movq %rax, 0x38(%rsp)
jmp 0x400a
movq 0x38(%rsp), %rdi
movq 0x306fa2(%rip), %rsi    # 0x30afb8
callq 0x21a0
jmp 0x401d
movl $0x1, %edi
callq 0x21f0
movq 0x288(%rsp), %rdx
leaq 0x3b8(%rsp), %rdi
leaq 0x240(%rsp), %rsi
callq 0x2240
jmp 0x4046
jmp 0x4048
movq $0x0, 0x238(%rsp)
movq 0x238(%rsp), %rax
movq %rax, 0x30(%rsp)
leaq 0x308(%rsp), %rdi
callq 0x56f0
movq %rax, %rcx
movq 0x30(%rsp), %rax
cmpq %rcx, %rax
jae 0x40eb
movq 0x238(%rsp), %rsi
leaq 0x308(%rsp), %rdi
movq %rdi, 0x20(%rsp)
callq 0x5710
movq %rax, %rdi
addq $0x18, %rdi
callq 0x4df0
movq 0x20(%rsp), %rdi
movq %rax, 0x28(%rsp)
movq 0x238(%rsp), %rsi
callq 0x5710
movq 0x28(%rsp), %rsi
movq 0x10(%rax), %rdx
leaq 0x3b8(%rsp), %rdi
callq 0x2240
jmp 0x40d0
jmp 0x40d2
movq 0x238(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x238(%rsp)
jmp 0x4054
leaq 0x3b8(%rsp), %rdi
callq 0x2140
movq %rdx, 0x10(%rsp)
movq %rax, 0x18(%rsp)
jmp 0x4104
movq 0x10(%rsp), %rax
movq 0x18(%rsp), %rcx
movq %rcx, 0x228(%rsp)
movq %rax, 0x230(%rsp)
leaq 0x228(%rsp), %rdi
callq 0x4e50
movq %rax, 0x8(%rsp)
jmp 0x4132
movq 0x8(%rsp), %rax
movq %rax, 0x3a8(%rsp)
leaq 0x308(%rsp), %rdi
callq 0x5730
leaq 0x340(%rsp), %rdi
callq 0x5790
leaq 0x370(%rsp), %rdi
callq 0x2110
movq 0x390(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x390(%rsp)
jmp 0x3681
leaq 0x308(%rsp), %rdi
callq 0x5730
leaq 0x340(%rsp), %rdi
callq 0x5790
leaq 0x370(%rsp), %rdi
callq 0x2110
jmp 0x424f
leaq 0x3b8(%rsp), %rdi
callq 0x2290
leaq 0x5b8(%rsp), %rdi
callq 0x2290
leaq 0x7b8(%rsp), %rdi
callq 0x2290
leaq 0xa28(%rsp), %rdi
callq 0x5690
leaq 0xa40(%rsp), %rdi
callq 0x5690
leaq 0xa58(%rsp), %rdi
callq 0x5690
leaq 0xa88(%rsp), %rdi
callq 0x2110
leaq 0xaa8(%rsp), %rdi
callq 0x2110
leaq 0xac8(%rsp), %rdi
callq 0x2110
leaq 0xaf0(%rsp), %rdi
callq 0x2110
leaq 0xb10(%rsp), %rdi
callq 0x2060
leaq 0xd18(%rsp), %rdi
callq 0x57f0
addq $0xd78, %rsp            # imm = 0xD78
retq
leaq 0x3b8(%rsp), %rdi
callq 0x2290
leaq 0x5b8(%rsp), %rdi
callq 0x2290
leaq 0x7b8(%rsp), %rdi
callq 0x2290
leaq 0xa28(%rsp), %rdi
callq 0x5690
leaq 0xa40(%rsp), %rdi
callq 0x5690
leaq 0xa58(%rsp), %rdi
callq 0x5690
leaq 0xa88(%rsp), %rdi
callq 0x2110
leaq 0xaa8(%rsp), %rdi
callq 0x2110
leaq 0xac8(%rsp), %rdi
callq 0x2110
leaq 0xaf0(%rsp), %rdi
callq 0x2110
leaq 0xb10(%rsp), %rdi
callq 0x2060
leaq 0xd18(%rsp), %rdi
callq 0x57f0
movq 0xd48(%rsp), %rdi
callq 0x2310
nopl (%rax,%rax)