// File: jaudoux[P]countTags/src/countTags.cpp
// Function: main
int main (int argc, char *argv[]) {

  // Config vars
  const char * tags_file;
  const char * seq_file;
  uint32_t tag_length = 22;
  bool stranded = false;
  bool normalize = false;
  bool print_tag_names = false;
  uint32_t nb_tags = 0;
  uint32_t max_reads = UINT32_MAX;
  int nb_threads = 1;
  uint32_t nb_samples;
  uint32_t i;
  uint32_t read_id;

  char * seq;
  std::string tag_name;
  uint32_t seq_length;
  uint64_t tag;
  uint64_t valrev,valfwd;
  uint64_t nb_factors;
  int64_t last;
  std::unordered_map<uint64_t,double*>  tags_counts;
  std::unordered_map<uint64_t,std::vector<std::string>> tags_names;
  std::unordered_map<uint64_t,double*>::iterator it_counts;
  std::vector<uint64_t> nb_factors_by_sample;

  // File vars
  std::string gzip_pipe = "gunzip -fc ";
  std::string cat_pipe = "cat ";
  std::string tmp;
  FILE * file;
  char * line = NULL;
  size_t len = 0;
  ssize_t read;
  uint32_t line_id = 0;

  /**********************************
   *
   *        Parsing options
   *
   *********************************/
  argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
  option::Stats  stats(usage, argc, argv);
  option::Option options[stats.options_max], buffer[stats.buffer_max];
  option::Parser parse(usage, argc, argv, options, buffer);

  if (parse.error())
    return 1;

  if (options[HELP] || argc == 0) {
    option::printUsage(std::cout, usage);
    return 0;
  }

  // TODO we should check the length to choose the appropriate
  // integer size to use
  if (options[PROBE_LENGTH]) {
    tag_length = atoi(options[PROBE_LENGTH].arg);
  }

  if (options[MAX_READS]) {
    max_reads = atoi(options[MAX_READS].arg);
  }

  //if (options[NB_THREADS]) {
  //  nb_threads = atoi(options[NB_THREADS].arg);
  //}

  if (options[STRANDED]) {
    stranded = true;
  }

  if (options[NORMALIZE]) {
    normalize = true;
  }

  if (options[TAG_NAMES]) {
    print_tag_names = true;
  }

  if(parse.nonOptionsCount() < 2) {
    option::printUsage(std::cout, usage);
    return 0;
  }

  tags_file = parse.nonOption(0);
  nb_samples = parse.nonOptionsCount() - 1;

  /**********************************
   *
   *   Create tags counting table
   *
   *********************************/
  file = popen(tmp.append(cat_pipe).append(tags_file).c_str(),"r");
  line_id = 0;

  std::cerr << "Counting k-mers" << std::endl;
  // Create hash table of k-mer counts
  line_id = 0;
  nb_tags = 0;
  while ((read = getline(&line, &len, file)) != -1) {
    if(line_id % 2 == 0) {
      tag_name = line;
      tag_name.pop_back(); // remove new_line char
      tag_name.erase(0,1); // remove the fasta ">" prefix
    }
    if(line_id % 2 == 1) {
      tag = DNAtoInt(line,tag_length,stranded);
      tags_counts[tag] = new double[nb_samples]();
      tags_names[tag].push_back(tag_name);
      nb_tags++;
    }
    line_id++;
  }
  fclose(file);
  if (line)
    free(line);

  std::cerr << "Finished indexing tags" << std::endl;


  /**********************************
   *
   *            First pass
   *
   *********************************/
//#pragma omp parallel num_threads(nb_threads)
  for (int s = 0; s < nb_samples; ++s) {
    std::cerr << "Counting tags for file: " << parse.nonOption(s+1) << "\n";

    line = NULL;
    len = 0;
    line_id = 0;
    tmp = "";
    file = popen(tmp.append(gzip_pipe).append(parse.nonOption(s+1)).c_str(),"r");
    nb_factors = 0;

    while ((read = getline(&line, &len, file)) != -1) {
      // If this line is a sequence
      if(line_id % 4 == 1) {
        read_id = ((int)((double)line_id*0.25) + 1);
        if(read_id >= max_reads) {
          break;
        }
        // Print a user-friendly output on STDERR every each XXXX reads processed
        if(read_id % MILLION == 0) {
          std::cerr << (int)((double)line_id*0.25) + 1 << " reads parsed" << std::endl;
        }
        // set seq to line
        seq = line;
        seq_length = strlen(seq) - 1; // Minus 1 because we have a new line

        // Skip the sequence if the read length is < to the tag_length
        if(seq_length < tag_length)
          continue;

        nb_tags = seq_length - tag_length + 1;
        nb_factors += nb_tags;

        //uint64_t valrev,valfwd;
        last = -3;

        for(i = 0; i < nb_tags; i++) {
          it_counts = tags_counts.find(valns(i,seq,tag_length,&last,&valfwd,&valrev,stranded));
          if(it_counts != tags_counts.end()) {
            it_counts->second[s]++;
          }
        }
      }
      line_id++;
    }

    nb_factors_by_sample.push_back(nb_factors);

    if(normalize && nb_factors > 0) {
      std::cerr << "Normalize counts" << std::endl;
      for (it_counts=tags_counts.begin(); it_counts!=tags_counts.end(); ++it_counts) {
        // TODO We should take into accout the error rate...
        if(it_counts->second[s] > 0)
          it_counts->second[s] = it_counts->second[s] * MILLION / nb_factors;
      }
    }

    // Close file and clear line buffer
    fclose(file);
    if (line)
      free(line);
  }

  /****
   * PRINT THE RESULTS
   */
  // First print headers
  std::cout << "tag";
  if (print_tag_names)
    std::cout << "\ttag_names";
  for (int s = 0; s < nb_samples; ++s) {
    std::cout << "\t" << parse.nonOption(s+1);
  }
  std::cout << "\n";
  char *tag_seq = new char[tag_length];
  for (it_counts=tags_counts.begin(); it_counts!=tags_counts.end(); ++it_counts) {
    intToDNA(it_counts->first,tag_length,tag_seq);
    std::cout << tag_seq;
    if(print_tag_names) {
      std::cout << "\t" << join(tags_names[it_counts->first],",");
    }
    for (int s = 0; s < nb_samples; ++s) {
      std::cout << "\t" << it_counts->second[s];
    }
    std::cout << std::endl;
  }

  std::cout << "total_factors";
  if (print_tag_names)
    std::cout << "\t*";
  for (int s = 0; s < nb_samples; ++s) {
    std::cout << "\t" << nb_factors_by_sample[s];
  }
  std::cout << std::endl;

}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x440, %rsp            # imm = 0x440
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl $0x16, -0x24(%rbp)
movb $0x0, -0x25(%rbp)
movb $0x0, -0x26(%rbp)
movb $0x0, -0x27(%rbp)
movl $0x0, -0x2c(%rbp)
movl $0xffffffff, -0x30(%rbp) # imm = 0xFFFFFFFF
movl $0x1, -0x34(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x3320
leaq -0xd0(%rbp), %rdi
callq 0x4bd0
leaq -0x108(%rbp), %rdi
callq 0x4bf0
leaq -0x110(%rbp), %rdi
callq 0x4c10
jmp 0x3820
leaq -0x138(%rbp), %rdi
callq 0x4c30
leaq -0x159(%rbp), %rdi
movq %rdi, -0x288(%rbp)
callq 0x33c0
movq -0x288(%rbp), %rdx
leaq 0xb927(%rip), %rsi      # 0xf174
leaq -0x158(%rbp), %rdi
callq 0x4930
jmp 0x385b
leaq -0x159(%rbp), %rdi
callq 0x3230
leaq -0x181(%rbp), %rdi
movq %rdi, -0x290(%rbp)
callq 0x33c0
movq -0x290(%rbp), %rdx
leaq 0xb8f8(%rip), %rsi      # 0xf180
leaq -0x180(%rbp), %rdi
callq 0x4930
jmp 0x3896
leaq -0x181(%rbp), %rdi
callq 0x3230
leaq -0x1a8(%rbp), %rdi
callq 0x3320
movq $0x0, -0x1b8(%rbp)
movq $0x0, -0x1c0(%rbp)
movl $0x0, -0x1cc(%rbp)
movl -0x8(%rbp), %eax
testl %eax, %eax
setg %cl
movzbl %cl, %ecx
subl %ecx, %eax
movl %eax, -0x8(%rbp)
movl -0x8(%rbp), %eax
testl %eax, %eax
setg %cl
movq -0x10(%rbp), %rax
movzbl %cl, %ecx
leaq (%rax,%rcx,8), %rax
movq %rax, -0x10(%rbp)
movl -0x8(%rbp), %edx
movq -0x10(%rbp), %rcx
leaq 0x1325d(%rip), %rsi     # 0x16b60
leaq -0x1d4(%rbp), %rdi
xorl %r9d, %r9d
movl %r9d, %r8d
callq 0x4c50
jmp 0x3917
movl -0x1d0(%rbp), %eax
movq %rax, -0x2a0(%rbp)
movq %rsp, %rcx
movq %rcx, -0x1e0(%rbp)
movq %rax, %rcx
shlq $0x4, %rcx
leaq (%rcx,%rcx,2), %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0x298(%rbp)
movq %rcx, %rsp
movq %rax, -0x1e8(%rbp)
cmpq $0x0, %rax
je 0x39af
movq -0x298(%rbp), %rax
movq -0x2a0(%rbp), %rcx
imulq $0x30, %rcx, %rdx
movq %rax, %rcx
addq %rdx, %rcx
movq %rcx, -0x2b0(%rbp)
movq %rax, -0x2a8(%rbp)
movq -0x2a8(%rbp), %rdi
movq %rdi, -0x2b8(%rbp)
callq 0x4cb0
jmp 0x3991
movq -0x2b0(%rbp), %rcx
movq -0x2b8(%rbp), %rax
addq $0x30, %rax
cmpq %rcx, %rax
movq %rax, -0x2a8(%rbp)
jne 0x397c
movl -0x1d4(%rbp), %eax
movq %rax, -0x2c8(%rbp)
movq %rax, %rcx
shlq $0x4, %rcx
leaq (%rcx,%rcx,2), %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0x2c0(%rbp)
movq %rcx, %rsp
movq %rax, -0x1f0(%rbp)
cmpq $0x0, %rax
je 0x3a3d
movq -0x2c0(%rbp), %rax
movq -0x2c8(%rbp), %rcx
imulq $0x30, %rcx, %rdx
movq %rax, %rcx
addq %rdx, %rcx
movq %rcx, -0x2d8(%rbp)
movq %rax, -0x2d0(%rbp)
movq -0x2d0(%rbp), %rdi
movq %rdi, -0x2e0(%rbp)
callq 0x4cb0
jmp 0x3a1f
movq -0x2d8(%rbp), %rcx
movq -0x2e0(%rbp), %rax
addq $0x30, %rax
cmpq %rcx, %rax
movq %rax, -0x2d0(%rbp)
jne 0x3a0a
movq -0x2c0(%rbp), %r9
movq -0x298(%rbp), %r8
movl -0x8(%rbp), %edx
movq -0x10(%rbp), %rcx
subq $0x20, %rsp
movq %rsp, %rax
movl $0xffffffff, 0x10(%rax) # imm = 0xFFFFFFFF
movl $0x0, 0x8(%rax)
movl $0x0, (%rax)
leaq 0x130ec(%rip), %rsi     # 0x16b60
leaq -0x208(%rbp), %rdi
callq 0x4d10
addq $0x20, %rsp
jmp 0x3a86
leaq -0x208(%rbp), %rdi
callq 0x4db0
movb %al, -0x2e1(%rbp)
jmp 0x3a9a
movb -0x2e1(%rbp), %al
testb $0x1, %al
jne 0x3aa9
jmp 0x3b33
movl $0x1, -0x4(%rbp)
movl $0x1, -0x20c(%rbp)
jmp 0x4847
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x118(%rbp)
movl %eax, -0x11c(%rbp)
jmp 0x48da
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x118(%rbp)
movl %eax, -0x11c(%rbp)
leaq -0x159(%rbp), %rdi
callq 0x3230
jmp 0x48ce
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x118(%rbp)
movl %eax, -0x11c(%rbp)
leaq -0x181(%rbp), %rdi
callq 0x3230
jmp 0x48c2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x118(%rbp)
movl %eax, -0x11c(%rbp)
jmp 0x48aa
movq -0x298(%rbp), %rdi
addq $0x30, %rdi
callq 0x4dd0
movq %rax, -0x2f0(%rbp)
jmp 0x3b4c
movq -0x2f0(%rbp), %rax
cmpq $0x0, %rax
jne 0x3b5f
cmpl $0x0, -0x8(%rbp)
jne 0x3b9a
movq 0x1345a(%rip), %rdi     # 0x16fc0
leaq 0x12ff3(%rip), %rsi     # 0x16b60
movl $0x50, %edx
movl $0x32, %ecx
movl $0x4b, %r8d
callq 0x4e00
jmp 0x3b84
movl $0x0, -0x4(%rbp)
movl $0x1, -0x20c(%rbp)
jmp 0x4847
movq -0x298(%rbp), %rdi
addq $0x60, %rdi
callq 0x4dd0
movq %rax, -0x2f8(%rbp)
jmp 0x3bb3
movq -0x2f8(%rbp), %rax
cmpq $0x0, %rax
je 0x3bd6
movq -0x298(%rbp), %rax
movq 0x80(%rax), %rdi
callq 0x3370
movl %eax, -0x24(%rbp)
movq -0x298(%rbp), %rdi
addq $0xc0, %rdi
callq 0x4dd0
movq %rax, -0x300(%rbp)
jmp 0x3bf2
movq -0x300(%rbp), %rax
cmpq $0x0, %rax
je 0x3c15
movq -0x298(%rbp), %rax
movq 0xe0(%rax), %rdi
callq 0x3370
movl %eax, -0x30(%rbp)
movq -0x298(%rbp), %rdi
addq $0x90, %rdi
callq 0x4dd0
movq %rax, -0x308(%rbp)
jmp 0x3c31
movq -0x308(%rbp), %rax
cmpq $0x0, %rax
je 0x3c42
movb $0x1, -0x25(%rbp)
movq -0x298(%rbp), %rdi
addq $0x120, %rdi            # imm = 0x120
callq 0x4dd0
movq %rax, -0x310(%rbp)
jmp 0x3c5e
movq -0x310(%rbp), %rax
cmpq $0x0, %rax
je 0x3c6f
movb $0x1, -0x26(%rbp)
movq -0x298(%rbp), %rdi
addq $0x150, %rdi            # imm = 0x150
callq 0x4dd0
movq %rax, -0x318(%rbp)
jmp 0x3c8b
movq -0x318(%rbp), %rax
cmpq $0x0, %rax
je 0x3c9c
movb $0x1, -0x27(%rbp)
leaq -0x208(%rbp), %rdi
callq 0x4e50
movl %eax, -0x31c(%rbp)
jmp 0x3cb0
movl -0x31c(%rbp), %eax
cmpl $0x2, %eax
jge 0x3cf6
movq 0x132fe(%rip), %rdi     # 0x16fc0
leaq 0x12e97(%rip), %rsi     # 0x16b60
movl $0x50, %edx
movl $0x32, %ecx
movl $0x4b, %r8d
callq 0x4e00
jmp 0x3ce0
movl $0x0, -0x4(%rbp)
movl $0x1, -0x20c(%rbp)
jmp 0x4847
leaq -0x208(%rbp), %rdi
xorl %esi, %esi
callq 0x4e70
movq %rax, -0x328(%rbp)
jmp 0x3d0d
movq -0x328(%rbp), %rax
movq %rax, -0x18(%rbp)
leaq -0x208(%rbp), %rdi
callq 0x4e50
movl %eax, -0x32c(%rbp)
jmp 0x3d2c
movl -0x32c(%rbp), %eax
decl %eax
movl %eax, -0x38(%rbp)
leaq -0x1a8(%rbp), %rdi
leaq -0x180(%rbp), %rsi
callq 0x3410
movq %rax, -0x338(%rbp)
jmp 0x3d53
movq -0x338(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x33f0
movq %rax, -0x340(%rbp)
jmp 0x3d6c
movq -0x340(%rbp), %rdi
callq 0x30d0
movq %rax, %rdi
leaq 0xb403(%rip), %rsi      # 0xf185
callq 0x30a0
movq %rax, -0x348(%rbp)
jmp 0x3d90
movq -0x348(%rbp), %rax
movq %rax, -0x1b0(%rbp)
movl $0x0, -0x1cc(%rbp)
movq 0x13239(%rip), %rdi     # 0x16fe8
leaq 0xb3d1(%rip), %rsi      # 0xf187
callq 0x31c0
movq %rax, -0x350(%rbp)
jmp 0x3dc4
movq -0x350(%rbp), %rdi
movq 0x131de(%rip), %rsi     # 0x16fb0
callq 0x3210
jmp 0x3dd9
movl $0x0, -0x1cc(%rbp)
movl $0x0, -0x2c(%rbp)
movq -0x1b0(%rbp), %rdx
leaq -0x1b8(%rbp), %rdi
leaq -0x1c0(%rbp), %rsi
callq 0x32b0
movq %rax, -0x358(%rbp)
jmp 0x3e0d
movq -0x358(%rbp), %rax
movq %rax, -0x1c8(%rbp)
cmpq $-0x1, %rax
je 0x3f4f
movl -0x1cc(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
jne 0x3e6e
movq -0x1b8(%rbp), %rsi
leaq -0x68(%rbp), %rdi
callq 0x3310
jmp 0x3e45
leaq -0x68(%rbp), %rdi
movq %rdi, -0x360(%rbp)
callq 0x3290
movq -0x360(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x1, %edx
callq 0x3050
jmp 0x3e6c
jmp 0x3e6e
movl -0x1cc(%rbp), %eax
andl $0x1, %eax
cmpl $0x1, %eax
jne 0x3f3b
movq -0x1b8(%rbp), %rdi
movl -0x24(%rbp), %esi
movzbl -0x25(%rbp), %edx
andl $0x1, %edx
callq 0x4ea0
movq %rax, -0x368(%rbp)
jmp 0x3e9f
movq -0x368(%rbp), %rax
movq %rax, -0x78(%rbp)
movl -0x38(%rbp), %eax
movl %eax, %edi
shlq $0x3, %rdi
movq %rdi, -0x378(%rbp)
callq 0x3030
movq %rax, -0x370(%rbp)
jmp 0x3ec8
movq -0x378(%rbp), %rdx
movq -0x370(%rbp), %rdi
xorl %esi, %esi
callq 0x3110
leaq -0xd0(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x4f40
movq %rax, -0x380(%rbp)
jmp 0x3ef6
movq -0x380(%rbp), %rax
movq -0x370(%rbp), %rcx
movq %rcx, (%rax)
leaq -0x108(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x4f70
movq %rax, -0x388(%rbp)
jmp 0x3f20
movq -0x388(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x4fa0
jmp 0x3f32
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
movl -0x1cc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1cc(%rbp)
jmp 0x3dea
movq -0x1b0(%rbp), %rdi
callq 0x31d0
jmp 0x3f5d
cmpq $0x0, -0x1b8(%rbp)
je 0x3f73
movq -0x1b8(%rbp), %rdi
callq 0x3280
movq 0x1306e(%rip), %rdi     # 0x16fe8
leaq 0xb216(%rip), %rsi      # 0xf197
callq 0x31c0
movq %rax, -0x390(%rbp)
jmp 0x3f8f
movq -0x390(%rbp), %rdi
movq 0x13013(%rip), %rsi     # 0x16fb0
callq 0x3210
jmp 0x3fa4
movl $0x0, -0x210(%rbp)
movl -0x210(%rbp), %eax
cmpl -0x38(%rbp), %eax
jae 0x44e9
movq 0x13024(%rip), %rdi     # 0x16fe8
leaq 0xb1e3(%rip), %rsi      # 0xf1ae
callq 0x31c0
movq %rax, -0x398(%rbp)
jmp 0x3fd9
movl -0x210(%rbp), %esi
incl %esi
leaq -0x208(%rbp), %rdi
callq 0x4e70
movq %rax, -0x3a0(%rbp)
jmp 0x3ff6
movq -0x3a0(%rbp), %rsi
movq -0x398(%rbp), %rdi
callq 0x31c0
movq %rax, -0x3a8(%rbp)
jmp 0x4012
movq -0x3a8(%rbp), %rdi
leaq 0xb348(%rip), %rsi      # 0xf368
callq 0x31c0
jmp 0x4027
movq $0x0, -0x1b8(%rbp)
movq $0x0, -0x1c0(%rbp)
movl $0x0, -0x1cc(%rbp)
leaq 0xb1a8(%rip), %rsi      # 0xf1f6
leaq -0x1a8(%rbp), %rdi
callq 0x3310
jmp 0x405c
leaq -0x1a8(%rbp), %rdi
leaq -0x158(%rbp), %rsi
callq 0x3410
movq %rax, -0x3b0(%rbp)
jmp 0x4078
movl -0x210(%rbp), %esi
incl %esi
leaq -0x208(%rbp), %rdi
callq 0x4e70
movq %rax, -0x3b8(%rbp)
jmp 0x4095
movq -0x3b8(%rbp), %rsi
movq -0x3b0(%rbp), %rdi
callq 0x33f0
movq %rax, -0x3c0(%rbp)
jmp 0x40b1
movq -0x3c0(%rbp), %rdi
callq 0x30d0
movq %rax, %rdi
leaq 0xb0be(%rip), %rsi      # 0xf185
callq 0x30a0
movq %rax, -0x3c8(%rbp)
jmp 0x40d5
movq -0x3c8(%rbp), %rax
movq %rax, -0x1b0(%rbp)
movq $0x0, -0x90(%rbp)
movq -0x1b0(%rbp), %rdx
leaq -0x1b8(%rbp), %rdi
leaq -0x1c0(%rbp), %rsi
callq 0x32b0
movq %rax, -0x3d0(%rbp)
jmp 0x4111
movq -0x3d0(%rbp), %rax
movq %rax, -0x1c8(%rbp)
cmpq $-0x1, %rax
je 0x4341
movl -0x1cc(%rbp), %eax
andl $0x3, %eax
cmpl $0x1, %eax
jne 0x432d
movl -0x1cc(%rbp), %eax
cvtsi2sd %rax, %xmm0
movsd 0xaeba(%rip), %xmm1     # 0xf008
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x40(%rbp), %eax
cmpl -0x30(%rbp), %eax
jb 0x4169
jmp 0x4341
movl -0x40(%rbp), %eax
movl $0xf4240, %ecx          # imm = 0xF4240
xorl %edx, %edx
divl %ecx
cmpl $0x0, %edx
jne 0x41df
movl -0x1cc(%rbp), %eax
cvtsi2sd %rax, %xmm0
movsd 0xae7b(%rip), %xmm1     # 0xf008
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %esi
incl %esi
movq 0x12e4a(%rip), %rdi     # 0x16fe8
callq 0x33a0
movq %rax, -0x3d8(%rbp)
jmp 0x41ac
movq -0x3d8(%rbp), %rdi
leaq 0xb00d(%rip), %rsi      # 0xf1c7
callq 0x31c0
movq %rax, -0x3e0(%rbp)
jmp 0x41c8
movq -0x3e0(%rbp), %rdi
movq 0x12dda(%rip), %rsi     # 0x16fb0
callq 0x3210
jmp 0x41dd
jmp 0x41df
movq -0x1b8(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rdi
callq 0x30f0
subq $0x1, %rax
movl %eax, -0x6c(%rbp)
movl -0x6c(%rbp), %eax
cmpl -0x24(%rbp), %eax
jae 0x4207
jmp 0x40ee
movl -0x6c(%rbp), %eax
subl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
addq -0x90(%rbp), %rax
movq %rax, -0x90(%rbp)
movq $-0x3, -0x98(%rbp)
movl $0x0, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jae 0x432b
movl -0x3c(%rbp), %edi
movq -0x48(%rbp), %rsi
movl -0x24(%rbp), %edx
movzbl -0x25(%rbp), %ecx
subq $0x10, %rsp
andl $0x1, %ecx
movq %rsp, %rax
movl %ecx, (%rax)
leaq -0x98(%rbp), %rcx
leaq -0x88(%rbp), %r8
leaq -0x80(%rbp), %r9
callq 0x5040
addq $0x10, %rsp
movq %rax, -0x3e8(%rbp)
jmp 0x4280
movq -0x3e8(%rbp), %rax
movq %rax, -0x220(%rbp)
leaq -0xd0(%rbp), %rdi
leaq -0x220(%rbp), %rsi
callq 0x5010
movq %rax, -0x3f0(%rbp)
jmp 0x42aa
movq -0x3f0(%rbp), %rax
movq %rax, -0x218(%rbp)
movq -0x218(%rbp), %rax
movq %rax, -0x110(%rbp)
leaq -0xd0(%rbp), %rdi
callq 0x51e0
movq %rax, -0x228(%rbp)
leaq -0x110(%rbp), %rdi
leaq -0x228(%rbp), %rsi
callq 0x51b0
testb $0x1, %al
jne 0x42f2
jmp 0x431b
leaq -0x110(%rbp), %rdi
callq 0x5210
movq 0x8(%rax), %rax
movslq -0x210(%rbp), %rcx
movsd 0xacff(%rip), %xmm0     # 0xf010
addsd (%rax,%rcx,8), %xmm0
movsd %xmm0, (%rax,%rcx,8)
jmp 0x431d
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x4236
jmp 0x432d
movl -0x1cc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1cc(%rbp)
jmp 0x40ee
leaq -0x138(%rbp), %rdi
leaq -0x90(%rbp), %rsi
callq 0x5240
jmp 0x4356
testb $0x1, -0x26(%rbp)
je 0x44af
cmpq $0x0, -0x90(%rbp)
jbe 0x44af
movq 0x12c73(%rip), %rdi     # 0x16fe8
leaq 0xae59(%rip), %rsi      # 0xf1d5
callq 0x31c0
movq %rax, -0x3f8(%rbp)
jmp 0x438a
movq -0x3f8(%rbp), %rdi
movq 0x12c18(%rip), %rsi     # 0x16fb0
callq 0x3210
jmp 0x439f
leaq -0xd0(%rbp), %rdi
callq 0x52b0
movq %rax, -0x230(%rbp)
movq -0x230(%rbp), %rax
movq %rax, -0x110(%rbp)
leaq -0xd0(%rbp), %rdi
callq 0x51e0
movq %rax, -0x238(%rbp)
leaq -0x110(%rbp), %rdi
leaq -0x238(%rbp), %rsi
callq 0x51b0
testb $0x1, %al
jne 0x43ef
jmp 0x44ad
leaq -0x110(%rbp), %rdi
callq 0x5210
movq 0x8(%rax), %rax
movslq -0x210(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x449a
leaq -0x110(%rbp), %rdi
callq 0x5210
movq 0x8(%rax), %rax
movslq -0x210(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movsd 0xabdc(%rip), %xmm1     # 0xf018
mulsd %xmm1, %xmm0
movaps 0xabd9(%rip), %xmm2     # 0xf020
movq -0x90(%rbp), %xmm1
punpckldq %xmm2, %xmm1    # xmm1 = xmm1[0],xmm2[0],xmm1[1],xmm2[1]
movapd 0xabd5(%rip), %xmm2     # 0xf030
subpd %xmm2, %xmm1
movaps %xmm1, %xmm2
unpckhpd %xmm1, %xmm1            # xmm1 = xmm1[1,1]
addsd %xmm2, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0x400(%rbp)
leaq -0x110(%rbp), %rdi
callq 0x5210
movsd -0x400(%rbp), %xmm0
movq 0x8(%rax), %rax
movslq -0x210(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
jmp 0x449c
leaq -0x110(%rbp), %rdi
callq 0x52e0
jmp 0x43c0
jmp 0x44af
movq -0x1b0(%rbp), %rdi
callq 0x31d0
jmp 0x44bd
cmpq $0x0, -0x1b8(%rbp)
je 0x44d3
movq -0x1b8(%rbp), %rdi
callq 0x3280
jmp 0x44d5
movl -0x210(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x210(%rbp)
jmp 0x3fae
movq 0x12ad0(%rip), %rdi     # 0x16fc0
leaq 0xacef(%rip), %rsi      # 0xf1e6
callq 0x31c0
jmp 0x44fe
testb $0x1, -0x27(%rbp)
je 0x451b
movq 0x12ab5(%rip), %rdi     # 0x16fc0
leaq 0xacd8(%rip), %rsi      # 0xf1ea
callq 0x31c0
jmp 0x4519
jmp 0x451b
movl $0x0, -0x23c(%rbp)
movl -0x23c(%rbp), %eax
cmpl -0x38(%rbp), %eax
jae 0x4591
movq 0x12a89(%rip), %rdi     # 0x16fc0
leaq 0xacb7(%rip), %rsi      # 0xf1f5
callq 0x31c0
movq %rax, -0x408(%rbp)
jmp 0x454c
movl -0x23c(%rbp), %esi
incl %esi
leaq -0x208(%rbp), %rdi
callq 0x4e70
movq %rax, -0x410(%rbp)
jmp 0x4569
movq -0x410(%rbp), %rsi
movq -0x408(%rbp), %rdi
callq 0x31c0
jmp 0x457e
jmp 0x4580
movl -0x23c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x23c(%rbp)
jmp 0x4525
movq 0x12a28(%rip), %rdi     # 0x16fc0
leaq 0xadc9(%rip), %rsi      # 0xf368
callq 0x31c0
jmp 0x45a6
movl -0x24(%rbp), %eax
movl %eax, %edi
callq 0x3030
movq %rax, -0x418(%rbp)
jmp 0x45b9
movq -0x418(%rbp), %rax
movq %rax, -0x248(%rbp)
leaq -0xd0(%rbp), %rdi
callq 0x52b0
movq %rax, -0x250(%rbp)
movq -0x250(%rbp), %rax
movq %rax, -0x110(%rbp)
leaq -0xd0(%rbp), %rdi
callq 0x51e0
movq %rax, -0x258(%rbp)
leaq -0x110(%rbp), %rdi
leaq -0x258(%rbp), %rsi
callq 0x51b0
testb $0x1, %al
jne 0x4617
jmp 0x478e
leaq -0x110(%rbp), %rdi
callq 0x5210
movq (%rax), %rdi
movl -0x24(%rbp), %esi
movq -0x248(%rbp), %rdx
callq 0x5310
jmp 0x4637
movq -0x248(%rbp), %rsi
movq 0x1297b(%rip), %rdi     # 0x16fc0
callq 0x31c0
jmp 0x464c
testb $0x1, -0x27(%rbp)
je 0x46f8
movq 0x12963(%rip), %rdi     # 0x16fc0
leaq 0xab91(%rip), %rsi      # 0xf1f5
callq 0x31c0
movq %rax, -0x420(%rbp)
jmp 0x4672
leaq -0x110(%rbp), %rdi
callq 0x5210
movq %rax, %rsi
leaq -0x108(%rbp), %rdi
callq 0x4f70
movq %rax, -0x428(%rbp)
jmp 0x4696
movq -0x428(%rbp), %rsi
leaq 0xab53(%rip), %rdx      # 0xf1f7
leaq -0x278(%rbp), %rdi
callq 0x35c0
jmp 0x46b2
movq -0x420(%rbp), %rdi
leaq -0x278(%rbp), %rsi
callq 0x31b0
jmp 0x46c7
leaq -0x278(%rbp), %rdi
callq 0x3130
jmp 0x46f8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x118(%rbp)
movl %eax, -0x11c(%rbp)
leaq -0x278(%rbp), %rdi
callq 0x3130
jmp 0x48aa
movl $0x0, -0x27c(%rbp)
movl -0x27c(%rbp), %eax
cmpl -0x38(%rbp), %eax
jae 0x4766
movq 0x128ac(%rip), %rdi     # 0x16fc0
leaq 0xaada(%rip), %rsi      # 0xf1f5
callq 0x31c0
movq %rax, -0x430(%rbp)
jmp 0x4729
leaq -0x110(%rbp), %rdi
callq 0x5210
movq -0x430(%rbp), %rdi
movq 0x8(%rax), %rax
movslq -0x27c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
callq 0x33e0
jmp 0x4753
jmp 0x4755
movl -0x27c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x27c(%rbp)
jmp 0x4702
movq 0x12853(%rip), %rdi     # 0x16fc0
movq 0x1283c(%rip), %rsi     # 0x16fb0
callq 0x3210
jmp 0x477b
jmp 0x477d
leaq -0x110(%rbp), %rdi
callq 0x52e0
jmp 0x45e8
movq 0x1282b(%rip), %rdi     # 0x16fc0
leaq 0xaa5d(%rip), %rsi      # 0xf1f9
callq 0x31c0
jmp 0x47a3
testb $0x1, -0x27(%rbp)
je 0x47c0
movq 0x12810(%rip), %rdi     # 0x16fc0
leaq 0xaa50(%rip), %rsi      # 0xf207
callq 0x31c0
jmp 0x47be
jmp 0x47c0
movl $0x0, -0x280(%rbp)
movl -0x280(%rbp), %eax
cmpl -0x38(%rbp), %eax
jae 0x4828
movq 0x127e4(%rip), %rdi     # 0x16fc0
leaq 0xaa12(%rip), %rsi      # 0xf1f5
callq 0x31c0
movq %rax, -0x438(%rbp)
jmp 0x47f1
movslq -0x280(%rbp), %rsi
leaq -0x138(%rbp), %rdi
callq 0x5380
movq -0x438(%rbp), %rdi
movq (%rax), %rsi
callq 0x3060
jmp 0x4815
jmp 0x4817
movl -0x280(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x280(%rbp)
jmp 0x47ca
movq 0x12791(%rip), %rdi     # 0x16fc0
movq 0x1277a(%rip), %rsi     # 0x16fb0
callq 0x3210
jmp 0x483d
movl $0x0, -0x20c(%rbp)
movq -0x1e0(%rbp), %rax
movq %rax, %rsp
leaq -0x1a8(%rbp), %rdi
callq 0x3130
leaq -0x180(%rbp), %rdi
callq 0x3130
leaq -0x158(%rbp), %rdi
callq 0x3130
leaq -0x138(%rbp), %rdi
callq 0x53a0
leaq -0x108(%rbp), %rdi
callq 0x5400
leaq -0xd0(%rbp), %rdi
callq 0x5420
leaq -0x68(%rbp), %rdi
callq 0x3130
movl -0x4(%rbp), %eax
movq %rbp, %rsp
popq %rbp
retq
leaq -0x1a8(%rbp), %rdi
callq 0x3130
leaq -0x180(%rbp), %rdi
callq 0x3130
leaq -0x158(%rbp), %rdi
callq 0x3130
leaq -0x138(%rbp), %rdi
callq 0x53a0
leaq -0x108(%rbp), %rdi
callq 0x5400
leaq -0xd0(%rbp), %rdi
callq 0x5420
leaq -0x68(%rbp), %rdi
callq 0x3130
movq -0x118(%rbp), %rdi
callq 0x33b0
nopw (%rax,%rax)