var Nt = function() { 'use strict'; function makeArray(length, val) { if (val === undefined) { val = 0|0; } if (val < 0) { val = 0; } length |= 0; var max = 0; for (var i = length; i !== 0; i >>>= 1) { max++; } var n = Array(max); n[0] = [val]; for (i = 1; i < max; i++) { n[i] = n[i-1].concat(n[i-1]); } var a = []; for (var i = 0, l = length; l !== 0; l >>>= 1, i++) { if (l&1) { a = a.concat(n[i]); } } return a; }; var __bitCount = (function() { var a = new Uint8Array(256); var bin; for (var i = 0; i < 256; i++) { bin = i; bin = bin - ((bin >> 1) & 0x55555555); bin = (bin & 0x33333333) + ((bin >> 2) & 0x33333333); a[i] = (((bin + (bin >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; } return a; })(); var __nucleotideTo4Bit = Object.create(null); __nucleotideTo4Bit['A'] = 8; // 0b1000 __nucleotideTo4Bit['T'] = 4; // 0b0100 __nucleotideTo4Bit['G'] = 2; // 0b0010 __nucleotideTo4Bit['C'] = 1; // 0b0001 function setNucleotide() { var n = arguments[0]; __nucleotideTo4Bit[n] = 0; for (var i = 1; i < arguments.length; i++) { __nucleotideTo4Bit[n] |= __nucleotideTo4Bit[arguments[i]]; } }; setNucleotide('-'); setNucleotide('W', 'A', 'T'); setNucleotide('S', 'G', 'C'); setNucleotide('M', 'A', 'C'); setNucleotide('K', 'G', 'T'); setNucleotide('R', 'A', 'G'); setNucleotide('Y', 'C', 'T'); setNucleotide('B', 'C', 'G', 'T'); setNucleotide('D', 'A', 'G', 'T'); setNucleotide('H', 'A', 'C', 'T'); setNucleotide('V', 'A', 'C', 'G'); setNucleotide('N', 'A', 'T', 'G', 'C'); var __4BitToNucleotide = ( function() { var a = makeArray(16); var keys = Object.keys(__nucleotideTo4Bit); for (var i = 0, len = keys.length; i < len; i++) { a[__nucleotideTo4Bit[keys[i]]] = keys[i]; } return a; } )(); var __nucleotideList = Object.keys(__nucleotideTo4Bit); var __complementNucleotide = ( function() { var a = Object.create(null); a['A'] = 'T'; a['G'] = 'C'; a['B'] = 'V'; a['H'] = 'D'; a['M'] = 'K'; a['R'] = 'Y'; // S, W, N, - not included var keys = Object.keys(a); for (var i = 0, len = keys.length; i < len; i++) { a[a[keys[i]]] = keys[i]; } a['S'] = 'S'; a['W'] = 'W'; a['N'] = 'N'; a['-'] = '-'; return a; } )(); var __complement4Bit = ( function() { var a = new Uint8Array(16); for (var i = 0, len = a.length; i < len; i++) { a[i] = __nucleotideTo4Bit[__complementNucleotide[__4BitToNucleotide[i]]]; } return a; } )(); function nucleotideToBin(s) { return __nucleotideTo4Bit[s] | 0; } function binToNucleotide(b) { return __4BitToNucleotide[b] || '-'; } function complementNucleotide(s) { return __complementNucleotide[s] || '-'; } function complementBin(b) { return __complement4Bit[b] | 0; } /* Double up to form bytes */ var __byteComplement; var __nucleotidesToByte; var __byteToNucleotides; var __byteNucleotideContent; void function() { var a = Object.create(null); var b = new Uint8Array(256); var c = new makeArray(256); var d = new makeArray(256); var keys = Object.keys(__nucleotideTo4Bit); var len = keys.length; var ki; var kj; var byte; for (var i = 0; i < len; i++) { ki = keys[i]; for (var j = 0; j < len; j++) { kj = keys[j]; byte = __nucleotideTo4Bit[ki] | (__nucleotideTo4Bit[kj] << 4); a[ki + kj] = byte; b[byte] = __nucleotideTo4Bit[complementNucleotide(kj)] | (__nucleotideTo4Bit[complementNucleotide(ki)] << 4); c[byte] = ki + kj; d[byte] = [ki, kj]; } } __nucleotidesToByte = a; __byteComplement = b; __byteToNucleotides = c; __byteNucleotideContent = d; }(); function nucleotidesToByte(ss) { return __nucleotidesToByte[ss] | 0; } /* amino acids */ var __codonToAminoAcid = Object.create(null); __codonToAminoAcid['AAA'] = 'K'; __codonToAminoAcid['AAT'] = 'N'; __codonToAminoAcid['AAG'] = 'K'; __codonToAminoAcid['AAC'] = 'N'; __codonToAminoAcid['ATA'] = 'I'; __codonToAminoAcid['ATT'] = 'I'; __codonToAminoAcid['ATG'] = 'M'; __codonToAminoAcid['ATC'] = 'I'; __codonToAminoAcid['AGA'] = 'R'; __codonToAminoAcid['AGT'] = 'S'; __codonToAminoAcid['AGG'] = 'R'; __codonToAminoAcid['AGC'] = 'S'; __codonToAminoAcid['ACA'] = 'T'; __codonToAminoAcid['ACT'] = 'T'; __codonToAminoAcid['ACG'] = 'T'; __codonToAminoAcid['ACC'] = 'T'; __codonToAminoAcid['TAA'] = '*'; __codonToAminoAcid['TAT'] = 'Y'; __codonToAminoAcid['TAG'] = '&'; __codonToAminoAcid['TAC'] = 'Y'; __codonToAminoAcid['TTA'] = 'L'; __codonToAminoAcid['TTT'] = 'F'; __codonToAminoAcid['TTG'] = 'L'; __codonToAminoAcid['TTC'] = 'F'; __codonToAminoAcid['TGA'] = '$'; __codonToAminoAcid['TGT'] = 'C'; __codonToAminoAcid['TGG'] = 'W'; __codonToAminoAcid['TGC'] = 'C'; __codonToAminoAcid['TCA'] = 'S'; __codonToAminoAcid['TCT'] = 'S'; __codonToAminoAcid['TCG'] = 'S'; __codonToAminoAcid['TCC'] = 'S'; __codonToAminoAcid['GAA'] = 'E'; __codonToAminoAcid['GAT'] = 'D'; __codonToAminoAcid['GAG'] = 'E'; __codonToAminoAcid['GAC'] = 'D'; __codonToAminoAcid['GTA'] = 'V'; __codonToAminoAcid['GTT'] = 'V'; __codonToAminoAcid['GTG'] = 'V'; __codonToAminoAcid['GTC'] = 'V'; __codonToAminoAcid['GGA'] = 'G'; __codonToAminoAcid['GGT'] = 'G'; __codonToAminoAcid['GGG'] = 'G'; __codonToAminoAcid['GGC'] = 'G'; __codonToAminoAcid['GCA'] = 'A'; __codonToAminoAcid['GCT'] = 'A'; __codonToAminoAcid['GCG'] = 'A'; __codonToAminoAcid['GCC'] = 'A'; __codonToAminoAcid['CAA'] = 'Q'; __codonToAminoAcid['CAT'] = 'H'; __codonToAminoAcid['CAG'] = 'Q'; __codonToAminoAcid['CAC'] = 'H'; __codonToAminoAcid['CTA'] = 'L'; __codonToAminoAcid['CTT'] = 'L'; __codonToAminoAcid['CTG'] = 'L'; __codonToAminoAcid['CTC'] = 'L'; __codonToAminoAcid['CGA'] = 'R'; __codonToAminoAcid['CGT'] = 'R'; __codonToAminoAcid['CGG'] = 'R'; __codonToAminoAcid['CGC'] = 'R'; __codonToAminoAcid['CCA'] = 'P'; __codonToAminoAcid['CCT'] = 'P'; __codonToAminoAcid['CCG'] = 'P'; __codonToAminoAcid['CCC'] = 'P'; var __12BitToAminoAcid = (function() { var a = makeArray(4096, '?'); var codons = Object.keys(__codonToAminoAcid); var codon; for (var i = 0, len = codons.length; i < len; i++) { codon = codons[i]; a[ (nucleotideToBin(codon[2]) << 8) | (nucleotideToBin(codon[1]) << 4) | nucleotideToBin(codon[0]) ] = __codonToAminoAcid[codon]; } return a; })(); function Seq(type) { if (type === undefined) { type = 'DNA'; } if (!{'RNA': true, 'DNA': true}[type]) { throw new Error('Sequence type ' + type + ' not supported'); } this.__type = type; this.__isRNA = (type === 'RNA'); this.__endPadding = 0; this.__buffer = new ArrayBuffer(4); this.__complement = null; this.__content = null; this.__fractionalContent = null; this.__contentATGC = null; this.__fractionalContent = null; }; Seq.prototype.read = function(strData) { var ntToByte = nucleotidesToByte; var nucleotideString = strData.toUpperCase() .replace(/\s/g, '') .replace('U', 'T') .replace(/[^ATGCBVHDMKRYSWN\-]/g, '-'); var length = nucleotideString.length | 0; var max = length >>> 1; var odd = length & 1; var endPadding = (4 - (max + odd) % 4) % 4; this.__endPadding = endPadding; var buffer = new ArrayBuffer(max + odd + endPadding + 4); var dataArray = new Int8Array(buffer, 4); var n; var byte; var content; for (var i = 0; i < max; i++) { n = i << 1; dataArray[i] = ntToByte(nucleotideString[n] + nucleotideString[++n]); } if (odd) { dataArray[i] = __nucleotideTo4Bit[nucleotideString[i << 1]]; } this.__buffer = buffer; this.__length = length; (new Uint32Array(buffer, 0, 1))[0] = length; this.__complement = null; this.__content = null; this.__fractionalContent = null; this.__contentATGC = null; this.__fractionalContent = null; return this; }; Seq.prototype.readFASTA = function(strFASTA) { var data = strFASTA.split(/\n\r?/gi); while (data.length && data[0][0] === '>') { data.shift(); } return this.read(data.join('')); }; Seq.prototype.readBuffer = function(buffer) { this.__buffer = buffer; var length = (new Uint32Array(buffer, 0, 1))[0]; var max = length >>> 1; var odd = length & 1; var endPadding = (4 - (max + odd) % 4) % 4; this.__endPadding = endPadding; this.__length = length; this.__complement = null; this.__content = null; this.__fractionalContent = null; this.__contentATGC = null; this.__fractionalContent = null; return this; }; Seq.prototype.__byteComplement = function() { var bComp = __byteComplement; var fwdBuffer = this.__buffer; var len = fwdBuffer.byteLength; var n, i; var copyBuffer, fromArray, copyArray; var isOdd = this.__length & 1; if (isOdd) { copyBuffer = new ArrayBuffer(len); copyArray = new Uint32Array(copyBuffer, 4); fromArray = new Uint32Array(fwdBuffer, 4); n = (len - 4) >>> 2; while(n--) { copyArray[n] = (fromArray[n] << 4) | ((fromArray[n - 1]) >>> 28); } } else { copyBuffer = fwdBuffer; } var fwdArray = new Uint8Array(copyBuffer, 4); var buffer = new ArrayBuffer(len); var dataArray = new Uint8Array(buffer, 4); n = (len - 4) - this.__endPadding; i = 0; while(n--) { dataArray[i++] = bComp[fwdArray[n]]; } (new Uint32Array(buffer, 0, 1))[0] = this.__length; return buffer; }; Seq.prototype.size = function() { return this.__length; }; Seq.prototype.sequence = function() { var byteToNt = __byteToNucleotides; var buffer = this.__buffer; if (buffer.byteLength < 4) { return ''; } var dataArray = new Uint8Array(buffer, 4); var len = (buffer.byteLength - 4) - this.__endPadding; var nts = makeArray(len); for (var i = 0; i < len; i++) { nts[i] = byteToNt[dataArray[i]]; } var returnString; i = nts.length - 1; if (this.__length & 1) { nts[i] = nts[i][0]; } returnString = nts.join(''); if (this.__isRNA) { returnString = returnString.replace(/T/gi, 'U'); } return returnString; }; Seq.prototype.complement = function() { if (!this.__complement) { this.__complement = this.__byteComplement(); } var complement = new Seq(this.__type).readBuffer(this.__complement.slice(0)); complement.__complement = this.__buffer.slice(0); return complement; }; Seq.prototype.equivalent = function(seq) { if (!(seq instanceof Seq)) { throw new Error('Can only check for equivalence between sequences'); } if (this.__type !== seq.__type) { return false; } var checkInts = new Uint32Array(this.__buffer); var compareInts = new Uint32Array(seq.__buffer); for (var i = 0, len = checkInts.length; i < len; i++) { if (checkInts[i] !== compareInts[i]) { return false; } } return true; }; Seq.prototype.replicate = function(start, length) { start |= 0; if (start < 0) { start = this.__length + start; } if (length === undefined) { if (start === 0) { return this.__clone(); } length = this.__length - start; } else { length |= 0; length = Math.min(length, this.__length - start); } length = Math.min(length, this.__length - start); if (length <= 0) { return this.__nullSeq(); } return this.__slice(start, length); }; Seq.prototype.polymerize = function(seq) { var seqLen = seq.__length; if (!(seq instanceof Seq)) { throw new Error('.polymerize requires valid sequence'); } if (!this.__length) { return seq.__clone(); } var offset = this.__length; var length = this.__length + seqLen; var max = length >>> 1; var odd = length & 1; var endPadding = (4 - (max + odd) % 4) % 4; var newBuffer = new ArrayBuffer(max + odd + endPadding + 4); var newArray = new Uint32Array(newBuffer, 4); var copyBuffer = this.__buffer; var copyArray = new Uint32Array(copyBuffer, 4); var seqBuffer = seq.__buffer; var seqArray = new Uint32Array(seqBuffer, 4); var copyPos = 0; var shift = (this.__length % 8) * 4; var shiftSeq = 32 - shift; for (var len = copyArray.length; copyPos < len; copyPos++) { newArray[copyPos] = copyArray[copyPos]; } if (shift) { newArray[--copyPos] |= seqArray[0] << shift; for (var i = 0, len = seqArray.length; i < len; i++) { newArray[++copyPos] = (seqArray[i] >>> shiftSeq) | (seqArray[i + 1] << shift); } } else { for (var i = 0, len = seqArray.length; i < len; i++) { newArray[copyPos++] = seqArray[i]; } } (new Uint32Array(newBuffer, 0, 1))[0] = length; return new Seq(this.__type).readBuffer(newBuffer); }; Seq.prototype.insertion = function(seq, offset) { if (!(seq instanceof Seq)) { throw new Error('Insertion requires valid sequence'); } offset |= 0; if (offset < 0) { offset = this.__length + offset; } offset = Math.min(offset, this.__length); return this.replicate(0, offset).polymerize(seq).polymerize(this.replicate(offset)); }; Seq.prototype.deletion = function(offset, count) { if (offset === undefined || count === undefined) { throw new Error('Must give valid offset and count for deletion'); } offset |= 0; count |= 0; if (count === 0) { return this.__clone(); } if (count < 0) { throw new Error('Invalid count for deletion'); } if (offset < 0) { offset = this.__length + offset; } offset = Math.min(offset, this.__length); return this.replicate(0, offset).polymerize(this.replicate(offset + count)); }; Seq.prototype.repeat = function(count) { count |= 0; var copy = this.replicate(); var base = new Seq(this.__type); if (count <= 0) { return base; } while(true) { if (count & 1) { base = base.polymerize(copy); } count >>>= 1; if (!count) { break; } copy = copy.polymerize(copy); } return base; }; Seq.prototype.mask = function(seq) { if (!(seq instanceof Seq)) { throw new Error('Can only mask with valid sequence'); } var newBuffer = this.__buffer.slice(0); var newArray = new Uint32Array(newBuffer, 4); var compareArray = new Uint32Array(seq.__buffer, 4); for (var i = 0, len = newArray.length; i < len; i++) { newArray[i] &= compareArray[i]; } return new Seq(this.__type).readBuffer(newBuffer); }; Seq.prototype.cover = function(seq) { if (!(seq instanceof Seq)) { throw new Error('Can only cover with valid sequence'); } var newBuffer = this.__buffer.slice(0); var newArray = new Uint32Array(newBuffer, 4); var compareArray = new Uint32Array(seq.__buffer, 4); for (var i = 0, len = newArray.length; i < len; i++) { newArray[i] |= compareArray[i]; } return new Seq(this.__type).readBuffer(newBuffer); }; Seq.prototype.__nullSeq = function() { return new Seq(this.__type).readBuffer(new ArrayBuffer(4)); }; Seq.prototype.__clone = function() { return new Seq(this.__type).readBuffer(this.__buffer.slice(0)); }; Seq.prototype.__slice = function(start, length) { var max = length >>> 1; var odd = length & 1; var endPadding = (4 - (max + odd) % 4) % 4; var newBuffer = new ArrayBuffer(max + odd + endPadding + 4); var newArray = new Uint32Array(newBuffer, 4); var subBuffer = this.__buffer.slice(4 + (start >>> 1), 4 + (start >>> 1) + newBuffer.byteLength); var subInt32Length = subBuffer.byteLength >>> 2; var subArray = new Uint32Array(subBuffer, 0, subInt32Length); if (start & 1) { for (var i = 0, len = subArray.length; i < len; i++) { newArray[i] = (subArray[i] >>> 4) | (subArray[i + 1] << 28); } var remainder = subBuffer.byteLength - subArray.byteLength; if (remainder) { var remainderArray = new Uint8Array(newBuffer, 4 + (i << 2)); var subRemainderArray = new Uint8Array(subBuffer, i << 2); if (newArray.length > 0) { newArray[i - 1] |= subRemainderArray[0] << 28; } for (var i = 0, len = subRemainderArray.length; i < len; i++) { remainderArray[i] = (subRemainderArray[i] >>> 4) | (subRemainderArray[i + 1] << 4); } } } else { for (var i = 0, len = subArray.length; i < len; i++) { newArray[i] = subArray[i]; } var remainder = subArray.byteLength - subBuffer.byteLength; if (remainder) { var remainderArray = new Uint8Array(newBuffer, 4 + (i << 2)); var subRemainderArray = new Uint8Array(subBuffer, i << 2); for (var i = 0, len = subRemainderArray.length; i < len; i++) { remainderArray[i] = subRemainderArray[i]; } } } var clearShift = ((endPadding * 2) + odd) * 4; var clearOut = new Uint32Array(newBuffer, newBuffer.byteLength - 4); clearOut[0] = (clearOut[0] << clearShift) >>> clearShift; (new Uint32Array(newBuffer, 0, 1))[0] = length; return new Seq(this.__type).readBuffer(newBuffer); }; Seq.prototype.content = function() { if (!this.__content) { var ntContentByte = makeArray(256); var buffer = this.__buffer; var dataArray = new Uint8Array(buffer); for(var i = 4; i < buffer.byteLength - this.__endPadding; i++) { ntContentByte[dataArray[i]]++; } var binToNt = binToNucleotide; var ntList = __nucleotideList; var ntContent = Object.create(null); for (var i = 0, len = ntList.length; i < len; i++) { ntContent[ntList[i]] = 0; } for (var i = 0, len = ntContentByte.length; i < len; i++) { if (ntContentByte[i]) { ntContent[binToNt(i & 0xF)] += ntContentByte[i]; ntContent[binToNt(i >>> 4)] += ntContentByte[i]; } } if (this.__length & 1) { ntContent['-']--; } if (this.__isRNA) { ntContent['U'] = ntContent['T']; delete ntContent['T']; } this.__content = ntContent; } var returnContent = Object.create(null); var keys = Object.keys(this.__content); for (var i = 0, len = keys.length; i < len; i++) { returnContent[keys[i]] = this.__content[keys[i]]; } return returnContent; }; Seq.prototype.fractionalContent = function() { if (!this.__fractionalContent) { var content = this.content(); var nts = Object.keys(content); for (var i = 0, len = nts.length; i < len; i++) { content[nts[i]] = content[nts[i]] / this.__length; } this.__fractionalContent = content; } var returnContent = Object.create(null); var keys = Object.keys(this.__fractionalContent); for (var i = 0, len = keys.length; i < len; i++) { returnContent[keys[i]] = this.__fractionalContent[keys[i]]; } return returnContent; }; Seq.prototype.contentATGC = function() { if (!this.__contentATGC) { var ntToBin = nucleotideToBin; var content = this.content(); var nts = Object.keys(content); var contentATGC = Object.create(null); contentATGC['A'] = 0; contentATGC['T'] = 0; contentATGC['G'] = 0; contentATGC['C'] = 0; var bits = 0; var nt; var ntBin; var n; var curContent; for (var i = 0, len = nts.length; i < len; i++) { nt = nts[i]; n = ntToBin(nt); for (bits = 0; n; bits++) { n &= n - 1; } ntBin = ntToBin(nt); curContent = content[nts[i]] * (1 / bits); contentATGC['A'] += (((ntToBin('A') & ntBin) | 0) && curContent); contentATGC['T'] += (((ntToBin('T') & ntBin) | 0) && curContent); contentATGC['G'] += (((ntToBin('G') & ntBin) | 0) && curContent); contentATGC['C'] += (((ntToBin('C') & ntBin) | 0) && curContent); } if (this.__isRNA) { contentATGC['U'] = contentATGC['T']; delete contentATGC['T']; } this.__contentATGC = contentATGC; } var returnContent = Object.create(null); var keys = Object.keys(this.__contentATGC); for (var i = 0, len = keys.length; i < len; i++) { returnContent[keys[i]] = this.__contentATGC[keys[i]]; } return returnContent; }; Seq.prototype.fractionalContentATGC = function() { if (!this.__fractionalContentATGC) { var content = this.contentATGC(); var nts = Object.keys(content); for (var i = 0, len = nts.length; i < len; i++) { content[nts[i]] = content[nts[i]] / this.__length; } this.__fractionalContentATGC = content; } var returnContent = Object.create(null); var keys = Object.keys(this.__fractionalContentATGC); for (var i = 0, len = keys.length; i < len; i++) { returnContent[keys[i]] = this.__fractionalContentATGC[keys[i]]; } return returnContent; }; Seq.prototype.translate = function(ntOffset, ntCount) { var binToAA = __12BitToAminoAcid; ntOffset |= 0; if (ntCount === undefined) { ntCount = this.__length - ntOffset; } ntCount |= 0; ntCount -= (ntCount % 3); var offset = (ntOffset >>> 1) + 4; var max = offset + (ntCount >>> 1) + (ntCount & 1); var dataArray = new Uint8Array(this.__buffer); var aminoAcids = makeArray(ntCount / 3); /**/ var aa = 0; var lastByte, byte1, byte2, byte3; if ((ntOffset & 1) === 0) { for (var i = offset; i < max; i += 3) { var byte1 = dataArray[i]; var byte2 = dataArray[i+1]; var byte3 = dataArray[i+2]; aminoAcids[aa++] = binToAA[byte1 | ((byte2 & 0xF) << 8)]; aminoAcids[aa++] = binToAA[(byte3 << 4) | (byte2 >>> 4)]; } } else { lastByte = dataArray[offset]; for (var i = offset + 1; i < max; i += 3) { byte1 = dataArray[i]; byte2 = dataArray[i+1]; byte3 = dataArray[i+2]; aminoAcids[aa++] = binToAA[(lastByte >> 4) | (byte1 << 4)]; aminoAcids[aa++] = binToAA[byte2 | ((byte3 & 0xF) << 8)]; lastByte = byte3; } } if (ntCount & 1) { aminoAcids.pop(); } return aminoAcids.join(''); }; Seq.prototype.translateFrame = function(frame, AAoffset, AAcount) { if (frame === undefined) { frame = 0; } if (frame !== 0 && frame !== 1 && frame !== 2) { throw new Error('Invalid translation frame, must be 0, 1 or 2.'); } if (AAoffset === undefined) { return this.translate(frame); } if (AAcount === undefined) { return this.translate(frame + ((AAoffset | 0) * 3)); } return this.translate(frame + ((AAoffset | 0) * 3), (AAcount * 3) | 0); }; Seq.prototype.mapSequence = function(seq, offset) { if (!(seq instanceof Seq)) { throw new Error('.mapSequence requires valid Seq'); } return new MatchMap(seq, this, offset); }; /* MatchResult */ function MatchResult(matchMap, pos, score) { Object.defineProperty(this, '__matchMap', {value: matchMap}); this.position = pos; this.score = score; this.__align = null; }; MatchResult.prototype.alignment = function() { if (!this.__align) { var map = this.__matchMap; if (this.position < 0) { this.__align = (new Nt.Seq()) .read('-') .repeat(-this.position) .polymerize(map.__searchSpace.replicate(0, map.__query.__length + this.position)); } else if (this.position + map.__query.__length > map.__searchSpace.__length) { this.__align = map.__searchSpace .replicate(this.position) .polymerize((new Nt.Seq()).read('-').repeat(map.__searchSpace.__length - this.position)); } else { this.__align = map.__searchSpace.replicate(this.position, map.__query.__length); } } return this.__align; }; MatchResult.prototype.alignmentMask = function() { return this.__matchMap.__query.mask(this.alignment()); }; MatchResult.prototype.alignmentCover = function() { return this.__matchMap.__query.cover(this.alignment()); }; /* MatchMap */ function MatchMap(query, searchSpace, offset) { if (!(query instanceof Seq) || !(searchSpace instanceof Seq)) { throw new Error('MatchMap requires valid Seq'); } this.__query = query.replicate(); this.__searchSpace = searchSpace.replicate(); this.__results = []; this.__orderedResults = []; this.__matchFrequencyData = null; this.__initialized = false; this.__offset = Math.max(0, offset | 0); this.__positionAdjustment = this.__offset - (this.__query.size() - 1); this.__debug = { searchTime: null, prepareTime: null, sortTime: null }; }; MatchMap.prototype.initialize = function(results) { this.__orderedResults = []; this.__matchFrequencyData = null; this.__initialized = true; var t = (new Date).valueOf(); if (!results) { var dataArray = new Uint32Array(this.__execute(this.__query.__buffer, this.__searchSpace.__buffer)); this.__debug.searchTime = (-t) + (t = (new Date).valueOf()); var queryLen = this.__query.size(); var searchLen = this.__searchSpace.size(); var resultsLen = ((8 - (queryLen % 8)) % 8) + 1; var totalLen = searchLen + queryLen - 1; results = [].slice.call(dataArray, resultsLen, resultsLen + totalLen); } this.__results = results; this.__debug.prepareTime = (-t) + (t = (new Date).valueOf()); return this; }; MatchMap.prototype.sort = function() { if (!this.__initialized) { throw new Error('MatchMap must be initialized first.'); } var t = new Date().valueOf(); if (this.__debug.sortTime !== null) { return this; } var adjust = this.__positionAdjustment; this.__orderedResults = this.__results .map(function(v, i) { return {n: i + adjust, s: v}; }) .sort(function(a, b) { return b.s - a.s; }); this.__debug.sortTime = new Date().valueOf() - t; return this; }; MatchMap.prototype.__calculate_p_match = function(query, searchSpace) { /* The approximate probability that two randomly chosen nucleotides from QUERY and SEARCH match each other */ var queryContent = query.fractionalContentATGC(); var searchSpaceContent = searchSpace.fractionalContentATGC(); return (queryContent['A'] * searchSpaceContent['A']) + (queryContent['T'] * searchSpaceContent['T']) + (queryContent['G'] * searchSpaceContent['G']) + (queryContent['C'] * searchSpaceContent['C']); }; MatchMap.prototype.results = function(offset, count) { if (!this.__initialized) { throw new Error('MatchMap must be initialized first.'); } if (offset === undefined) { return this.__results.slice(); } if (count === undefined) { return this.__results.slice(offset | 0); } return this.__results.slice(offset | 0, count | 0); }; MatchMap.prototype.best = function() { if (!this.__initialized) { throw new Error('MatchMap must be initialized first.'); } if (!this.__orderedResults.length) { throw new Error('MatchMap must be sorted first.'); } var result = this.__orderedResults[0]; return new MatchResult(this, result.n, result.s); }; MatchMap.prototype.top = function(n) { if (!this.__initialized) { throw new Error('MatchMap must be initialized first.'); } if (!this.__orderedResults.length) { throw new Error('MatchMap must be sorted first.'); } var self = this; return this.__orderedResults.slice(0, n).map(function(result) { return new MatchResult(self, result.n, result.s); }); }; MatchMap.prototype.bottom = function(n) { if (!this.__initialized) { throw new Error('MatchMap must be initialized first.'); } if (!this.__orderedResults.length) { throw new Error('MatchMap must be sorted first.'); } var self = this; var adjust = this.__positionAdjustment; var len = this.__orderedResults.length; return this.__orderedResults.slice(this.__orderedResults.length - n, n).map(function(result) { return new MatchResult(self, result.n, result.s); }); }; /* Can be optimized with binary splitting */ MatchMap.prototype.matchFrequencyData = function() { if (!this.__initialized) { throw new Error('MatchMap must be initialized first.'); } if (!this.__orderedResults.length) { throw new Error('MatchMap must be sorted first.'); } if (this.__matchFrequencyData) { return this.__matchFrequencyData; } var ordered = this.__orderedResults; var matchFrequencyData = makeArray(this.__query.size() + 1); var maxMatch = this.__query.size(); var lastIndex = 0; var num; for (var i = 0, len = ordered.length; i < len; i++) { num = ordered[i].s; if (num < maxMatch) { matchFrequencyData[maxMatch] = i - lastIndex; lastIndex = i; maxMatch = num; } if (num === 0) { matchFrequencyData[0] = len - i; break; } } return (this.__matchFrequencyData = matchFrequencyData); }; MatchMap.prototype.__countMatches = function(int, bitCount) { int |= int >>> 1; int |= int >>> 2; int &= 0x11111111; int |= int >>> 3; int |= int >>> 6; return bitCount[((int >>> 12) & 0xF0) | (int & 0xF)]; }; MatchMap.prototype.__execute = function(queryBuffer, searchSpaceBuffer) { var queryInts, spaceInts, queryIntsLength, spaceIntsLength, arrLen, mapBuffer, mapArray, A, B, A1, A2, T, cur, pos, move, i, k, adjustNeg, adjustPos, fnCountMatches, bitCount; queryInts = new Uint32Array(queryBuffer, 4); spaceInts = new Uint32Array(searchSpaceBuffer, 4); fnCountMatches = this.__countMatches; bitCount = __bitCount; queryIntsLength = queryInts.length|0; spaceIntsLength = spaceInts.length|0; arrLen = (queryIntsLength + spaceIntsLength) << 3; mapBuffer = new ArrayBuffer(4 * arrLen); mapArray = new Uint32Array(mapBuffer); for (k = 0|0; k < queryIntsLength; k++) { A = queryInts[k]; cur = (queryIntsLength - k) << 3; for (i = 0|0; i < spaceIntsLength; i++) { (T = A & spaceInts[i]) && (mapArray[(i << 3) + cur] += fnCountMatches(T, bitCount)); } A1 = A >>> 4; A2 = A << 4; adjustNeg = cur - 1; adjustPos = cur + 1; while(A1 || A2) { for (i = 0|0; i < spaceIntsLength; i++) { B = spaceInts[i]; pos = (i << 3); (T = A1 & B) && (mapArray[pos + adjustNeg] += fnCountMatches(T, bitCount)); (T = A2 & B) && (mapArray[pos + adjustPos] += fnCountMatches(T, bitCount)); } A1 >>>= 4; A2 <<= 4; --adjustNeg; ++adjustPos; } } return mapBuffer; }; return { Seq: Seq, MatchMap: MatchMap }; }();