// File: /workspace/github_c_makefile_star2_O2/sc932[P]ALE/src/ALEhelpers.c
// Function: computeLibraryParameters
libraryParametersT *computeLibraryParameters(samfile_t *ins, double outlierFraction, int qOff) {

  int i,j;
  long *mapLens[MATE_ORIENTATION_MAX];

  // allocate memory
  for(i=0; i < MATE_ORIENTATION_MAX; i++)
    mapLens[i] = malloc(sizeof(long)*mapLens_MAX);
  libraryParametersT *libParams = malloc(sizeof(libraryParametersT));

  // initialize
  for(j=0; j < MATE_ORIENTATION_MAX; j++) {
    for(i = 0; i < mapLens_MAX; i++)
      mapLens[j][i] = 0;
    libParams->mateParameters[j].insertLength = 0.0;
    libParams->mateParameters[j].insertStd = 0.0;
    libParams->mateParameters[j].zNormalizationInsert = 1.0;
    libParams->mateParameters[j].count = 0;
    libParams->mateParameters[j].mapped = 0;
    libParams->mateParameters[j].placed = 0;
    libParams->mateParameters[j].isValid = 0;
  }
  // set SINGLE_READ insert parameters
  libParams->mateParameters[SINGLE_READ].insertStd = 1.0;
  libParams->mateParameters[SINGLE_READ].zNormalizationInsert = zNormalizationInsertStd(1.0);

  libParams->qOff = qOff;
  libParams->avgReadSize = 0;
  libParams->numReads = 0;
  libParams->isSortedByName = -1; // undefined
  libParams->primaryOrientation = SINGLE_READ;  // can be only SINGLE_READ or the most abundant of the MAPPED_PAIRED_ORIENTATION


  bam1_t *thisRead = bam_init1();
  long readCount = 0;
  long unmappedReads = 0;
  long chimericReads = 0;
  long improperReads = 0;
  long mappedPairedReads = 0;
  long newNames = 0;
  long newPairedNames = 0;
  long pairedReads = 0;
  char *lastName = strdup("");

  while(1){
    enum MATE_ORIENTATION orientation = readNextBAM(ins, thisRead);

    if (orientation == NO_READS){
      break;
    }

    libraryMateParametersT *mateParams = &libParams->mateParameters[orientation];

    int mapLen = -1;
    switch(orientation) {
      case(VALID_FR):
      case(VALID_RF):
      case(VALID_FF):
      case(NOT_PROPER_FR):
      case(NOT_PROPER_RF):
      case(NOT_PROPER_FF):
        mapLen = getFragmentMapLenBAM(thisRead);
        mappedPairedReads++;
        break;

      case(SINGLE_READ):
      case(UNMAPPED_SINGLE):
        break;

      case(SINGLE_UNMAPPED_MATE):
        break;

      case(CHIMER):
        chimericReads++;
        break;

      case(UNMAPPED_PAIR):
      case(UNMAPPED_MATE):
        break;

      default:
        // should never get here
        printf("Improper read with invalid orientation/pairing: %s\n", lastName);
        improperReads++;
    }

    readCount++;
    mateParams->count++;
    libParams->avgReadSize += thisRead->core.l_qseq;
    libParams->numReads++;
    if (libParams->qOff < 0) {
      libParams->qOff = guessQualityOffset(thisRead);
    }

    if ( (thisRead->core.flag & BAM_FUNMAP) == BAM_FUNMAP ) {
        unmappedReads++;
    } else {
    	mateParams->mapped++;
    }

    if ( (thisRead->core.flag & BAM_FPAIRED) == BAM_FPAIRED ) {
    	pairedReads++;
    }
    if (strcmp(lastName, bam1_qname(thisRead)) != 0){
        newNames++;
        if ( (thisRead->core.flag & BAM_FPAIRED) == BAM_FPAIRED ) {
        	newPairedNames++;
        }
    }
    free(lastName);
    lastName = strdup(bam1_qname(thisRead));

    if (mapLen > 0) {
      mateParams->insertLength += mapLen;
      if (mapLen < mapLens_MAX){
        ++mapLens[orientation][mapLen];
      }
    }

    if (readCount%1000000 == 0){
      printf("Read %ld reads...\n", readCount);
    }
  }
  bam_destroy1(thisRead);
  free(lastName);

  if (pairedReads > 0 && newNames <= readCount/2 && newPairedNames == pairedReads / 2) {
    libParams->isSortedByName = 1;
    printf("Setting library to be sorted by name (%ld new sequential names vs %ld reads)\n", newNames, readCount);
  } else {
    libParams->isSortedByName = 0;
  }

  // zero out top and bottom outliers
  long totalValidMateReads = 0;
  long totalValidSingleReads = 0;
  double maximumFraction = 0.0;
  double pairedReadsFraction = (double) mappedPairedReads / (double) libParams->numReads;
  for(j = 0; j < MATE_ORIENTATION_MAX; j++) {
    libraryMateParametersT *mateParams = &libParams->mateParameters[j];
    //printf("Evaluating %s orientation with %ld reads\n", MATE_ORIENTATION_LABELS[j], mateParams->count);
    long observed = 0;
    long purged = 0;
    long lengthTotal = 0;
    for(i = 0; i < mapLens_MAX; i++) {
      if (observed > (1.0-outlierFraction) * mateParams->count) {
        purged += mapLens[j][i];
        mapLens[j][i] = 0;
      } else {
        observed += mapLens[j][i];
        lengthTotal += i*mapLens[j][i];
      }
      if (observed < outlierFraction * mateParams->count) {
        purged += mapLens[j][i];
        mapLens[j][i] = 0;
      }
    }
    mateParams->libraryFraction = (double) mateParams->count / (double) libParams->numReads;
    if (mateParams->libraryFraction > maximumFraction && j <= MAPPED_PAIRED_ORIENTATION) {
        maximumFraction = mateParams->libraryFraction;
        libParams->primaryOrientation = j;
    }

    if (mateParams->count > 0 && (j == VALID_FR || j == VALID_RF || j == VALID_FF || j == NOT_PROPER_FR || j == NOT_PROPER_RF || j == NOT_PROPER_FF )) {

      // TODO better test for significance and normal distribution for a valid orientation
      if (mateParams->libraryFraction > SIGNIFICANT_LIBRARY_FRACTION * pairedReadsFraction ) {
        mateParams->isValid = 1;
      } else {
        improperReads += mateParams->count;
        mateParams->isValid = 0;
      }

    } else if (mateParams->count > 0 && (j == SINGLE_READ || j == SINGLE_UNMAPPED_MATE)) {
        totalValidSingleReads += mateParams->count;
        mateParams->isValid = 1;
    } else {
        improperReads += mateParams->count;
        mateParams->isValid = 0;
    }

    if (mateParams->isValid == 1) {
      /*printf("Read %ld %s oriented sequences and purged %ld %0.1lf%% & %0.1lf%% outliers.  This %s a valid orientation (%01lf%%)\n",
          mateParams->count,
          MATE_ORIENTATION_LABELS[j],
          purged,
          (outlierFraction*100.0),
          ((1.0-outlierFraction)*100.0),
          mateParams->isValid ? "is" : "is NOT",
          mateParams->libraryFraction*100.0);*/
    }

    long modifiedReadCount = mateParams->count - purged;

    if (mateParams->isValid && j <= MAPPED_PAIRED_ORIENTATION) {
      mateParams->insertLength = (double)lengthTotal/(double)modifiedReadCount;
      for(i = 0; i < mapLens_MAX; i++){
        if(mapLens[j][i] > 0){
          double tmp = mapLens[j][i]*((double)i - mateParams->insertLength)*((double)i - mateParams->insertLength);
          mateParams->insertStd += tmp;
          //printf("i : %s mapLens[i] :: %i : %ld\n", MATE_ORIENTATION_LABELS[j], i, mapLens[j][i]);
        }
      }
      mateParams->insertStd = sqrt(mateParams->insertStd/(double)(modifiedReadCount-1));
      mateParams->zNormalizationInsert = zNormalizationInsertStd(mateParams->insertStd);
      printf("Found %s sample avg insert length to be %lf from %ld mapped reads\n", MATE_ORIENTATION_LABELS[j], mateParams->insertLength, modifiedReadCount);
      printf("Found %s sample insert length std to be %lf\n", MATE_ORIENTATION_LABELS[j], mateParams->insertStd);
      if (mateParams->insertStd > MAXIMUM_STD_DEV_FRACTION * mateParams->insertLength) {
    	  mateParams->isValid = 0;
    	  improperReads += mateParams->count;
    	  printf("stddev is too large (> %lf * insertLength).  This orientation is invalid\n", MAXIMUM_STD_DEV_FRACTION );
      } else {
          totalValidMateReads += mateParams->count;
      }
    }
  }
  printf("There were %ld total reads, %ld paired (%ld properly mated), %ld proper singles, %ld improper reads (%ld chimeric). (%ld reads were unmapped)\n", readCount, pairedReads, totalValidMateReads, totalValidSingleReads, improperReads, chimericReads, unmappedReads);

  libParams->avgReadSize = libParams->avgReadSize / libParams->numReads;

  libParams->totalValidMateFraction = (double) (totalValidMateReads) / (double) libParams->numReads;
  libParams->totalValidSingleFraction = (double) totalValidSingleReads / (double) libParams->numReads;
  libParams->totalChimerMateFraction = (double) (improperReads) / (double) libParams->numReads;
  libParams->totalUnmappedFraction = (double) unmappedReads / (double) libParams->numReads;

  /*printf("ValidMates %0.3lf%%, Single(+half-mapped mate pairs) %0.3lf%%, Improper/ChimerMates %0.3lf%% (Unmapped %0.3lf%%)\n",
          libParams->totalValidMateFraction*100,
          libParams->totalValidSingleFraction*100,
          libParams->totalChimerMateFraction*100,
          libParams->totalUnmappedFraction*100);*/

  // release memory
  for(i=0; i < MATE_ORIENTATION_MAX; i++)
    free(mapLens[i]);

  return libParams;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x128, %rsp            # imm = 0x128
movl %esi, 0x1c(%rsp)
movsd %xmm0, 0x20(%rsp)
movq %rdi, 0xa0(%rsp)
xorl %ebx, %ebx
cmpq $0xe, %rbx
je 0xa610
movl $0xc3500, %edi          # imm = 0xC3500
callq 0x3420
movq %rax, 0xb0(%rsp,%rbx,8)
incq %rbx
jmp 0xa5f3
movl $0x3c0, %edi            # imm = 0x3C0
callq 0x3420
movq %rax, %rbx
xorl %eax, %eax
xorps %xmm0, %xmm0
movabsq $0x3ff0000000000000, %rcx # imm = 0x3FF0000000000000
cmpq $0xe, %rax
je 0xa66e
movq 0xb0(%rsp,%rax,8), %rdx
xorl %esi, %esi
cmpq $0x186a0, %rsi          # imm = 0x186A0
je 0xa64f
andq $0x0, (%rdx,%rsi,8)
incq %rsi
jmp 0xa63c
movq %rax, %rdx
shlq $0x6, %rdx
movups %xmm0, (%rbx,%rdx)
movq %rcx, 0x10(%rbx,%rdx)
incq %rax
movups %xmm0, 0x20(%rbx,%rdx)
movups %xmm0, 0x2c(%rbx,%rdx)
jmp 0xa62c
movapd 0x14b3a(%rip), %xmm0    # 0x1f1b0
movupd %xmm0, 0x2c8(%rbx)
movl 0x1c(%rsp), %eax
movl %eax, 0x3b0(%rbx)
xorpd %xmm0, %xmm0
movupd %xmm0, 0x380(%rbx)
movl $0xb, 0x3b8(%rbx)
pushq $0x1
popq %rbp
pushq $0x38
popq %rsi
movq %rbp, %rdi
callq 0x3310
movq %rax, %r12
leaq 0x160d6(%rip), %rdi     # 0x2078c
callq 0x3630
movq %rax, 0x10(%rsp)
movq $0x0, 0x28(%rsp)
movq $0x0, 0x58(%rsp)
movq $0x0, 0x78(%rsp)
xorl %r15d, %r15d
xorl %r13d, %r13d
xorl %r14d, %r14d
movq $0x0, 0x8(%rsp)
movq $0x0, 0x70(%rsp)
movq $0x0, 0x80(%rsp)
movq %rbx, 0x88(%rsp)
movq %r12, (%rsp)
movq %rbp, 0x48(%rsp)
movq %rbp, %rax
xorl %edx, %edx
movl $0xf4240, %ecx          # imm = 0xF4240
divq %rcx
movq %rax, 0x60(%rsp)
movq 0xa0(%rsp), %rdi
movq %r12, %rsi
callq 0x9b6c
cmpl $0xd, %eax
je 0xa90e
movl %eax, %ebp
movq %r15, 0x40(%rsp)
movq %r13, 0x38(%rsp)
jae 0xa8f1
pushq $0x3f
popq %rax
btl %ebp, %eax
jb 0xa770
movl $0x1b40, %eax           # imm = 0x1B40
btl %ebp, %eax
jae 0xa8e2
pushq $-0x1
popq %r15
movq (%rsp), %r13
jmp 0xa784
movq (%rsp), %r13
movq %r13, %rdi
callq 0x99b8
movl %eax, %r15d
incq 0x78(%rsp)
movl %ebp, %r12d
movq %r12, 0xa8(%rsp)
shlq $0x6, %r12
addq %rbx, %r12
movq 0x28(%rsp), %rax
leaq 0x1(%rax), %rdx
incq 0x20(%r12)
movslq 0x10(%r13), %rax
movq 0x58(%rsp), %rcx
addq %rax, %rcx
movq %rcx, 0x58(%rsp)
movq %rcx, 0x380(%rbx)
movq %rdx, 0x90(%rsp)
movq %rdx, 0x388(%rbx)
cmpl $0x0, 0x1c(%rsp)
jns 0xa7e4
movq %r13, %rdi
callq 0x6c99
movl %eax, 0x1c(%rsp)
movl %eax, 0x3b0(%rbx)
movq 0x8(%r13), %rbx
btq $0x22, %rbx
jb 0xa7f6
incq 0x28(%r12)
jmp 0xa7fe
incq 0x80(%rsp)
btq $0x20, %rbx
adcq $0x0, %r14
movq %r14, 0x50(%rsp)
movq 0x30(%r13), %r13
movq 0x10(%rsp), %rbp
movq %rbp, %rdi
movq %r13, %rsi
callq 0x3330
xorl %r14d, %r14d
testl %eax, %eax
setne 0x30(%rsp)
movq %rbp, %rdi
callq 0x3070
movq %r13, %rdi
callq 0x3630
movq %rax, 0x10(%rsp)
testl %r15d, %r15d
jle 0xa875
cvtsi2sd %r15d, %xmm0
addsd (%r12), %xmm0
movsd %xmm0, (%r12)
cmpl $0x1869f, %r15d         # imm = 0x1869F
ja 0xa875
movq 0xa8(%rsp), %rax
movq 0xb0(%rsp,%rax,8), %rax
movl %r15d, %ecx
incq (%rax,%rcx,8)
imulq $0xf4240, 0x60(%rsp), %rax # imm = 0xF4240
decq %rax
cmpq 0x28(%rsp), %rax
movq 0x38(%rsp), %r13
movq 0x90(%rsp), %r12
jne 0xa8a6
leaq 0x14346(%rip), %rdi     # 0x1ebe2
movq %r12, %rsi
xorl %eax, %eax
callq 0x3210
shrq $0x20, %rbx
movb 0x30(%rsp), %al
movb %al, %r14b
movq 0x40(%rsp), %r15
addq %r14, %r15
andl %r14d, %ebx
addq %rbx, %r13
movq 0x48(%rsp), %rbp
incq %rbp
movq %r12, 0x28(%rsp)
movq 0x88(%rsp), %rbx
movq 0x50(%rsp), %r14
movq (%rsp), %r12
jmp 0xa70e
cmpl $0x7, %ebp
jne 0xa8f1
incq 0x70(%rsp)
jmp 0xa766
leaq 0x158b3(%rip), %rdi     # 0x201ab
movq 0x10(%rsp), %rsi
xorl %eax, %eax
callq 0x3210
incq 0x8(%rsp)
jmp 0xa766
movq (%rsp), %r12
testq %r12, %r12
je 0xa929
movq 0x30(%r12), %rdi
callq 0x3070
movq %r12, %rdi
callq 0x3070
movq 0x10(%rsp), %rdi
callq 0x3070
xorl %eax, %eax
testq %r14, %r14
movq 0x28(%rsp), %r12
movq %r14, 0x50(%rsp)
jle 0xad1d
movq %r12, %rcx
shrq %rcx
cmpq %rcx, %r15
movsd 0x20(%rsp), %xmm4
ja 0xa981
movq %r14, %rcx
shrq %rcx
cmpq %rcx, %r13
jne 0xa981
leaq 0x15874(%rip), %rdi     # 0x201df
movq %r15, %rsi
movq %r12, %rdx
xorl %eax, %eax
callq 0x3210
movsd 0x20(%rsp), %xmm4
pushq $0x1
popq %rax
cvtsi2sdq 0x78(%rsp), %xmm6
movl %eax, 0x3b4(%rbx)
cvtsi2sd %r12, %xmm5
divsd %xmm5, %xmm6
movsd 0xf091(%rip), %xmm7     # 0x19a30
mulsd 0x14839(%rip), %xmm6    # 0x1f1e0
subsd %xmm4, %xmm7
xorl %r13d, %r13d
movq $0x0, 0x30(%rsp)
movq $0x0, 0x40(%rsp)
xorpd %xmm8, %xmm8
movapd %xmm5, 0x60(%rsp)
movsd %xmm6, 0x38(%rsp)
movapd %xmm7, 0x90(%rsp)
cmpq $0xe, %r13
je 0xac45
movq %r13, %rax
shlq $0x6, %rax
leaq (%rbx,%rax), %rbp
movq 0x20(%rbx,%rax), %r15
cvtsi2sd %r15, %xmm0
movapd %xmm7, %xmm1
mulsd %xmm0, %xmm1
movapd %xmm0, %xmm2
mulsd %xmm4, %xmm2
movq 0xb0(%rsp,%r13,8), %rdx
xorl %esi, %esi
xorl %edi, %edi
xorl %eax, %eax
xorl %ecx, %ecx
cmpq $0x186a0, %rsi          # imm = 0x186A0
je 0xaa63
cvtsi2sd %rdi, %xmm3
ucomisd %xmm1, %xmm3
movq (%rdx,%rsi,8), %r8
jbe 0xaa3e
addq %r8, %rax
andq $0x0, (%rdx,%rsi,8)
xorl %r8d, %r8d
jmp 0xaa50
addq %r8, %rdi
movq %r8, %r9
imulq %rsi, %r9
addq %r9, %rcx
cvtsi2sd %rdi, %xmm3
ucomisd %xmm3, %xmm2
jbe 0xaa5e
addq %r8, %rax
andq $0x0, (%rdx,%rsi,8)
incq %rsi
jmp 0xaa19
divsd %xmm5, %xmm0
movsd %xmm0, 0x18(%rbp)
cmpq $0x5, %r13
ja 0xaa85
ucomisd %xmm8, %xmm0
jbe 0xaa85
movl %r13d, 0x3b8(%rbx)
movapd %xmm0, %xmm8
cmpq $0x6, %r13
setae %dl
testq %r15, %r15
setle %sil
orb %dl, %sil
jne 0xaaa3
ucomisd %xmm6, %xmm0
ja 0xaab9
jmp 0xab23
testq %r15, %r15
jle 0xab23
cmpl $0xb, %r13d
je 0xaab4
cmpl $0x8, %r13d
jne 0xab23
addq %r15, 0x40(%rsp)
movl $0x1, 0x38(%rbp)
cmpq $0x5, %r13
ja 0xac3d
movq %r15, %r14
subq %rax, %r14
cvtsi2sd %rcx, %xmm2
cvtsi2sd %r14, %xmm0
divsd %xmm0, %xmm2
movsd %xmm2, (%rbp)
movq 0xb0(%rsp,%r13,8), %rax
xorl %ecx, %ecx
cmpq $0x186a0, %rcx          # imm = 0x186A0
je 0xab31
movq (%rax,%rcx,8), %rdx
testq %rdx, %rdx
jle 0xab1e
cvtsi2sd %rdx, %xmm0
cvtsi2sd %ecx, %xmm1
subsd %xmm2, %xmm1
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
addsd 0x8(%rbp), %xmm0
movsd %xmm0, 0x8(%rbp)
incq %rcx
jmp 0xaaed
addq %r15, 0x8(%rsp)
andl $0x0, 0x38(%rbp)
jmp 0xac3d
movsd %xmm2, 0x10(%rsp)
leaq -0x1(%r14), %rax
cvtsi2sd %rax, %xmm1
movsd 0x8(%rbp), %xmm0
divsd %xmm1, %xmm0
ucomisd 0xef37(%rip), %xmm0     # 0x19a88
movsd %xmm8, 0x48(%rsp)
jb 0xab60
sqrtsd %xmm0, %xmm0
jmp 0xab65
callq 0x3600
movsd %xmm0, 0x8(%rbp)
movapd %xmm0, %xmm3
movsd %xmm0, (%rsp)
mulsd 0x1465d(%rip), %xmm0    # 0x1f1d8
movsd 0xeead(%rip), %xmm2     # 0x19a30
movapd %xmm2, %xmm1
divsd %xmm0, %xmm1
xorpd %xmm0, %xmm0
cmpltsd %xmm3, %xmm0
andpd %xmm0, %xmm1
andnpd %xmm2, %xmm0
orpd %xmm1, %xmm0
movlpd %xmm0, 0x10(%rbp)
leaq 0x1e194(%rip), %rax     # 0x28d40
movq (%rax,%r13,8), %r12
leaq 0x15676(%rip), %rdi     # 0x2022d
movq %r12, %rsi
movsd 0x10(%rsp), %xmm0
movq %r14, %rdx
movb $0x1, %al
callq 0x3210
leaq 0x1569f(%rip), %rdi     # 0x20270
movq %r12, %rsi
movsd (%rsp), %xmm0
movb $0x1, %al
callq 0x3210
movsd 0x14600(%rip), %xmm0    # 0x1f1e8
movsd 0x10(%rsp), %xmm2
mulsd %xmm0, %xmm2
movsd (%rsp), %xmm1
ucomisd %xmm2, %xmm1
jbe 0xac16
andl $0x0, 0x38(%rbp)
addq %r15, 0x8(%rsp)
leaq 0x15690(%rip), %rdi     # 0x2029d
movb $0x1, %al
callq 0x3210
jmp 0xac1b
addq %r15, 0x30(%rsp)
movsd 0x20(%rsp), %xmm4
movapd 0x60(%rsp), %xmm5
movsd 0x38(%rsp), %xmm6
movapd 0x90(%rsp), %xmm7
movsd 0x48(%rsp), %xmm8
incq %r13
jmp 0xa9da
leaq 0x1569b(%rip), %rdi     # 0x202e7
movq %rbx, %r14
xorl %ebx, %ebx
movq 0x28(%rsp), %r13
movq %r13, %rsi
movq 0x50(%rsp), %rdx
movq 0x30(%rsp), %r12
movq %r12, %rcx
movq 0x40(%rsp), %rbp
movq %rbp, %r8
movq 0x8(%rsp), %r9
movq %r9, 0x8(%rsp)
xorl %eax, %eax
movq 0x80(%rsp), %r15
pushq %r15
pushq 0x78(%rsp)
callq 0x3210
popq %rcx
popq %rdx
movq 0x58(%rsp), %rax
cqto
idivq %r13
movq %rax, 0x380(%r14)
cvtsi2sd %r12, %xmm0
movapd 0x60(%rsp), %xmm2
divsd %xmm2, %xmm0
movsd %xmm0, 0x398(%r14)
cvtsi2sd %rbp, %xmm0
divsd %xmm2, %xmm0
movsd %xmm0, 0x390(%r14)
cvtsi2sd %r15, %xmm0
cvtsi2sdq 0x8(%rsp), %xmm1
unpcklpd %xmm0, %xmm1            # xmm1 = xmm1[0],xmm0[0]
unpcklpd %xmm2, %xmm2            # xmm2 = xmm2[0,0]
divpd %xmm2, %xmm1
movupd %xmm1, 0x3a0(%r14)
cmpq $0xe, %rbx
je 0xad03
movq 0xb0(%rsp,%rbx,8), %rdi
callq 0x3070
incq %rbx
jmp 0xaceb
movq 0x88(%rsp), %rax
addq $0x128, %rsp            # imm = 0x128
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movsd 0x20(%rsp), %xmm4
jmp 0xa981