diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..8da7481 --- /dev/null +++ b/LICENCE @@ -0,0 +1,24 @@ +opyright (c) 2013, Jeongbin Park +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or other +materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4c36287 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +Cas-Analyzer +== + +Updated soon diff --git a/core/compile_core.sh b/core/compile_core.sh new file mode 100755 index 0000000..40dc6a0 --- /dev/null +++ b/core/compile_core.sh @@ -0,0 +1,4 @@ +cp jbfilereader/jbfilereader.coffee . +coffee --bare --compile jbfilereader.coffee +coffee --bare --compile fastq-join.coffee +coffee --bare --compile miseq-analyzer.coffee diff --git a/core/fastq-join-sync.coffee b/core/fastq-join-sync.coffee new file mode 100644 index 0000000..25b5c73 --- /dev/null +++ b/core/fastq-join-sync.coffee @@ -0,0 +1,220 @@ +### +fastq-join.coffee +(Based on Fastq-join 1.01 by Expression Analysis / Erik Aronesty) + +Copyright (c) 2015 Jeongbin Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +### + +dev = 0 +joins = [] +#un1s = [] +#un2s = [] + +class _line + constructor: -> + this.s = '' + this.n = 0 + +class _fq + constructor: -> + this.id = new _line + this.seq = new _line + this.com = new _line + this.qual = new _line + +comp = (l) -> + for i in [0...l.length] by 1 + if l[i] == 'A' + l[i] = 'T' + else if l[i] == 'T' + l[i] = 'A' + else if l[i] == 'G' + l[i] = 'C' + else if l[i] == 'C' + l[i] = 'G' + else if l[i] == 'a' + l[i] = 't' + else if l[i] == 't' + l[i] = 'a' + else if l[i] == 'g' + l[i] = 'c' + else if l[i] == 'c' + l[i] = 'g' + return l + +revcomp = (fq) -> + fq.seq.s = comp(fq.seq.s).reverse() # Non-unicode aware! + fq.qual.s = fq.qual.s.reverse() # Again, non-unicode aware! + return fq + +min = (a, b) -> + if a > b + return b + else + return a + +max = (a, b) -> + if a < b + return b + else + return a + +hd = (a, s, b, n) -> + d = 0 + i = 0 + while n > 0 + if a[s+i] != b[i] + d++ + n-- + i++ + return d+n + +# Third mate file is not supported yet +run_fastq_join = (files, donecallback, pgcallback, chunkcallback, joinsonly = false, mino = 6, pctdiff = 8) -> + dev = 0 + joincnt = 0 + tlen = 0 + tlensq = 0 + nline = [0, 0] + joins = [] + un1s = [] + un2s = [] + fq = [new _fq, new _fq] + nrec = 0 + prevfpos = 0 + steprec = 50 + + readers = [0, 0] + for nfin in [0..1] by 1 + entries = files[nfin].name.split('.') + if entries[entries.length-1] == 'gz' + gzipped = 1 + readers[nfin] = new jbfilereader(files[nfin], gzipped) + + read_line = (nfin, l, opt) -> + readers[nfin].readline( (line) -> + if readers[0].eof or line == "" + readers[1].readline( (line2) -> + if readers[1].eof or line2 == "" + post_loop() + else + self.postMessage({msgtype: 1, error: "# of rows in mate file doesn't match primary file!"}) + ) + else if readers[1].eof and !readers[0].eof + self.postMessage({msgtype: 1, error: "# of rows in mate file doesn't match primary file!"}) + else + l.s = line.split("") # To array, because strings are immutable, note that this is not unicode aware! + l.n = l.s.length + opt++ + read_fq(opt) + ) + return + + post_loop = -> + chunkcallback(joins) + pgcallback(100) + donecallback() + return + + read_fq = (opt) -> + for nfin in [0..1] by 1 + if opt == 0+nfin*4 + read_line(nfin, fq[nfin].id, opt) + return + else if opt == 1+nfin*4 + read_line(nfin, fq[nfin].seq, opt) + return + else if opt == 2+nfin*4 + read_line(nfin, fq[nfin].com, opt) + return + else if opt == 3+nfin*4 + read_line(nfin, fq[nfin].qual, opt) + return + if opt == 8 + #if fq[nfin].id.s[0] == '>' + # alert('Input is FASTA!') + # return 1 + if (fq[0].id.n == 0 or (fq[0].id.n != 0 and fq[0].id.s[0] != '@')) or + (fq[1].id.n == 0 or (fq[1].id.n != 0 and fq[1].id.s[0] != '@')) + self.postMessage({msgtype: 1, error: 'Input file is not FASTQ!'}) + return 1 + main_loop() + return + return + + main_loop = -> + nrec++ + rc = revcomp(fq[1]) + maxo = min(fq[0].seq.n, rc.seq.n) + bestscore = 2147483647 # INT_MAX of C + besto = -1 + for i in [mino..maxo] by 1 + mind = (pctdiff * i) // 100 + d = hd(fq[0].seq.s, fq[0].seq.n-i, rc.seq.s, i) + if d <= mind + score = (1000*(d*d+1)) // i + if (score < bestscore) + bestscore = score + besto = i + hasex = 0 + olen = besto - hasex + if besto > 0 + joincnt++ + + tlen += olen + tlensq += olen**2 + + #joins.push(fq[0].id.s.join("") + "\n") + for i in [0...besto] by 1 + li = fq[0].seq.n-besto+i + ri = i + if fq[0].seq.s[li] == rc.seq.s[ri] + fq[0].qual.s[li] = String.fromCharCode(max(fq[0].qual.s[li].charCodeAt(0), rc.qual.s[ri].charCodeAt(0))) + else + if fq[0].qual.s[li].charCodeAt(0) > rc.qual.s[ri].charCodeAt(0) + fq[0].qual.s[li] = String.fromCharCode(33+min(fq[0].qual.s[li].charCodeAt(0),max(fq[0].qual.s[li].charCodeAt(0)-rc.qual.s[ri].charCodeAt(0),3))) + else + fq[0].seq.s[li] = rc.seq.s[ri] + fq[0].qual.s[li] = String.fromCharCode(33+min(rc.qual.s[ri].charCodeAt(0),max(rc.qual.s[ri].charCodeAt(0)-fq[0].qual.s[li].charCodeAt(0),3))) + joins.push(fq[0].seq.s.join("") + rc.seq.s[besto..].join("") + "\n") + #joins.push(fq[0].com.s.join("") + "\n") + #joins.push(fq[0].qual.s.join("") + rc.qual.s[besto..].join("") + "\n") + #else if !joinsonly + # un1s.push(fq[0].id.s.join("") + "\n") + # un1s.push(fq[0].seq.s.join("") + "\n") + # un1s.push(fq[0].com.s.join("") + "\n") + # un1s.push(fq[0].qual.s.join("") + "\n") + # un2s.push(fq[1].id.s.join("") + "\n") + # un2s.push(fq[1].seq.s.join("") + "\n") + # un2s.push(fq[1].com.s.join("") + "\n") + # un2s.push(fq[1].qual.s.join("") + "\n") + if nrec %% steprec == 0 + if prevfpos != readers[0].fpos + pgcallback(readers[0].fpos*100/files[0].size) + chunkcallback(joins) + joins = [] + prevfpos = readers[0].fpos + setTimeout( ( -> read_fq(0)), 0) + else + read_fq(0) + return + setTimeout( ( -> read_fq(0)), 0) + return diff --git a/core/fastq-join.coffee b/core/fastq-join.coffee new file mode 100644 index 0000000..22f5ffc --- /dev/null +++ b/core/fastq-join.coffee @@ -0,0 +1,208 @@ +### +fastq-join.coffee +(Based on Fastq-join 1.01 by Expression Analysis / Erik Aronesty) + +Copyright (c) 2015 Jeongbin Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +### + +dev = 0 +joins = [] +#un1s = [] +#un2s = [] + +class _line + constructor: -> + this.s = '' + this.n = 0 + +class _fq + constructor: -> + this.id = new _line + this.seq = new _line + this.com = new _line + this.qual = new _line + +comp = (l) -> + for i in [0...l.length] by 1 + if l[i] == 'A' + l[i] = 'T' + else if l[i] == 'T' + l[i] = 'A' + else if l[i] == 'G' + l[i] = 'C' + else if l[i] == 'C' + l[i] = 'G' + else if l[i] == 'a' + l[i] = 't' + else if l[i] == 't' + l[i] = 'a' + else if l[i] == 'g' + l[i] = 'c' + else if l[i] == 'c' + l[i] = 'g' + return l + +revcomp = (fq) -> + fq.seq.s = comp(fq.seq.s).reverse() # Non-unicode aware! + fq.qual.s = fq.qual.s.reverse() # Again, non-unicode aware! + return fq + +min = (a, b) -> + if a > b + return b + else + return a + +max = (a, b) -> + if a < b + return b + else + return a + +hd = (a, s, b, n) -> + d = 0 + i = 0 + while n > 0 + if a[s+i] != b[i] + d++ + n-- + i++ + return d+n + +# Third mate file is not supported yet +run_fastq_join = (files, pgcallback, chunkcallback, joinsonly = false, mino = 6, pctdiff = 8) -> + dev = 0 + joincnt = 0 + tlen = 0 + tlensq = 0 + nline = [0, 0] + joins = [] + un1s = [] + un2s = [] + fq = [new _fq, new _fq] + nrec = 0 + prevfpos = 0 + steprec = 500 + + readers = [0, 0] + for nfin in [0..1] by 1 + entries = files[nfin].name.split('.') + if entries[entries.length-1] == 'gz' + gzipped = 1 + else + gzipped = 0 + readers[nfin] = new jbfilereadersync(files[nfin], gzipped) + + read_fq = () -> + eofs = [false, false] + for nfin in [0..1] by 1 + for type in [0..3] by 1 + try + line = readers[nfin].readline() + if line == "" + eofs[nfin] = true + break + catch e + self.postMessage({msgtype: 1, error: e}) + return 2 + if type == 0 + fq[nfin].id.s = line.split("") + fq[nfin].id.n = fq[nfin].id.s.length + else if type == 1 + fq[nfin].seq.s = line.split("") + fq[nfin].seq.n = fq[nfin].seq.s.length + else if type == 2 + fq[nfin].com.s = line.split("") + fq[nfin].com.n = fq[nfin].com.s.length + else if type == 3 + fq[nfin].qual.s = line.split("") + fq[nfin].qual.n = fq[nfin].qual.s.length + if (fq[nfin].id.n == 0 or (fq[nfin].id.n != 0 and fq[nfin].id.s[0] != '@')) + self.postMessage({msgtype: 1, error: "Input file is not FASTQ!"}) + return 2 + if (eofs[0] == true and eofs[1] == false) or (eofs[0] == false and eofs[1] == true) + self.postMessage({msgtype: 1, error: "# of rows in mate file doesn't match primary file!"}) + return 2 + else if eofs[0] == true and eofs[1] == true + return 1 + else + return 0 + + loop + nrec++ + rtn = read_fq() + if rtn == 1 + break + else if rtn == 2 + return + rc = revcomp(fq[1]) + maxo = min(fq[0].seq.n, rc.seq.n) + bestscore = 2147483647 # INT_MAX of C + besto = -1 + for i in [mino..maxo] by 1 + mind = (pctdiff * i) // 100 + d = hd(fq[0].seq.s, fq[0].seq.n-i, rc.seq.s, i) + if d <= mind + score = (1000*(d*d+1)) // i + if (score < bestscore) + bestscore = score + besto = i + hasex = 0 + olen = besto - hasex + if besto > 0 + joincnt++ + + tlen += olen + tlensq += olen**2 + + #joins.push(fq[0].id.s.join("") + "\n") + for i in [0...besto] by 1 + li = fq[0].seq.n-besto+i + ri = i + if fq[0].seq.s[li] == rc.seq.s[ri] + fq[0].qual.s[li] = String.fromCharCode(max(fq[0].qual.s[li].charCodeAt(0), rc.qual.s[ri].charCodeAt(0))) + else + if fq[0].qual.s[li].charCodeAt(0) > rc.qual.s[ri].charCodeAt(0) + fq[0].qual.s[li] = String.fromCharCode(33+min(fq[0].qual.s[li].charCodeAt(0),max(fq[0].qual.s[li].charCodeAt(0)-rc.qual.s[ri].charCodeAt(0),3))) + else + fq[0].seq.s[li] = rc.seq.s[ri] + fq[0].qual.s[li] = String.fromCharCode(33+min(rc.qual.s[ri].charCodeAt(0),max(rc.qual.s[ri].charCodeAt(0)-fq[0].qual.s[li].charCodeAt(0),3))) + joins.push(fq[0].seq.s.join("") + rc.seq.s[besto..].join("") + "\n") + #joins.push(fq[0].com.s.join("") + "\n") + #joins.push(fq[0].qual.s.join("") + rc.qual.s[besto..].join("") + "\n") + #else if !joinsonly + # un1s.push(fq[0].id.s.join("") + "\n") + # un1s.push(fq[0].seq.s.join("") + "\n") + # un1s.push(fq[0].com.s.join("") + "\n") + # un1s.push(fq[0].qual.s.join("") + "\n") + # un2s.push(fq[1].id.s.join("") + "\n") + # un2s.push(fq[1].seq.s.join("") + "\n") + # un2s.push(fq[1].com.s.join("") + "\n") + # un2s.push(fq[1].qual.s.join("") + "\n") + if nrec %% steprec == 0 + if prevfpos != readers[0].fpos + pgcallback(readers[0].fpos*100/files[0].size) + chunkcallback(joins) + joins = [] + prevfpos = readers[0].fpos + chunkcallback(joins) + pgcallback(100) + return diff --git a/core/fastq-join.js b/core/fastq-join.js new file mode 100644 index 0000000..6586b3e --- /dev/null +++ b/core/fastq-join.js @@ -0,0 +1,258 @@ +// Generated by CoffeeScript 1.8.0 + +/* +fastq-join.coffee +(Based on Fastq-join 1.01 by Expression Analysis / Erik Aronesty) + +Copyright (c) 2015 Jeongbin Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +var comp, dev, hd, joins, max, min, revcomp, run_fastq_join, _fq, _line, + __modulo = function(a, b) { return (+a % (b = +b) + b) % b; }; + +dev = 0; + +joins = []; + +_line = (function() { + function _line() { + this.s = ''; + this.n = 0; + } + + return _line; + +})(); + +_fq = (function() { + function _fq() { + this.id = new _line; + this.seq = new _line; + this.com = new _line; + this.qual = new _line; + } + + return _fq; + +})(); + +comp = function(l) { + var i, _i, _ref; + for (i = _i = 0, _ref = l.length; _i < _ref; i = _i += 1) { + if (l[i] === 'A') { + l[i] = 'T'; + } else if (l[i] === 'T') { + l[i] = 'A'; + } else if (l[i] === 'G') { + l[i] = 'C'; + } else if (l[i] === 'C') { + l[i] = 'G'; + } else if (l[i] === 'a') { + l[i] = 't'; + } else if (l[i] === 't') { + l[i] = 'a'; + } else if (l[i] === 'g') { + l[i] = 'c'; + } else if (l[i] === 'c') { + l[i] = 'g'; + } + } + return l; +}; + +revcomp = function(fq) { + fq.seq.s = comp(fq.seq.s).reverse(); + fq.qual.s = fq.qual.s.reverse(); + return fq; +}; + +min = function(a, b) { + if (a > b) { + return b; + } else { + return a; + } +}; + +max = function(a, b) { + if (a < b) { + return b; + } else { + return a; + } +}; + +hd = function(a, s, b, n) { + var d, i; + d = 0; + i = 0; + while (n > 0) { + if (a[s + i] !== b[i]) { + d++; + } + n--; + i++; + } + return d + n; +}; + +run_fastq_join = function(files, pgcallback, chunkcallback, joinsonly, mino, pctdiff) { + var besto, bestscore, d, entries, fq, gzipped, hasex, i, joincnt, li, maxo, mind, nfin, nline, nrec, olen, prevfpos, rc, read_fq, readers, ri, rtn, score, steprec, tlen, tlensq, un1s, un2s, _i, _j, _k; + if (joinsonly == null) { + joinsonly = false; + } + if (mino == null) { + mino = 6; + } + if (pctdiff == null) { + pctdiff = 8; + } + dev = 0; + joincnt = 0; + tlen = 0; + tlensq = 0; + nline = [0, 0]; + joins = []; + un1s = []; + un2s = []; + fq = [new _fq, new _fq]; + nrec = 0; + prevfpos = 0; + steprec = 500; + readers = [0, 0]; + for (nfin = _i = 0; _i <= 1; nfin = _i += 1) { + entries = files[nfin].name.split('.'); + if (entries[entries.length - 1] === 'gz') { + gzipped = 1; + } else { + gzipped = 0; + } + readers[nfin] = new jbfilereadersync(files[nfin], gzipped); + } + read_fq = function() { + var e, eofs, line, type, _j, _k; + eofs = [false, false]; + for (nfin = _j = 0; _j <= 1; nfin = _j += 1) { + for (type = _k = 0; _k <= 3; type = _k += 1) { + try { + line = readers[nfin].readline(); + if (line === "") { + eofs[nfin] = true; + break; + } + } catch (_error) { + e = _error; + self.postMessage({ + msgtype: 1, + error: e + }); + return 2; + } + if (type === 0) { + fq[nfin].id.s = line.split(""); + fq[nfin].id.n = fq[nfin].id.s.length; + } else if (type === 1) { + fq[nfin].seq.s = line.split(""); + fq[nfin].seq.n = fq[nfin].seq.s.length; + } else if (type === 2) { + fq[nfin].com.s = line.split(""); + fq[nfin].com.n = fq[nfin].com.s.length; + } else if (type === 3) { + fq[nfin].qual.s = line.split(""); + fq[nfin].qual.n = fq[nfin].qual.s.length; + } + } + if (fq[nfin].id.n === 0 || (fq[nfin].id.n !== 0 && fq[nfin].id.s[0] !== '@')) { + self.postMessage({ + msgtype: 1, + error: "Input file is not FASTQ!" + }); + return 2; + } + } + if ((eofs[0] === true && eofs[1] === false) || (eofs[0] === false && eofs[1] === true)) { + self.postMessage({ + msgtype: 1, + error: "# of rows in mate file doesn't match primary file!" + }); + return 2; + } else if (eofs[0] === true && eofs[1] === true) { + return 1; + } else { + return 0; + } + }; + while (true) { + nrec++; + rtn = read_fq(); + if (rtn === 1) { + break; + } else if (rtn === 2) { + return; + } + rc = revcomp(fq[1]); + maxo = min(fq[0].seq.n, rc.seq.n); + bestscore = 2147483647; + besto = -1; + for (i = _j = mino; _j <= maxo; i = _j += 1) { + mind = Math.floor((pctdiff * i) / 100); + d = hd(fq[0].seq.s, fq[0].seq.n - i, rc.seq.s, i); + if (d <= mind) { + score = Math.floor((1000 * (d * d + 1)) / i); + if (score < bestscore) { + bestscore = score; + besto = i; + } + } + } + hasex = 0; + olen = besto - hasex; + if (besto > 0) { + joincnt++; + tlen += olen; + tlensq += Math.pow(olen, 2); + for (i = _k = 0; _k < besto; i = _k += 1) { + li = fq[0].seq.n - besto + i; + ri = i; + if (fq[0].seq.s[li] === rc.seq.s[ri]) { + fq[0].qual.s[li] = String.fromCharCode(max(fq[0].qual.s[li].charCodeAt(0), rc.qual.s[ri].charCodeAt(0))); + } else { + if (fq[0].qual.s[li].charCodeAt(0) > rc.qual.s[ri].charCodeAt(0)) { + fq[0].qual.s[li] = String.fromCharCode(33 + min(fq[0].qual.s[li].charCodeAt(0), max(fq[0].qual.s[li].charCodeAt(0) - rc.qual.s[ri].charCodeAt(0), 3))); + } else { + fq[0].seq.s[li] = rc.seq.s[ri]; + fq[0].qual.s[li] = String.fromCharCode(33 + min(rc.qual.s[ri].charCodeAt(0), max(rc.qual.s[ri].charCodeAt(0) - fq[0].qual.s[li].charCodeAt(0), 3))); + } + } + } + joins.push(fq[0].seq.s.join("") + rc.seq.s.slice(besto).join("") + "\n"); + } + if (__modulo(nrec, steprec) === 0) { + if (prevfpos !== readers[0].fpos) { + pgcallback(readers[0].fpos * 100 / files[0].size); + chunkcallback(joins); + joins = []; + prevfpos = readers[0].fpos; + } + } + } + chunkcallback(joins); + pgcallback(100); +}; diff --git a/core/jbfilereader b/core/jbfilereader new file mode 160000 index 0000000..973b960 --- /dev/null +++ b/core/jbfilereader @@ -0,0 +1 @@ +Subproject commit 973b960048f6a539a0fe8422c2444fc67f139b70 diff --git a/core/jbfilereader.coffee b/core/jbfilereader.coffee new file mode 100644 index 0000000..8b72170 --- /dev/null +++ b/core/jbfilereader.coffee @@ -0,0 +1,207 @@ +### +jbfilereader.coffee + +Copyright (c) 2015 Jeongbin Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +### + +class _inflater + constructor: -> + window_bits = 15 + enable_windows_gzip = 32 + @inflater_pako = new pako.Inflate({to: 'string', chunkSize: 16384, windowBits: window_bits|enable_windows_gzip}) + @inflating_buffer = '' + that = this + @inflater_pako.onData = (chunk) -> + that.inflating_buffer += chunk + return + return + + decompress: (chunk, islastchunk) -> + @inflating_buffer = '' + @inflater_pako.push(chunk, islastchunk) + @ended = @inflater_pako.ended + @strm = @inflater_pako.strm + return @inflating_buffer + +class jbfilereadersync + constructor: (@file, @gzipped) -> + @buffer = '' + @filesize = @file.size + @chunksize = 1024 * 512 + @reader = new FileReaderSync() + + if @gzipped + @inflater = new _inflater() + + @islastchunk = false + + @fpos = 0 + @endpos = 0 + + @eof = false + + return + + _getchunk: -> + if @fpos + @chunksize >= @filesize + @endpos = @filesize + @islastchunk = true + else + @endpos = @fpos + @chunksize + blob = @file.slice(@fpos, @endpos) + + @fpos += @endpos - @fpos + if @gzipped + raw_array = new Uint8Array(@reader.readAsArrayBuffer(blob)) + s = @inflater.decompress(raw_array, @islastchunk) + if s + if @inflater.ended and (@inflater.strm.avail_in or !@islastchunk) + # Non-standard gzip. See http://www.gzip.org/#faq8 + remaining_bytes = @inflater.strm.avail_in + rel_pos = 0 + while raw_array[raw_array.byteLength-remaining_bytes+rel_pos] == 0 + rel_pos++ + @fpos -= remaining_bytes-rel_pos + @inflater = new _inflater() # Renew Pako + else + throw 'Something wrong with the gzipped file!' + else + s = @reader.readAsText(blob) + return s + + readline: () -> + if @eof + return "" + + lfpos = @buffer.indexOf("\n") + while lfpos == -1 + if @fpos >= @filesize + result = @buffer + @buffer = "" + @fpos = @filesize + @eof = true + return result + @buffer += @_getchunk() + lfpos = @buffer.indexOf("\n") + + if @buffer[lfpos-1] == "\r" + result = @buffer[...lfpos-1] + else + result = @buffer[...lfpos] + @buffer = @buffer[lfpos+1...] + return result + +class jbfilereader + constructor: (@file, @gzipped) -> + @buffer = '' + @filesize = @file.size + @chunksize = 1024 * 512 + @reader = new FileReader() + + if @gzipped + @inflater = new _inflater() + + @islastchunk = false + + @fpos = 0 + @endpos = 0 + + @eof = false + + return + + _readblob: (blob) -> + that = this + readpromise = new Promise( (resolve, reject) -> + that.reader.onload = (e) -> + resolve(e.target.result) + that.reader.onerror = -> + reject() + return + ) + if @gzipped + @reader.readAsArrayBuffer(blob) + else + @reader.readAsText(blob) + return readpromise + + _getchunk: -> + if @fpos + @chunksize >= @filesize + @endpos = @filesize + @islastchunk = true + else + @endpos = @fpos + @chunksize + blob = @file.slice(@fpos, @endpos) + + that = this + chunkpromise = new Promise( (resolve, reject) -> + readpromise = that._readblob(blob) + readpromise.then( (s) -> + that.fpos += that.endpos - that.fpos + if that.gzipped + raw_array = new Uint8Array(s) + s = that.inflater.decompress(raw_array, that.islastchunk) + if s + if that.inflater.ended and (that.inflater.strm.avail_in or !that.islastchunk) + # Non-standard gzip. See http://www.gzip.org/#faq8 + remaining_bytes = that.inflater.strm.avail_in + rel_pos = 0 + while raw_array[raw_array.byteLength-remaining_bytes+rel_pos] == 0 + rel_pos++ + that.fpos -= remaining_bytes-rel_pos + that.inflater = new _inflater() # Renew Pako + else + alert('Something wrong with the gzipped file!') + reject() + that.buffer += s + resolve() + return + ).catch( (s) -> + alert('Something wrong while reading file!') + reject() + return + ) + ) + return chunkpromise + + readline: (callback) -> + if @eof + callback("") + + lfpos = @buffer.indexOf("\n") + if lfpos == -1 + if @fpos >= @filesize + result = @buffer + @buffer = "" + @eof = true + callback(result) + else + that = this + datapromise = @_getchunk() + datapromise.then( -> that.readline(callback) ) + else + if @buffer[lfpos] == "\r" + result = @buffer[...lfpos-1] + else + result = @buffer[...lfpos] + @buffer = @buffer[lfpos+1...] + callback(result) + return diff --git a/core/jbfilereader.js b/core/jbfilereader.js new file mode 100644 index 0000000..b4fe680 --- /dev/null +++ b/core/jbfilereader.js @@ -0,0 +1,251 @@ +// Generated by CoffeeScript 1.8.0 + +/* +jbfilereader.coffee + +Copyright (c) 2015 Jeongbin Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + */ +var jbfilereader, jbfilereadersync, _inflater; + +_inflater = (function() { + function _inflater() { + var enable_windows_gzip, that, window_bits; + window_bits = 15; + enable_windows_gzip = 32; + this.inflater_pako = new pako.Inflate({ + to: 'string', + chunkSize: 16384, + windowBits: window_bits | enable_windows_gzip + }); + this.inflating_buffer = ''; + that = this; + this.inflater_pako.onData = function(chunk) { + that.inflating_buffer += chunk; + }; + return; + } + + _inflater.prototype.decompress = function(chunk, islastchunk) { + this.inflating_buffer = ''; + this.inflater_pako.push(chunk, islastchunk); + this.ended = this.inflater_pako.ended; + this.strm = this.inflater_pako.strm; + return this.inflating_buffer; + }; + + return _inflater; + +})(); + +jbfilereadersync = (function() { + function jbfilereadersync(file, gzipped) { + this.file = file; + this.gzipped = gzipped; + this.buffer = ''; + this.filesize = this.file.size; + this.chunksize = 1024 * 512; + this.reader = new FileReaderSync(); + if (this.gzipped) { + this.inflater = new _inflater(); + } + this.islastchunk = false; + this.fpos = 0; + this.endpos = 0; + this.eof = false; + return; + } + + jbfilereadersync.prototype._getchunk = function() { + var blob, raw_array, rel_pos, remaining_bytes, s; + if (this.fpos + this.chunksize >= this.filesize) { + this.endpos = this.filesize; + this.islastchunk = true; + } else { + this.endpos = this.fpos + this.chunksize; + } + blob = this.file.slice(this.fpos, this.endpos); + this.fpos += this.endpos - this.fpos; + if (this.gzipped) { + raw_array = new Uint8Array(this.reader.readAsArrayBuffer(blob)); + s = this.inflater.decompress(raw_array, this.islastchunk); + if (s) { + if (this.inflater.ended && (this.inflater.strm.avail_in || !this.islastchunk)) { + remaining_bytes = this.inflater.strm.avail_in; + rel_pos = 0; + while (raw_array[raw_array.byteLength - remaining_bytes + rel_pos] === 0) { + rel_pos++; + } + this.fpos -= remaining_bytes - rel_pos; + this.inflater = new _inflater(); + } + } else { + throw 'Something wrong with the gzipped file!'; + } + } else { + s = this.reader.readAsText(blob); + } + return s; + }; + + jbfilereadersync.prototype.readline = function() { + var lfpos, result; + if (this.eof) { + return ""; + } + lfpos = this.buffer.indexOf("\n"); + while (lfpos === -1) { + if (this.fpos >= this.filesize) { + result = this.buffer; + this.buffer = ""; + this.fpos = this.filesize; + this.eof = true; + return result; + } + this.buffer += this._getchunk(); + lfpos = this.buffer.indexOf("\n"); + } + if (this.buffer[lfpos - 1] === "\r") { + result = this.buffer.slice(0, lfpos - 1); + } else { + result = this.buffer.slice(0, lfpos); + } + this.buffer = this.buffer.slice(lfpos + 1); + return result; + }; + + return jbfilereadersync; + +})(); + +jbfilereader = (function() { + function jbfilereader(file, gzipped) { + this.file = file; + this.gzipped = gzipped; + this.buffer = ''; + this.filesize = this.file.size; + this.chunksize = 1024 * 512; + this.reader = new FileReader(); + if (this.gzipped) { + this.inflater = new _inflater(); + } + this.islastchunk = false; + this.fpos = 0; + this.endpos = 0; + this.eof = false; + return; + } + + jbfilereader.prototype._readblob = function(blob) { + var readpromise, that; + that = this; + readpromise = new Promise(function(resolve, reject) { + that.reader.onload = function(e) { + return resolve(e.target.result); + }; + that.reader.onerror = function() { + return reject(); + }; + }); + if (this.gzipped) { + this.reader.readAsArrayBuffer(blob); + } else { + this.reader.readAsText(blob); + } + return readpromise; + }; + + jbfilereader.prototype._getchunk = function() { + var blob, chunkpromise, that; + if (this.fpos + this.chunksize >= this.filesize) { + this.endpos = this.filesize; + this.islastchunk = true; + } else { + this.endpos = this.fpos + this.chunksize; + } + blob = this.file.slice(this.fpos, this.endpos); + that = this; + chunkpromise = new Promise(function(resolve, reject) { + var readpromise; + readpromise = that._readblob(blob); + return readpromise.then(function(s) { + var raw_array, rel_pos, remaining_bytes; + that.fpos += that.endpos - that.fpos; + if (that.gzipped) { + raw_array = new Uint8Array(s); + s = that.inflater.decompress(raw_array, that.islastchunk); + if (s) { + if (that.inflater.ended && (that.inflater.strm.avail_in || !that.islastchunk)) { + remaining_bytes = that.inflater.strm.avail_in; + rel_pos = 0; + while (raw_array[raw_array.byteLength - remaining_bytes + rel_pos] === 0) { + rel_pos++; + } + that.fpos -= remaining_bytes - rel_pos; + that.inflater = new _inflater(); + } + } else { + alert('Something wrong with the gzipped file!'); + reject(); + } + } + that.buffer += s; + resolve(); + })["catch"](function(s) { + alert('Something wrong while reading file!'); + reject(); + }); + }); + return chunkpromise; + }; + + jbfilereader.prototype.readline = function(callback) { + var datapromise, lfpos, result, that; + if (this.eof) { + callback(""); + } + lfpos = this.buffer.indexOf("\n"); + if (lfpos === -1) { + if (this.fpos >= this.filesize) { + result = this.buffer; + this.buffer = ""; + this.eof = true; + callback(result); + } else { + that = this; + datapromise = this._getchunk(); + datapromise.then(function() { + return that.readline(callback); + }); + } + } else { + if (this.buffer[lfpos] === "\r") { + result = this.buffer.slice(0, lfpos - 1); + } else { + result = this.buffer.slice(0, lfpos); + } + this.buffer = this.buffer.slice(lfpos + 1); + callback(result); + } + }; + + return jbfilereader; + +})(); diff --git a/core/miseq-analyzer.coffee b/core/miseq-analyzer.coffee new file mode 100644 index 0000000..6074a33 --- /dev/null +++ b/core/miseq-analyzer.coffee @@ -0,0 +1,290 @@ +### +cas-analyser.coffee + +Copyright (c) 2015 Jeongbin Park + +GNU General Public License + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +### + +pri_len = 15 # Constant +s_seq = '' +seq_range = '' + +joins_length = 0 +seq_count = {} + +pri_for_patterns = [] +pri_back_patterns = [] + +set_primer_patterns = (_pri_for_patterns, _pri_back_patterns) -> + pri_for_patterns = _pri_for_patterns + pri_back_patterns = _pri_back_patterns + +empty_cache = -> + joins_length = 0 + seq_count = {} + return + +process_chunk = (seqs) -> + for seq in seqs + flag_for = 0 + flag_back = 0 + + for pattern in pri_for_patterns + pattern = new RegExp(pattern) + m = pattern.exec(seq) + if m + start_pos = m.index + flag_for = 1 + + for pattern in pri_back_patterns + pattern = new RegExp(pattern) + m = pattern.exec(seq) + if m + end_pos = m.index + flag_back = 1 + + if flag_for and flag_back + cut_seq = seq[start_pos...(end_pos+pri_len)] + if cut_seq of seq_count + seq_count[cut_seq] += 1 + else + seq_count[cut_seq] = 1 + joins_length += 1 + return + +parse_file = (file, pgcallback, chunkcallback) -> + seq_list = [] + bufsize = 10000 + gzipped = 0 + if file.name.split('.').pop() == 'gz' + gzipped = 1 + f = new jbfilereadersync(file, gzipped) + + linecnt = 0 + line = f.readline() + while line.length > 0 + if linecnt %% 4 == 1 + seq_list.push(line) + if seq_list.length == bufsize + chunkcallback(seq_list) + seq_list = [] + if linecnt %% 1000 == 0 + pgcallback(f.fpos*100/f.filesize) + line = f.readline() + linecnt += 1 + if seq_list.length > 0 + chunkcallback(seq_list) + pgcallback(f.fpos*100/f.filesize) + return + +revcompstr = (s) -> + l = s.split('').reverse() + for i in [0...l.length] by 1 + if l[i] == 'A' + l[i] = 'T' + else if l[i] == 'T' + l[i] = 'A' + else if l[i] == 'G' + l[i] = 'C' + else if l[i] == 'C' + l[i] = 'G' + else if l[i] == 'a' + l[i] = 't' + else if l[i] == 't' + l[i] = 'a' + else if l[i] == 'g' + l[i] = 'c' + else if l[i] == 'c' + l[i] = 'g' + return l.join('') + +run_cas_analyser = (seq_range, seq_hdr, filt_n, filt_r, pgcallback)-> + tot_results = [] + mut_results = [] + count_seqs = [] + totlr_count = 0 + tot_count = 0 + + length_range = seq_range.length + + n = Object.keys(seq_count).length//20 + i = 0 + for seq of seq_count + if !seq_count.hasOwnProperty(seq) + continue + item_cnt = seq_count[seq] + totlr_count += item_cnt + if item_cnt > filt_n + count_seqs.push( {"seq": seq, "count": item_cnt} ) + tot_count += item_cnt + if i % n == 0 + pgcallback(i/Object.keys(seq_count).length*50) + i += 1 + pgcallback(50) + + query_cnt = 0 + + compare = (a, b) -> + if (a.count < b.count) + return 1 + if (a.count > b.count) + return -1 + return 0 + + count_seqs.sort(compare) + + data = {table: [], il: [], dl: [], is: [], ds: [], hdr: 0} + cnt_hdr = 0 + cnt_ins = 0 + cnt_del = 0 + + dscnt = 1 + iscnt = 1 + + re_gap = /-+/g + + for i in [0..seq_range.length] by 1 + data.il.push( [i, 0] ) + data.dl.push( [i, 0] ) + + n = count_seqs.length // 20 + for i in [0...count_seqs.length] by 1 + entry = [] + p = needle(seq_range, count_seqs[i].seq, 10, 0.5, 10, 0.5) + entry[0] = i + 1 + entry[1] = p[0] + entry[2] = p[2] + entry[3] = p[1] + entry[4] = count_seqs[i].seq.length + entry[5] = count_seqs[i].count + if seq_range.length == entry[4] + entry[6] = 0 # WT + else + if filt_r > 0 and s_seq != '' and count_seqs[i].seq.indexOf(s_seq) > 0 + entry[6] = 0 + else + if entry[4] > seq_range.length + entry[6] = 1 # Insertion + cnt_ins += entry[5] + else + entry[6] = 2 # Deletion + cnt_del += entry[5] + if seq_hdr == '' + entry[7] = -2 + else + entry[7] = count_seqs[i].seq.indexOf(seq_hdr) + if entry[7] > 0 + cnt_hdr += entry[5] + + data.table.push(entry) + + cpos = 0 + if entry[6] == 1 + loop + m = re_gap.exec(entry[1]) + if m + gap = m[0] + if data.is.length < gap.length + for j in [0..gap.length - data.is.length] by 1 + data.is.push([iscnt++, 0]) + data.is[gap.length-1][1] += count_seqs[i].count + else + break + for j in [0..entry[1].length - 1] by 1 + if entry[1][j] != '-' + cpos += 1 + if cpos >= seq_range.length + break + if entry[1][j+1] == '-' + data.il[cpos][1] += count_seqs[i].count + else if entry[6] == 2 + loop + m = re_gap.exec(entry[2]) + if m + gap = m[0] + if data.ds.length < gap.length + for j in [0..gap.length - data.ds.length] by 1 + data.ds.push([dscnt++, 0]) + data.ds[gap.length-1][1] += count_seqs[i].count + else + break + for j in [0..entry[1].length] by 1 + if entry[2][j] == '-' + data.dl[cpos][1] += count_seqs[i].count + if entry[1][j] != '-' + cpos += 1 + if i % n == 0 + pgcallback(50+50*i/(count_seqs.length-1)) + + for i in [0..seq_range.length] by 1 + data.il[i][1] /= tot_count + data.dl[i][1] /= tot_count + data.il[i][1] *= 100 + data.dl[i][1] *= 100 + + data.hdr = cnt_hdr + data.joins_length = joins_length + data.totlr_count = totlr_count + data.tot_count = tot_count + data.cnt_ins = cnt_ins + data.cnt_del = cnt_del + + pgcallback(100) + + return data + +parse_joined = -> + reader = new FileReader() + chunksize = 1024*1024*10 + noncomplete_line = '' + fpos = 0 + fstep = 200 + nline = 0 + feof = 0 + + getchunk = -> + if fpos >= joinedfile.size + feof = 1 + readline() + + if fpos + chunksize >= joinedfile.size + endpos = joinedfile.size + else + endpos = fpos + chunksize + + blob = joinedfile.slice(fpos, endpos) + fpos += endpos - fpos + reader.readAsText(blob) + + reader.onload = -> + chunk_lines = reader.result.replace(/\r\n|\n\r|\r/, '\n').split('\n') + chunk_lines[0] = noncomplete_line + chunk_lines[0] + noncomplete_line = chunk_lines[chunk_lines.length-1] + chunk_lines = chunk_lines[...chunk_lines.length-1] + readline() + + readline = -> + if nline >= chunk_lines.length + if feof + return '' + else + getchunk() + return + return chunk_lines[nline++] + + line = readline() diff --git a/core/miseq-analyzer.js b/core/miseq-analyzer.js new file mode 100644 index 0000000..caf0f00 --- /dev/null +++ b/core/miseq-analyzer.js @@ -0,0 +1,349 @@ +// Generated by CoffeeScript 1.8.0 + +/* +cas-analyser.coffee + +Copyright (c) 2015 Jeongbin Park + +GNU General Public License + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + */ +var empty_cache, joins_length, parse_file, parse_joined, pri_back_patterns, pri_for_patterns, pri_len, process_chunk, revcompstr, run_cas_analyser, s_seq, seq_count, seq_range, set_primer_patterns, + __modulo = function(a, b) { return (+a % (b = +b) + b) % b; }; + +pri_len = 15; + +s_seq = ''; + +seq_range = ''; + +joins_length = 0; + +seq_count = {}; + +pri_for_patterns = []; + +pri_back_patterns = []; + +set_primer_patterns = function(_pri_for_patterns, _pri_back_patterns) { + pri_for_patterns = _pri_for_patterns; + return pri_back_patterns = _pri_back_patterns; +}; + +empty_cache = function() { + joins_length = 0; + seq_count = {}; +}; + +process_chunk = function(seqs) { + var cut_seq, end_pos, flag_back, flag_for, m, pattern, seq, start_pos, _i, _j, _k, _len, _len1, _len2; + for (_i = 0, _len = seqs.length; _i < _len; _i++) { + seq = seqs[_i]; + flag_for = 0; + flag_back = 0; + for (_j = 0, _len1 = pri_for_patterns.length; _j < _len1; _j++) { + pattern = pri_for_patterns[_j]; + pattern = new RegExp(pattern); + m = pattern.exec(seq); + if (m) { + start_pos = m.index; + flag_for = 1; + } + } + for (_k = 0, _len2 = pri_back_patterns.length; _k < _len2; _k++) { + pattern = pri_back_patterns[_k]; + pattern = new RegExp(pattern); + m = pattern.exec(seq); + if (m) { + end_pos = m.index; + flag_back = 1; + } + } + if (flag_for && flag_back) { + cut_seq = seq.slice(start_pos, end_pos + pri_len); + if (cut_seq in seq_count) { + seq_count[cut_seq] += 1; + } else { + seq_count[cut_seq] = 1; + } + } + joins_length += 1; + } +}; + +parse_file = function(file, pgcallback, chunkcallback) { + var bufsize, f, gzipped, line, linecnt, seq_list; + seq_list = []; + bufsize = 10000; + gzipped = 0; + if (file.name.split('.').pop() === 'gz') { + gzipped = 1; + } + f = new jbfilereadersync(file, gzipped); + linecnt = 0; + line = f.readline(); + while (line.length > 0) { + if (__modulo(linecnt, 4) === 1) { + seq_list.push(line); + if (seq_list.length === bufsize) { + chunkcallback(seq_list); + seq_list = []; + } + } + if (__modulo(linecnt, 1000) === 0) { + pgcallback(f.fpos * 100 / f.filesize); + } + line = f.readline(); + linecnt += 1; + } + if (seq_list.length > 0) { + chunkcallback(seq_list); + pgcallback(f.fpos * 100 / f.filesize); + } +}; + +revcompstr = function(s) { + var i, l, _i, _ref; + l = s.split('').reverse(); + for (i = _i = 0, _ref = l.length; _i < _ref; i = _i += 1) { + if (l[i] === 'A') { + l[i] = 'T'; + } else if (l[i] === 'T') { + l[i] = 'A'; + } else if (l[i] === 'G') { + l[i] = 'C'; + } else if (l[i] === 'C') { + l[i] = 'G'; + } else if (l[i] === 'a') { + l[i] = 't'; + } else if (l[i] === 't') { + l[i] = 'a'; + } else if (l[i] === 'g') { + l[i] = 'c'; + } else if (l[i] === 'c') { + l[i] = 'g'; + } + } + return l.join(''); +}; + +run_cas_analyser = function(seq_range, seq_hdr, filt_n, filt_r, pgcallback) { + var cnt_del, cnt_hdr, cnt_ins, compare, count_seqs, cpos, data, dscnt, entry, gap, i, iscnt, item_cnt, j, length_range, m, mut_results, n, p, query_cnt, re_gap, seq, tot_count, tot_results, totlr_count, _i, _j, _k, _l, _m, _n, _o, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6; + tot_results = []; + mut_results = []; + count_seqs = []; + totlr_count = 0; + tot_count = 0; + length_range = seq_range.length; + n = Math.floor(Object.keys(seq_count).length / 20); + i = 0; + for (seq in seq_count) { + if (!seq_count.hasOwnProperty(seq)) { + continue; + } + item_cnt = seq_count[seq]; + totlr_count += item_cnt; + if (item_cnt > filt_n) { + count_seqs.push({ + "seq": seq, + "count": item_cnt + }); + tot_count += item_cnt; + } + if (i % n === 0) { + pgcallback(i / Object.keys(seq_count).length * 50); + } + i += 1; + } + pgcallback(50); + query_cnt = 0; + compare = function(a, b) { + if (a.count < b.count) { + return 1; + } + if (a.count > b.count) { + return -1; + } + return 0; + }; + count_seqs.sort(compare); + data = { + table: [], + il: [], + dl: [], + is: [], + ds: [], + hdr: 0 + }; + cnt_hdr = 0; + cnt_ins = 0; + cnt_del = 0; + dscnt = 1; + iscnt = 1; + re_gap = /-+/g; + for (i = _i = 0, _ref = seq_range.length; _i <= _ref; i = _i += 1) { + data.il.push([i, 0]); + data.dl.push([i, 0]); + } + n = Math.floor(count_seqs.length / 20); + for (i = _j = 0, _ref1 = count_seqs.length; _j < _ref1; i = _j += 1) { + entry = []; + p = needle(seq_range, count_seqs[i].seq, 10, 0.5, 10, 0.5); + entry[0] = i + 1; + entry[1] = p[0]; + entry[2] = p[2]; + entry[3] = p[1]; + entry[4] = count_seqs[i].seq.length; + entry[5] = count_seqs[i].count; + if (seq_range.length === entry[4]) { + entry[6] = 0; + } else { + if (filt_r > 0 && s_seq !== '' && count_seqs[i].seq.indexOf(s_seq) > 0) { + entry[6] = 0; + } else { + if (entry[4] > seq_range.length) { + entry[6] = 1; + cnt_ins += entry[5]; + } else { + entry[6] = 2; + cnt_del += entry[5]; + } + } + } + if (seq_hdr === '') { + entry[7] = -2; + } else { + entry[7] = count_seqs[i].seq.indexOf(seq_hdr); + if (entry[7] > 0) { + cnt_hdr += entry[5]; + } + } + data.table.push(entry); + cpos = 0; + if (entry[6] === 1) { + while (true) { + m = re_gap.exec(entry[1]); + if (m) { + gap = m[0]; + if (data.is.length < gap.length) { + for (j = _k = 0, _ref2 = gap.length - data.is.length; _k <= _ref2; j = _k += 1) { + data.is.push([iscnt++, 0]); + } + } + data.is[gap.length - 1][1] += count_seqs[i].count; + } else { + break; + } + } + for (j = _l = 0, _ref3 = entry[1].length - 1; _l <= _ref3; j = _l += 1) { + if (entry[1][j] !== '-') { + cpos += 1; + if (cpos >= seq_range.length) { + break; + } + if (entry[1][j + 1] === '-') { + data.il[cpos][1] += count_seqs[i].count; + } + } + } + } else if (entry[6] === 2) { + while (true) { + m = re_gap.exec(entry[2]); + if (m) { + gap = m[0]; + if (data.ds.length < gap.length) { + for (j = _m = 0, _ref4 = gap.length - data.ds.length; _m <= _ref4; j = _m += 1) { + data.ds.push([dscnt++, 0]); + } + } + data.ds[gap.length - 1][1] += count_seqs[i].count; + } else { + break; + } + } + for (j = _n = 0, _ref5 = entry[1].length; _n <= _ref5; j = _n += 1) { + if (entry[2][j] === '-') { + data.dl[cpos][1] += count_seqs[i].count; + } + if (entry[1][j] !== '-') { + cpos += 1; + } + } + } + if (i % n === 0) { + pgcallback(50 + 50 * i / (count_seqs.length - 1)); + } + } + for (i = _o = 0, _ref6 = seq_range.length; _o <= _ref6; i = _o += 1) { + data.il[i][1] /= tot_count; + data.dl[i][1] /= tot_count; + data.il[i][1] *= 100; + data.dl[i][1] *= 100; + } + data.hdr = cnt_hdr; + data.joins_length = joins_length; + data.totlr_count = totlr_count; + data.tot_count = tot_count; + data.cnt_ins = cnt_ins; + data.cnt_del = cnt_del; + pgcallback(100); + return data; +}; + +parse_joined = function() { + var chunksize, feof, fpos, fstep, getchunk, line, nline, noncomplete_line, reader, readline; + reader = new FileReader(); + chunksize = 1024 * 1024 * 10; + noncomplete_line = ''; + fpos = 0; + fstep = 200; + nline = 0; + feof = 0; + getchunk = function() { + var blob, endpos; + if (fpos >= joinedfile.size) { + feof = 1; + readline(); + } + if (fpos + chunksize >= joinedfile.size) { + endpos = joinedfile.size; + } else { + endpos = fpos + chunksize; + } + blob = joinedfile.slice(fpos, endpos); + fpos += endpos - fpos; + return reader.readAsText(blob); + }; + reader.onload = function() { + var chunk_lines; + chunk_lines = reader.result.replace(/\r\n|\n\r|\r/, '\n').split('\n'); + chunk_lines[0] = noncomplete_line + chunk_lines[0]; + noncomplete_line = chunk_lines[chunk_lines.length - 1]; + chunk_lines = chunk_lines.slice(0, chunk_lines.length - 1); + return readline(); + }; + readline = function() { + if (nline >= chunk_lines.length) { + if (feof) { + return ''; + } else { + getchunk(); + return; + } + } + return chunk_lines[nline++]; + }; + return line = readline(); +}; diff --git a/core/needle.js b/core/needle.js new file mode 100644 index 0000000..3274869 --- /dev/null +++ b/core/needle.js @@ -0,0 +1,291 @@ +/* + * needle.js + * + * Author: Jeongbin Park (pjb7687 at gmail.com) + * Based on source code of 'needle' in EMBOSS software suite (http://emboss.sourceforge.net/). + * + * GNU General Public License + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + function needle(a, b, gapopen, gapextend, endgapopen, endgapextend) { + function E_FPEQ(a, b, e) { return (((b - e) < a) && (a < (b + e))); } + + var sub = [[5, -4, -4, -4, -4, 1, 1, -4, -4, 1, -4, -1, -1, -1, -2, -4], [-4, 5, -4, -4, -4, 1, -4, 1, 1, -4, -1, -4, -1, -1, -2, 5], [-4, -4, 5, -4, 1, -4, 1, -4, 1, -4, -1, -1, -4, -1, -2, -4], [-4, -4, -4, 5, 1, -4, -4, 1, -4, 1, -1, -1, -1, -4, -2, -4], [-4, -4, 1, 1, -1, -4, -2, -2, -2, -2, -1, -1, -3, -3, -1, -4], [1, 1, -4, -4, -4, -1, -2, -2, -2, -2, -3, -3, -1, -1, -1, 1], [1, -4, 1, -4, -2, -2, -1, -4, -2, -2, -3, -1, -3, -1, -1, -4], [-4, 1, -4, 1, -2, -2, -4, -1, -2, -2, -1, -3, -1, -3, -1, 1], [-4, 1, 1, -4, -2, -2, -2, -2, -1, -4, -1, -3, -3, -1, -1, 1], [1, -4, -4, 1, -2, -2, -2, -2, -4, -1, -3, -1, -1, -3, -1, -4], [-4, -1, -1, -1, -1, -3, -3, -1, -1, -3, -1, -2, -2, -2, -1, -1], [-1, -4, -1, -1, -1, -3, -1, -3, -3, -1, -2, -1, -2, -2, -1, -4], [-1, -1, -4, -1, -3, -1, -3, -1, -3, -1, -2, -2, -1, -2, -1, -1], [-1, -1, -1, -4, -3, -1, -1, -3, -1, -3, -2, -2, -2, -1, -1, -1], [-2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2], [-4, 5, -4, -4, -4, 1, -4, 1, 1, -4, -1, -4, -1, -1, -2, 5]]; // EDNAFULL + var base_to_idx = {'A': 0, 'C': 3, 'B': 10, 'D': 13, 'G': 2, 'H': 12, 'K': 8, 'M': 9, 'N': 14, 'S': 4, 'R': 6, 'U': 15, 'T': 1, 'W': 5, 'V': 11, 'Y': 7}; // for EDNAFULL + var idx_to_base = {0: 'A', 1: 'T', 2: 'G', 3: 'C', 4: 'S', 5: 'W', 6: 'R', 7: 'Y', 8: 'K', 9: 'M', 10: 'B', 11: 'V', 12: 'H', 13: 'D', 14: 'N', 15: 'U'}; // for EDNAFULL + + var ix = [], iy = [], m = []; + var ixp, iyp, mp; + + var compass = []; + + var i, j; + var cursor, cursorp; + + var p = []; q = []; + + for(i=0; i= testeg) + iy[cursor] = testog; + else + iy[cursor] = testeg; + m[cursor] = match - (endgapopen + (ypos - 1) * endgapextend); + ix[cursor] = -endgapopen - ypos * endgapextend - gapopen; + } + ix[cursor] -= endgapopen; + ix[cursor] += gapopen; + + cursor = 0; + + for (xpos=1; xpos= testeg) + ix[cursor] = testog; + else + ix[cursor] = testeg; + + m[cursor] = match - (endgapopen + (xpos - 1) * endgapextend); + iy[cursor] = -endgapopen - xpos * endgapextend - gapopen; + } + iy[cursor] -= endgapopen; + iy[cursor] += gapopen; + + xpos = 1; + while (xpos != lenb) { + ypos = 1; + bconvcode = q[xpos]; + + cursorp = xpos-1; + cursor = xpos++; + + while (ypos < lena) { + match = sub[p[ypos++]][bconvcode]; + cursor += lenb; + + mp = m[cursorp]; + ixp = ix[cursorp]; + iyp = iy[cursorp]; + + if (mp > ixp && mp > iyp) + m[cursor] = mp + match; + else if (ixp > iyp) + m[cursor] = ixp + match; + else + m[cursor] = iyp + match; + + cursorp += 1; + if (xpos == lenb) { + testog = m[cursorp] - endgapopen; + testeg = iy[cursorp] - endgapextend; + } else { + testog = m[cursorp]; + if (testog < ix[cursorp]) + testog = ix[cursorp]; + + testog -= gapopen; + testeg = iy[cursorp] - gapextend; + } + if (testog > testeg) + iy[cursor] = testog; + else + iy[cursor] = testeg; + + cursorp += lenb; + + cursorp -= 1; + if (ypos == lena) { + testog = m[cursorp] - endgapopen; + testeg= ix[cursorp] - endgapextend; + } else { + testog = m[cursorp]; + if (testog < iy[cursorp]) + testog = iy[cursorp]; + testog -= gapopen; + testeg = ix[cursorp] - gapextend; + } + if (testog > testeg) + ix[cursor] = testog; + else + ix[cursor] = testeg; + } + } + + score = -32767; // INT_MIN + start1 = lena - 1; + start2 = lenb - 1; + + cursor = lena * lenb - 1; + if (m[cursor] > ix[cursor] && m[cursor] > iy[cursor]) + score = m[cursor]; + else if (ix[cursor] > iy[cursor]) + score = ix[cursor]; + else + score = iy[cursor]; + + cursorp = 0; + cursor = 1; + + eps = 1.192e-6; + + ypos = start1; + xpos = start2; + + while (xpos>=0 && ypos>=0) { + cursor = ypos*lenb+xpos; + mp = m[cursor]; + + if(cursorp == 1 && E_FPEQ((ypos==0||(ypos==lena-1)?endgapextend:gapextend), (ix[cursor]-ix[cursor+1]), eps)) + { + compass[cursor] = 1; + xpos--; + } + else if(cursorp== 2 && E_FPEQ((xpos==0||(xpos==lenb-1)?endgapextend:gapextend), (iy[cursor]-iy[cursor+lenb]), eps)) + { + compass[cursor] = 2; + ypos--; + } + else if(mp >= ix[cursor] && mp>= iy[cursor]) + { + + if(cursorp == 1 && E_FPEQ(mp,ix[cursor],eps)) + { + compass[cursor] = 1; + xpos--; + } + else if(cursorp == 2 && E_FPEQ(mp,iy[cursor],eps)) + { + compass[cursor] = 2; + ypos--; + } + else + { + compass[cursor] = 0; + ypos--; + xpos--; + } + + } + else if(ix[cursor]>=iy[cursor] && xpos>-1) + { + compass[cursor] = 1; + xpos--; + } + else if(ypos>-1) + { + compass[cursor] = 2; + ypos--; + } + else + { + alert("Needle: Something is seriously wrong in the traceback algorithm"); + return -1; + } + cursorp = compass[cursor]; + } + + for (i=lenb-1; i>start2;) { + aln_b.push(idx_to_base[q[i--]]); + aln_a.push('-'); + aln_r.push(' '); + } + for (j=lena-1; j>start1;) { + aln_a.push(idx_to_base[p[j--]]); + aln_b.push('-'); + aln_r.push(' '); + } + + while (start2 >= 0 && start1 >= 0) + { + cursor = start1 * lenb + start2; + if(!compass[cursor]) /* diagonal */ + { + b1 = p[start1--]; b2 = q[start2--]; + aln_a.push(idx_to_base[b1]); + aln_b.push(idx_to_base[b2]); + if (b1 == b2) + aln_r.push('|'); + else + aln_r.push('.'); + continue; + } + else if(compass[cursor] == 1) /* Left, gap(s) in vertical */ + { + aln_a.push('-'); + aln_b.push(idx_to_base[q[start2--]]); + aln_r.push(' '); + continue; + } + else if(compass[cursor] == 2) /* Down, gap(s) in horizontal */ + { + aln_a.push(idx_to_base[p[start1--]]); + aln_b.push('-'); + aln_r.push(' '); + continue; + } else { + alert("Needle: Walk Error in NW"); + return -1; + } + } + + for (;start2>=0;start2--) + { + aln_b.push(idx_to_base[q[start2]]); + aln_a.push('-'); + aln_r.push(' '); + } + + for (;start1>=0;start1--) + { + aln_a.push(idx_to_base[p[start1]]); + aln_b.push('-'); + aln_r.push(' '); + } + + aln_a = aln_a.reverse().join(""); + aln_b = aln_b.reverse().join(""); + aln_r = aln_r.reverse().join(""); //.replace(/ /gi, " "); + + return [aln_a, aln_r, aln_b]; + } diff --git a/core/pako_inflate.min.js b/core/pako_inflate.min.js new file mode 100644 index 0000000..58662fb --- /dev/null +++ b/core/pako_inflate.min.js @@ -0,0 +1,2 @@ +/* pako 0.2.5 nodeca/pako */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.pako=e()}}(function(){return function e(t,i,n){function a(s,o){if(!i[s]){if(!t[s]){var f="function"==typeof require&&require;if(!o&&f)return f(s,!0);if(r)return r(s,!0);throw new Error("Cannot find module '"+s+"'")}var l=i[s]={exports:{}};t[s][0].call(l.exports,function(e){var i=t[s][1][e];return a(i?i:e)},l,l.exports,e,t,i,n)}return i[s].exports}for(var r="function"==typeof require&&require,s=0;s=0&&t.windowBits<16&&(t.windowBits=-t.windowBits,0===t.windowBits&&(t.windowBits=-15)),!(t.windowBits>=0&&t.windowBits<16)||e&&e.windowBits||(t.windowBits+=32),t.windowBits>15&&t.windowBits<48&&0===(15&t.windowBits)&&(t.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new d,this.strm.avail_out=0;var i=r.inflateInit2(this.strm,t.windowBits);if(i!==f.Z_OK)throw new Error(l[i]);this.header=new h,r.inflateGetHeader(this.strm,this.header)};u.prototype.push=function(e,t){var i,n,a,l,d,h=this.strm,u=this.options.chunkSize;if(this.ended)return!1;n=t===~~t?t:t===!0?f.Z_FINISH:f.Z_NO_FLUSH,h.input="string"==typeof e?o.binstring2buf(e):e,h.next_in=0,h.avail_in=h.input.length;do{if(0===h.avail_out&&(h.output=new s.Buf8(u),h.next_out=0,h.avail_out=u),i=r.inflate(h,f.Z_NO_FLUSH),i!==f.Z_STREAM_END&&i!==f.Z_OK)return this.onEnd(i),this.ended=!0,!1;h.next_out&&(0===h.avail_out||i===f.Z_STREAM_END||0===h.avail_in&&n===f.Z_FINISH)&&("string"===this.options.to?(a=o.utf8border(h.output,h.next_out),l=h.next_out-a,d=o.buf2string(h.output,a),h.next_out=l,h.avail_out=u-l,l&&s.arraySet(h.output,h.output,a,l,0),this.onData(d)):this.onData(s.shrinkBuf(h.output,h.next_out)))}while(h.avail_in>0&&i!==f.Z_STREAM_END);return i===f.Z_STREAM_END&&(n=f.Z_FINISH),n===f.Z_FINISH?(i=r.inflateEnd(this.strm),this.onEnd(i),this.ended=!0,i===f.Z_OK):!0},u.prototype.onData=function(e){this.chunks.push(e)},u.prototype.onEnd=function(e){e===f.Z_OK&&(this.result="string"===this.options.to?this.chunks.join(""):s.flattenChunks(this.chunks)),this.chunks=[],this.err=e,this.msg=this.strm.msg},i.Inflate=u,i.inflate=n,i.inflateRaw=a,i.ungzip=n},{"./utils/common":2,"./utils/strings":3,"./zlib/constants":5,"./zlib/gzheader":7,"./zlib/inflate.js":9,"./zlib/messages":11,"./zlib/zstream":12}],2:[function(e,t,i){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;i.assign=function(e){for(var t=Array.prototype.slice.call(arguments,1);t.length;){var i=t.shift();if(i){if("object"!=typeof i)throw new TypeError(i+"must be non-object");for(var n in i)i.hasOwnProperty(n)&&(e[n]=i[n])}}return e},i.shrinkBuf=function(e,t){return e.length===t?e:e.subarray?e.subarray(0,t):(e.length=t,e)};var a={arraySet:function(e,t,i,n,a){if(t.subarray&&e.subarray)return void e.set(t.subarray(i,i+n),a);for(var r=0;n>r;r++)e[a+r]=t[i+r]},flattenChunks:function(e){var t,i,n,a,r,s;for(n=0,t=0,i=e.length;i>t;t++)n+=e[t].length;for(s=new Uint8Array(n),a=0,t=0,i=e.length;i>t;t++)r=e[t],s.set(r,a),a+=r.length;return s}},r={arraySet:function(e,t,i,n,a){for(var r=0;n>r;r++)e[a+r]=t[i+r]},flattenChunks:function(e){return[].concat.apply([],e)}};i.setTyped=function(e){e?(i.Buf8=Uint8Array,i.Buf16=Uint16Array,i.Buf32=Int32Array,i.assign(i,a)):(i.Buf8=Array,i.Buf16=Array,i.Buf32=Array,i.assign(i,r))},i.setTyped(n)},{}],3:[function(e,t,i){"use strict";function n(e,t){if(65537>t&&(e.subarray&&s||!e.subarray&&r))return String.fromCharCode.apply(null,a.shrinkBuf(e,t));for(var i="",n=0;t>n;n++)i+=String.fromCharCode(e[n]);return i}var a=e("./common"),r=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(o){r=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(o){s=!1}for(var f=new a.Buf8(256),l=0;256>l;l++)f[l]=l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;f[254]=f[254]=1,i.string2buf=function(e){var t,i,n,r,s,o=e.length,f=0;for(r=0;o>r;r++)i=e.charCodeAt(r),55296===(64512&i)&&o>r+1&&(n=e.charCodeAt(r+1),56320===(64512&n)&&(i=65536+(i-55296<<10)+(n-56320),r++)),f+=128>i?1:2048>i?2:65536>i?3:4;for(t=new a.Buf8(f),s=0,r=0;f>s;r++)i=e.charCodeAt(r),55296===(64512&i)&&o>r+1&&(n=e.charCodeAt(r+1),56320===(64512&n)&&(i=65536+(i-55296<<10)+(n-56320),r++)),128>i?t[s++]=i:2048>i?(t[s++]=192|i>>>6,t[s++]=128|63&i):65536>i?(t[s++]=224|i>>>12,t[s++]=128|i>>>6&63,t[s++]=128|63&i):(t[s++]=240|i>>>18,t[s++]=128|i>>>12&63,t[s++]=128|i>>>6&63,t[s++]=128|63&i);return t},i.buf2binstring=function(e){return n(e,e.length)},i.binstring2buf=function(e){for(var t=new a.Buf8(e.length),i=0,n=t.length;n>i;i++)t[i]=e.charCodeAt(i);return t},i.buf2string=function(e,t){var i,a,r,s,o=t||e.length,l=new Array(2*o);for(a=0,i=0;o>i;)if(r=e[i++],128>r)l[a++]=r;else if(s=f[r],s>4)l[a++]=65533,i+=s-1;else{for(r&=2===s?31:3===s?15:7;s>1&&o>i;)r=r<<6|63&e[i++],s--;s>1?l[a++]=65533:65536>r?l[a++]=r:(r-=65536,l[a++]=55296|r>>10&1023,l[a++]=56320|1023&r)}return n(l,a)},i.utf8border=function(e,t){var i;for(t=t||e.length,t>e.length&&(t=e.length),i=t-1;i>=0&&128===(192&e[i]);)i--;return 0>i?t:0===i?t:i+f[e[i]]>t?i:t}},{"./common":2}],4:[function(e,t){"use strict";function i(e,t,i,n){for(var a=65535&e|0,r=e>>>16&65535|0,s=0;0!==i;){s=i>2e3?2e3:i,i-=s;do a=a+t[n++]|0,r=r+a|0;while(--s);a%=65521,r%=65521}return a|r<<16|0}t.exports=i},{}],5:[function(e,t){t.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],6:[function(e,t){"use strict";function i(){for(var e,t=[],i=0;256>i;i++){e=i;for(var n=0;8>n;n++)e=1&e?3988292384^e>>>1:e>>>1;t[i]=e}return t}function n(e,t,i,n){var r=a,s=n+i;e=-1^e;for(var o=n;s>o;o++)e=e>>>8^r[255&(e^t[o])];return-1^e}var a=i();t.exports=n},{}],7:[function(e,t){"use strict";function i(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}t.exports=i},{}],8:[function(e,t){"use strict";var i=30,n=12;t.exports=function(e,t){var a,r,s,o,f,l,d,h,u,c,b,w,m,k,g,_,v,p,x,y,S,B,E,Z,A;a=e.state,r=e.next_in,Z=e.input,s=r+(e.avail_in-5),o=e.next_out,A=e.output,f=o-(t-e.avail_out),l=o+(e.avail_out-257),d=a.dmax,h=a.wsize,u=a.whave,c=a.wnext,b=a.window,w=a.hold,m=a.bits,k=a.lencode,g=a.distcode,_=(1<m&&(w+=Z[r++]<>>24,w>>>=x,m-=x,x=p>>>16&255,0===x)A[o++]=65535&p;else{if(!(16&x)){if(0===(64&x)){p=k[(65535&p)+(w&(1<m&&(w+=Z[r++]<>>=x,m-=x),15>m&&(w+=Z[r++]<>>24,w>>>=x,m-=x,x=p>>>16&255,!(16&x)){if(0===(64&x)){p=g[(65535&p)+(w&(1<m&&(w+=Z[r++]<m&&(w+=Z[r++]<d){e.msg="invalid distance too far back",a.mode=i;break e}if(w>>>=x,m-=x,x=o-f,S>x){if(x=S-x,x>u&&a.sane){e.msg="invalid distance too far back",a.mode=i;break e}if(B=0,E=b,0===c){if(B+=h-x,y>x){y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}}else if(x>c){if(B+=h+c-x,x-=c,y>x){y-=x;do A[o++]=b[B++];while(--x);if(B=0,y>c){x=c,y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}}}else if(B+=c-x,y>x){y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}for(;y>2;)A[o++]=E[B++],A[o++]=E[B++],A[o++]=E[B++],y-=3;y&&(A[o++]=E[B++],y>1&&(A[o++]=E[B++]))}else{B=o-S;do A[o++]=A[B++],A[o++]=A[B++],A[o++]=A[B++],y-=3;while(y>2);y&&(A[o++]=A[B++],y>1&&(A[o++]=A[B++]))}break}}break}}while(s>r&&l>o);y=m>>3,r-=y,m-=y<<3,w&=(1<r?5+(s-r):5-(r-s),e.avail_out=l>o?257+(l-o):257-(o-l),a.hold=w,a.bits=m}},{}],9:[function(e,t,i){"use strict";function n(e){return(e>>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function a(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new k.Buf16(320),this.work=new k.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function r(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=F,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new k.Buf32(bt),t.distcode=t.distdyn=new k.Buf32(wt),t.sane=1,t.back=-1,A):C}function s(e){var t;return e&&e.state?(t=e.state,t.wsize=0,t.whave=0,t.wnext=0,r(e)):C}function o(e,t){var i,n;return e&&e.state?(n=e.state,0>t?(i=0,t=-t):(i=(t>>4)+1,48>t&&(t&=15)),t&&(8>t||t>15)?C:(null!==n.window&&n.wbits!==t&&(n.window=null),n.wrap=i,n.wbits=t,s(e))):C}function f(e,t){var i,n;return e?(n=new a,e.state=n,n.window=null,i=o(e,t),i!==A&&(e.state=null),i):C}function l(e){return f(e,kt)}function d(e){if(gt){var t;for(w=new k.Buf32(512),m=new k.Buf32(32),t=0;144>t;)e.lens[t++]=8;for(;256>t;)e.lens[t++]=9;for(;280>t;)e.lens[t++]=7;for(;288>t;)e.lens[t++]=8;for(p(y,e.lens,0,288,w,0,e.work,{bits:9}),t=0;32>t;)e.lens[t++]=5;p(S,e.lens,0,32,m,0,e.work,{bits:5}),gt=!1}e.lencode=w,e.lenbits=9,e.distcode=m,e.distbits=5}function h(e,t,i,n){var a,r=e.state;return null===r.window&&(r.wsize=1<=r.wsize?(k.arraySet(r.window,t,i-r.wsize,r.wsize,0),r.wnext=0,r.whave=r.wsize):(a=r.wsize-r.wnext,a>n&&(a=n),k.arraySet(r.window,t,i-n,a,r.wnext),n-=a,n?(k.arraySet(r.window,t,i-n,n,0),r.wnext=n,r.whave=r.wsize):(r.wnext+=a,r.wnext===r.wsize&&(r.wnext=0),r.whavec;){if(0===f)break e;f--,u+=a[s++]<>>8&255,i.check=_(i.check,Zt,2,0),u=0,c=0,i.mode=D;break}if(i.flags=0,i.head&&(i.head.done=!1),!(1&i.wrap)||(((255&u)<<8)+(u>>8))%31){e.msg="incorrect header check",i.mode=ht;break}if((15&u)!==T){e.msg="unknown compression method",i.mode=ht;break}if(u>>>=4,c-=4,xt=(15&u)+8,0===i.wbits)i.wbits=xt;else if(xt>i.wbits){e.msg="invalid window size",i.mode=ht;break}i.dmax=1<c;){if(0===f)break e;f--,u+=a[s++]<>8&1),512&i.flags&&(Zt[0]=255&u,Zt[1]=u>>>8&255,i.check=_(i.check,Zt,2,0)),u=0,c=0,i.mode=U;case U:for(;32>c;){if(0===f)break e;f--,u+=a[s++]<>>8&255,Zt[2]=u>>>16&255,Zt[3]=u>>>24&255,i.check=_(i.check,Zt,4,0)),u=0,c=0,i.mode=L;case L:for(;16>c;){if(0===f)break e;f--,u+=a[s++]<>8),512&i.flags&&(Zt[0]=255&u,Zt[1]=u>>>8&255,i.check=_(i.check,Zt,2,0)),u=0,c=0,i.mode=H;case H:if(1024&i.flags){for(;16>c;){if(0===f)break e;f--,u+=a[s++]<>>8&255,i.check=_(i.check,Zt,2,0)),u=0,c=0}else i.head&&(i.head.extra=null);i.mode=M;case M:if(1024&i.flags&&(m=i.length,m>f&&(m=f),m&&(i.head&&(xt=i.head.extra_len-i.length,i.head.extra||(i.head.extra=new Array(i.head.extra_len)),k.arraySet(i.head.extra,a,s,m,xt)),512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,i.length-=m),i.length))break e;i.length=0,i.mode=K;case K:if(2048&i.flags){if(0===f)break e;m=0;do xt=a[s+m++],i.head&&xt&&i.length<65536&&(i.head.name+=String.fromCharCode(xt));while(xt&&f>m);if(512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,xt)break e}else i.head&&(i.head.name=null);i.length=0,i.mode=j;case j:if(4096&i.flags){if(0===f)break e;m=0;do xt=a[s+m++],i.head&&xt&&i.length<65536&&(i.head.comment+=String.fromCharCode(xt));while(xt&&f>m);if(512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,xt)break e}else i.head&&(i.head.comment=null);i.mode=P;case P:if(512&i.flags){for(;16>c;){if(0===f)break e;f--,u+=a[s++]<>9&1,i.head.done=!0),e.adler=i.check=0,i.mode=G;break;case q:for(;32>c;){if(0===f)break e;f--,u+=a[s++]<>>=7&c,c-=7&c,i.mode=ft;break}for(;3>c;){if(0===f)break e;f--,u+=a[s++]<>>=1,c-=1,3&u){case 0:i.mode=W;break;case 1:if(d(i),i.mode=tt,t===Z){u>>>=2,c-=2;break e}break;case 2:i.mode=V;break;case 3:e.msg="invalid block type",i.mode=ht}u>>>=2,c-=2;break;case W:for(u>>>=7&c,c-=7&c;32>c;){if(0===f)break e;f--,u+=a[s++]<>>16^65535)){e.msg="invalid stored block lengths",i.mode=ht;break}if(i.length=65535&u,u=0,c=0,i.mode=J,t===Z)break e;case J:i.mode=Q;case Q:if(m=i.length){if(m>f&&(m=f),m>l&&(m=l),0===m)break e;k.arraySet(r,a,s,m,o),f-=m,s+=m,l-=m,o+=m,i.length-=m;break}i.mode=G;break;case V:for(;14>c;){if(0===f)break e;f--,u+=a[s++]<>>=5,c-=5,i.ndist=(31&u)+1,u>>>=5,c-=5,i.ncode=(15&u)+4,u>>>=4,c-=4,i.nlen>286||i.ndist>30){e.msg="too many length or distance symbols",i.mode=ht;break}i.have=0,i.mode=$;case $:for(;i.havec;){if(0===f)break e;f--,u+=a[s++]<>>=3,c-=3}for(;i.have<19;)i.lens[At[i.have++]]=0;if(i.lencode=i.lendyn,i.lenbits=7,St={bits:i.lenbits},yt=p(x,i.lens,0,19,i.lencode,0,i.work,St),i.lenbits=St.bits,yt){e.msg="invalid code lengths set",i.mode=ht;break}i.have=0,i.mode=et;case et:for(;i.have>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,u+=a[s++]<gt)u>>>=mt,c-=mt,i.lens[i.have++]=gt;else{if(16===gt){for(Bt=mt+2;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=mt,c-=mt,0===i.have){e.msg="invalid bit length repeat",i.mode=ht;break}xt=i.lens[i.have-1],m=3+(3&u),u>>>=2,c-=2}else if(17===gt){for(Bt=mt+3;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=mt,c-=mt,xt=0,m=3+(7&u),u>>>=3,c-=3}else{for(Bt=mt+7;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=mt,c-=mt,xt=0,m=11+(127&u),u>>>=7,c-=7}if(i.have+m>i.nlen+i.ndist){e.msg="invalid bit length repeat",i.mode=ht;break}for(;m--;)i.lens[i.have++]=xt}}if(i.mode===ht)break;if(0===i.lens[256]){e.msg="invalid code -- missing end-of-block",i.mode=ht;break}if(i.lenbits=9,St={bits:i.lenbits},yt=p(y,i.lens,0,i.nlen,i.lencode,0,i.work,St),i.lenbits=St.bits,yt){e.msg="invalid literal/lengths set",i.mode=ht;break}if(i.distbits=6,i.distcode=i.distdyn,St={bits:i.distbits},yt=p(S,i.lens,i.nlen,i.ndist,i.distcode,0,i.work,St),i.distbits=St.bits,yt){e.msg="invalid distances set",i.mode=ht;break}if(i.mode=tt,t===Z)break e;case tt:i.mode=it;case it:if(f>=6&&l>=258){e.next_out=o,e.avail_out=l,e.next_in=s,e.avail_in=f,i.hold=u,i.bits=c,v(e,w),o=e.next_out,r=e.output,l=e.avail_out,s=e.next_in,a=e.input,f=e.avail_in,u=i.hold,c=i.bits,i.mode===G&&(i.back=-1);break}for(i.back=0;Et=i.lencode[u&(1<>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,u+=a[s++]<>_t)],mt=Et>>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=_t+mt);){if(0===f)break e;f--,u+=a[s++]<>>=_t,c-=_t,i.back+=_t}if(u>>>=mt,c-=mt,i.back+=mt,i.length=gt,0===kt){i.mode=ot;break}if(32&kt){i.back=-1,i.mode=G;break}if(64&kt){e.msg="invalid literal/length code",i.mode=ht;break}i.extra=15&kt,i.mode=nt;case nt:if(i.extra){for(Bt=i.extra;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=i.extra,c-=i.extra,i.back+=i.extra}i.was=i.length,i.mode=at;case at:for(;Et=i.distcode[u&(1<>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,u+=a[s++]<>_t)],mt=Et>>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=_t+mt);){if(0===f)break e;f--,u+=a[s++]<>>=_t,c-=_t,i.back+=_t}if(u>>>=mt,c-=mt,i.back+=mt,64&kt){e.msg="invalid distance code",i.mode=ht;break}i.offset=gt,i.extra=15&kt,i.mode=rt;case rt:if(i.extra){for(Bt=i.extra;Bt>c;){if(0===f)break e;f--,u+=a[s++]<>>=i.extra,c-=i.extra,i.back+=i.extra}if(i.offset>i.dmax){e.msg="invalid distance too far back",i.mode=ht;break}i.mode=st;case st:if(0===l)break e;if(m=w-l,i.offset>m){if(m=i.offset-m,m>i.whave&&i.sane){e.msg="invalid distance too far back",i.mode=ht;break}m>i.wnext?(m-=i.wnext,bt=i.wsize-m):bt=i.wnext-m,m>i.length&&(m=i.length),wt=i.window}else wt=r,bt=o-i.offset,m=i.length;m>l&&(m=l),l-=m,i.length-=m;do r[o++]=wt[bt++];while(--m);0===i.length&&(i.mode=it);break;case ot:if(0===l)break e;r[o++]=i.length,l--,i.mode=it;break;case ft:if(i.wrap){for(;32>c;){if(0===f)break e;f--,u|=a[s++]<c;){if(0===f)break e;f--,u+=a[s++]<=z;z++)M[z]=0;for(R=0;b>R;R++)M[t[c+R]]++;for(I=A,N=n;N>=1&&0===M[N];N--);if(I>N&&(I=N),0===N)return w[m++]=20971520,w[m++]=20971520,g.bits=1,0;for(C=1;N>C&&0===M[C];C++);for(C>I&&(I=C),F=1,z=1;n>=z;z++)if(F<<=1,F-=M[z],0>F)return-1;if(F>0&&(e===s||1!==N))return-1;for(K[1]=0,z=1;n>z;z++)K[z+1]=K[z]+M[z];for(R=0;b>R;R++)0!==t[c+R]&&(k[K[t[c+R]]++]=R);if(e===s?(L=j=k,S=19):e===o?(L=l,H-=257,j=d,P-=257,S=256):(L=h,j=u,S=-1),U=0,R=0,z=C,y=m,O=I,T=0,p=-1,D=1<a||e===f&&D>r)return 1;for(var q=0;;){q++,B=z-T,k[R]S?(E=j[P+k[R]],Z=L[H+k[R]]):(E=96,Z=0),_=1<>T)+v]=B<<24|E<<16|Z|0;while(0!==v);for(_=1<>=1;if(0!==_?(U&=_-1,U+=_):U=0,R++,0===--M[z]){if(z===N)break;z=t[c+k[R]]}if(z>I&&(U&x)!==p){for(0===T&&(T=I),y+=C,O=z-T,F=1<O+T&&(F-=M[O+T],!(0>=F));)O++,F<<=1;if(D+=1<a||e===f&&D>r)return 1;p=U&x,w[p]=I<<24|O<<16|y-m|0}}return 0!==U&&(w[y+U]=z-T<<24|64<<16|0),g.bits=I,0}},{"../utils/common":2}],11:[function(e,t){"use strict";t.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],12:[function(e,t){"use strict";function i(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}t.exports=i},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/interface.coffee b/interface.coffee new file mode 100644 index 0000000..226bd4d --- /dev/null +++ b/interface.coffee @@ -0,0 +1,496 @@ +### +interface.coffee + +Copyright (c) 2015 Jeongbin Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +### + +plots = [] +files = [] +joinedfile = 0 +singleendfile = 0 + +seq_wt = '' +seq_fancy_wt = '' +seq_RGEN = '' +seq_RGEN2 = '' +filt_r = 0 +filt_n = 0 +end_range = 0 +joins_length = 0 +joins = [] + +skip_progress = 0 + +seq_hdr = '' +rgen_type = 0 # 0 for Cas9, 1 for Cpf1, 2 for TALEN/ZFN/dCas9-FokI, 3 for paired Cas9, 4 for paired Cpf1 +cate = -1 +_results = [] + +worker = undefined + +#prevsinglefile = '' +#prevfile1 = '' +#prevfile2 = '' + +update_progress_fastqjoin = (progress) -> + $('#progress_fastqjoin').css('width', progress + '%') + +$('#submit').click -> + if typeof(Worker) != "undefined" + worker = new Worker("/static/cas-analyzer/worker.js") + window.cas_analyzer_worker = worker # Keep reference of worker so that it won't garbage collected + else + alert("Your browser currently does not support features used by Cas-Analyzer. Please consider upgrading.") + seq_wt = new String($("#fullseq").val()).toUpperCase().replace(/\s/g,'') + seq_hdr = new String($("#hdrseq").val()).toUpperCase().replace(/\s/g,'') + + if seq_hdr + n = seq_wt.search(seq_hdr[...10])+10 + lcnt = 10 + while seq_wt[n+lcnt-10] == seq_hdr[lcnt] + lcnt += 1 + + n = seq_wt.search(seq_hdr[-10...])-1 + rcnt = 11 + while seq_wt[n-rcnt+11] == seq_hdr[-rcnt...][0] + rcnt += 1 + + while seq_hdr.length-lcnt-rcnt < 10 + lcnt -= 1 + rcnt -= 1 + + seq_hdr = seq_hdr[lcnt...seq_hdr.length+1-rcnt] + + # rgen_type: 0 for Cas9, 1 for Cpf1, 2 for TALEN/ZFN, 3 for dCas9-FokI, 4 for paired Cas9, 5 for paired Cpf1 + seq_RGEN = new String($("#rgenseq").val()).toUpperCase().replace(/\s/g,'') + if $("#nuctype").val() == 0 and $("#nucleases").val() == 6 + rgen_type = 1 + else if $("#nuctype").val() == 1 + seq_RGEN2 = new String($("#rgenseq-right").val()).toUpperCase().replace(/\s/g,'') + if $("#nucleases").val() == 9 + if $("#pams").val() == 6 + rgen_type = 5 + else + rgen_type = 4 + else if $("#nucleases").val() == 10 + rgen_type = 3 + else + rgen_type = 2 + + filt_n = parseInt($("#nval").val()) + filt_r = parseInt($("#rval").val()) + if $('#chklr').is(":checked") + end_range = seq_wt.length + else + end_range = parseInt($("#lrval").val()) + + if isNaN(end_range) + end_range = 70 + if isNaN(filt_n) + filt_n = 1 + if $('#chkr').is(":checked") + if isNaN(filt_r) + filt_r = 5 + else + filt_r = 0 + + fileopt = parseInt($('#optfile').val()) + if fileopt == 0 + files[0] = document.getElementById("file1").files[0] + files[1] = document.getElementById("file2").files[0] + if !files[0] + alert('Please set file R1!') + return + if !files[1] + alert('Please set file R2!') + return + else if fileopt == 1 + singleendfile = document.getElementById("file3").files[0] + if !singleendfile + alert('Please set single read file!') + return + if !seq_wt + alert('Please input wildtype sequence!') + return + if !seq_RGEN + alert('Please input RGEN sequence!') + return + if end_range <= 12 + alert('R should be at least 12!') + return + if fileopt == 0 + $('.file-loading-results-header').html('File1File2') + $('.joinedfn1').attr('colspan', '3') + $('.joinedfn2').show() + $('.joinedfn1').html(files[0].name) + $('.joinedfn2').html(files[1].name) + else + $('.file-loading-results-header').html('File name') + $('.joinedfn1').attr('colspan', '6') + $('.joinedfn2').hide() + $('.singlefn').html(singleendfile.name) + $('.input-rgenseq').html(seq_RGEN) + $('.input-rval').html(String(filt_r)) + $('.input-nval').html(String(filt_n)) + if $('#chklr').is(':checked') + $('.input-lrval').html('Using both ends') + else + $('.input-lrval').html(String(end_range)) + data = {} + data.msgtype = 0 + data.seq_wt = seq_wt + data.rgen_type = rgen_type + data.seq_RGEN = seq_RGEN + data.seq_RGEN2 = seq_RGEN2 + data.seq_hdr = seq_hdr + data.end_range = end_range + data.filt_n = filt_n + data.filt_r = filt_r + data.files = files + + worker.onmessage = (msg) -> + if msg.data.msgtype == 0 + $('.input-fullseq').html(msg.data.seq_fancy_wt) + location.hash = "!progress" + if fileopt == 0 + $("#upper_progress").text("Fastq-join") + setTimeout( -> + #if prevsinglefile == '' and prevfile1 == (files[0].name+files[0].size) and prevfile2 == (files[1].name+files[1].size) + # worker.postMessage({msgtype: 3}) + #else + # prevfile1 = files[0].name+files[0].size + # prevfile2 = files[1].name+files[1].size + # prevsinglefile = '' + # worker.postMessage({msgtype: 1, files: files}) + #return + worker.postMessage({msgtype: 1, files: files}) + , 0) + else if fileopt == 1 + $("#upper_progress").text("File loading") + setTimeout( -> + #if prevsinglefile == singleendfile.name+singleendfile.size and prevfile1 == '' and prevfile2 == '' + # worker.postMessage({msgtype: 3}) + #else + # prevsinglefile = singleendfile.name+singleendfile.size + # prevfile1 = '' + # prevfile2 = '' + # worker.postMessage({msgtype: 2, file: singleendfile}) + #return + worker.postMessage({msgtype: 2, file: singleendfile}) + , 0) + else if msg.data.msgtype == 1 + alert(msg.data.error) # Error + location.hash = "" + else if msg.data.msgtype == 2 + setTimeout( -> + $('#progress_fastqjoin').css('width', msg.data.progress + '%') + return + , 0) + else if msg.data.msgtype == 3 + setTimeout( -> + $('#progress_analysis').css('width', msg.data.progress + '%') + return + , 0) + else + all_done(msg.data.results) + worker.postMessage(data) + return + +$('#btnselect10').click -> + $('.chkmsas').attr('checked', false) + for i in [0..9] by 1 + $('#chkmsa'+i).attr('checked', true) + return + +$('#chklr').click -> + if $(this).is(":checked") + $('#lrval').attr('disabled', true) + else + $('#lrval').attr('disabled', false) + return + +$('#chkr').click -> + if $(this).is(":checked") + $('#rval').attr('disabled', false) + else + $('#rval').attr('disabled', true) + return + +$('#btnshowall').click( (e) -> + e.preventDefault() + $('.seqfilter').removeClass("active") + $(this).parent().addClass("active") + cate = -1 + list_data() +) + +$('#btnshowws').click( (e) -> + e.preventDefault() + $('.seqfilter').removeClass("active") + $(this).parent().addClass("active") + cate = 0 + list_data() +) + +$('#btnshowins').click( (e) -> + e.preventDefault() + $('.seqfilter').removeClass("active") + $(this).parent().addClass("active") + cate = 1 + list_data() +) + +$('#btnshowdel').click( (e) -> + e.preventDefault() + $('.seqfilter').removeClass("active") + $(this).parent().addClass("active") + cate = 2 + list_data() +) + +$('#showhdr').click( (e) -> + list_data() +) + +list_data = -> + ishdr = $('#showhdr').is(":checked") + view_data = [] + for i in [0..._results.length] by 1 + if (cate == -1 or _results[i][6] == cate) and (!ishdr or (ishdr and _results[i][7] > 0)) + view_data.push(_results[i]) + load_page(0, view_data, 10) + +all_done = (data) -> + joins_count = data.joins_length + totlr_count = data.totlr_count + totn_count = data.tot_count + ins_count = data.cnt_ins + del_count = data.cnt_del + results = data.table + il = data.il + dl = data.dl + isi = data.is + dsi = data.ds + hdr = data.hdr + + $('.result-joined').html(String(joins_count)) + $('.result-totallr').html(String(totlr_count)) + $('.result-totaln').html(String(totn_count)) + $('.result-insertions').html(String(ins_count)) + $('.result-deletions').html(String(del_count)) + $('.result-indelratio').html(String(ins_count+del_count)+" ("+String(((ins_count+del_count)*100.0/totn_count).toFixed(1)) + "%)") + $('.result-hdrratio').html(String(hdr)+" ("+String((hdr*100.0/totn_count).toFixed(1)) + "%)") + rows = '' + if results.length == 0 + rows = 'No entries found.' + else + ins_list = [] + del_list = [] + ws_list = [] + + _results = results + + $('#btndownload').off() + $('#btndownload').on('click', -> + s = '#ID\tWT Sequence\tRGEN Treated Sequence\tLength\tCount\tType\tHDR\n' + for i in [0...results.length] by 1 + entry = results[i] + s += entry[0] + '\t' + entry[1] + '\t' + entry[2] + '\t' + entry[4] + '\t' + entry[5] + '\t' + if entry[6] == 0 + s += 'WT or Sub' + else if entry[6] == 1 + s += 'Ins' + else + s += 'del' + s += '\t' + if entry[7] < -1 + s += 'N/A' + else if entry[7] == -1 + s += 'X' + else + s += 'O' + s += '\n' + saveTextData(s, 'result.txt') + return + ) + + draw_plots = -> + if ($("#placeholder_is").width()) + load_page(0, results, 10) + plots.push( + $.plot("#placeholder_is", [ + { data: isi, color: "#DE000F" } + ], { + series: { + bars: { show: true }, + }, + grid: { + hoverable: true + }, + xaxis: { + #transform: (v) -> return if v == 0 then v else Math.log(v), + axisLabel: "Size", + axisLabelUseCanvas: true, + axisLabelFontFamily: 'Arial', + axisLabelPadding: 10 + }, + yaxis: { + axisLabel: "Count", + axisLabelUseCanvas: true, + axisLabelFontFamily: 'Arial', + axisLabelPadding: 8 + } + }) + ) + plots.push( + $.plot("#placeholder_ds", [ + { data: dsi, color: "#DE000F" } + ], { + series: { + bars: { show: true }, + }, + grid: { + hoverable: true + }, + xaxis: { + #transform: (v) -> return if v == 0 then v else Math.log(v), + axisLabel: "Size", + axisLabelUseCanvas: true, + axisLabelFontFamily: 'Arial', + axisLabelPadding: 10 + }, + yaxis: { + axisLabel: "Count", + axisLabelUseCanvas: true, + axisLabelFontFamily: 'Arial', + axisLabelPadding: 8 + } + }) + ) + plots.push( + $.plot("#placeholder_il", [ + { data: il, color: "#5482FF" } + ], { + series: { + bars: { show: true }, + }, + grid: { + hoverable: true + }, + xaxis: { + axisLabel: "Position", + axisLabelUseCanvas: true, + axisLabelFontFamily: 'Arial', + axisLabelPadding: 10 + }, + yaxis: { + axisLabel: "Ratio (%)", + axisLabelUseCanvas: true, + axisLabelFontFamily: 'Arial', + axisLabelPadding: 8 + } + }) + ) + plots.push( + $.plot("#placeholder_dl", [ + { data: dl, color: "#5482FF" } + ], { + series: { + bars: { show: true }, + }, + grid: { + hoverable: true + }, + xaxis: { + axisLabel: "Position", + axisLabelUseCanvas: true, + axisLabelFontFamily: 'Arial', + axisLabelPadding: 10 + }, + yaxis: { + axisLabel: "Ratio (%)", + axisLabelUseCanvas: true, + axisLabelFontFamily: 'Arial', + axisLabelPadding: 8 + } + }) + ) + $("
").css({ + position: "absolute", + display: "none", + border: "1px solid #fdd", + padding: "2px", + "background-color": "#fee", + opacity: 0.80 + }).appendTo("body") + $(".plotarea").each( -> + $(this).bind("plothover", (evt, pos, item) -> + if (item) + x = item.datapoint[0] + if this.id == "placeholder_ds" or this.id == "placeholder_is" + y = item.datapoint[1] + else + y = item.datapoint[1].toFixed(3) + $("#tooltip_plot").html("(" + x + ", " + y + ")").css({top: item.pageY+5, left: item.pageX+5}).fadeIn(200) + else + $("#tooltip_plot").hide() + return + ) + return + ) + else + setTimeout(draw_plots, 200) + return + setTimeout(draw_plots, 200) + + location.hash = "!result" + skip_progress = 1 + return +clear_plots = -> + for plot in plots + plot.shutdown() + plots = [] +window.onload = -> + location.hash = "!" + return + +window.onhashchange = -> + $('#progress_fastqjoin').css('width', '0') + $('#progress_analysis').css('width', '0') + if location.hash == "#!progress" + if skip_progress + skip_progress = 0 + location.hash = "!" + else + $("#inputform").hide() + $("#progress").show() + else if location.hash == "#!result" + $("#progress").hide() + $("#result").show() + else + worker.terminate() + clear_plots() + $("#progress").hide() + $("#result").hide() + $("#inputform").show() + $('.seqfilter').removeClass("active") + $('#btnshowall').parent().addClass("active") + return diff --git a/worker.js b/worker.js new file mode 100644 index 0000000..6e5569d --- /dev/null +++ b/worker.js @@ -0,0 +1,145 @@ +importScripts('core/pako_inflate.min.js'); +importScripts('core/jbfilereader.js'); +importScripts('core/fastq-join.js'); +importScripts('core/needle.js'); +importScripts('core/miseq-analyzer.js'); + +var rgen_type, seq_RGEN, seq_RGEN2, seq_wt, seq_hdr, end_range, filt_n, filt_r, files; + +onmessage = function(msg) { + if (msg.data.msgtype == 0) { + rgen_type = msg.data.rgen_type; + seq_RGEN = msg.data.seq_RGEN; + seq_RGEN2 = msg.data.seq_RGEN2; + seq_wt = msg.data.seq_wt; + seq_hdr = msg.data.seq_hdr; + end_range = msg.data.end_range; + filt_n = msg.data.filt_n; + filt_r = msg.data.filt_r; + files = msg.data.files; + + if (rgen_type < 2) { + pattern = new RegExp("(" + seq_RGEN + ")|(" + revcompstr(seq_RGEN) + ")"); + m = pattern.exec(seq_wt); + if (m) { + if (rgen_type === 0) { + if (m[1]) { + bp = m.index + seq_RGEN.length - 3; + } else { + bp = m.index + 3; + } + } else if (rgen_type === 1) { + if (m[1]) { + bp = m.index + 21; + } else { + bp = m.index + seq_RGEN.length - 16; + } + } + } else { + self.postMessage({msgtype: 1, error: "Couldn't find RGEN site in WT sequence!"}); + return; + } + } else { + if (rgen_type === 2) { + pattern_1 = new RegExp("(" + seq_RGEN + ")"); + pattern_2 = new RegExp("(" + seq_RGEN2 + ")"); + } else { + pattern_1 = new RegExp("(" + seq_RGEN + ")|(" + revcompstr(seq_RGEN) + ")"); + pattern_2 = new RegExp("(" + seq_RGEN2 + ")|(" + revcompstr(seq_RGEN2) + ")"); + } + m_1 = pattern_1.exec(seq_wt); + m_2 = pattern_2.exec(seq_wt); + if (m_1 && m_2) { + if (m_1.index > m_2.index) { + self.postMessage({msgtype: 1, error: "Position of left site is bigger than that of right site!"}); + return; + } + if (rgen_type < 4) { + bp = Math.round((m_1.index + m_2.index + seq_RGEN2.length) / 2); + } else if (rgen_type === 4) { + if (m_1[1]) { + bp_1 = m.index + seq_RGEN.length - 3; + } else { + bp_1 = m.index + 3; + } + if (m_2[1]) { + bp_2 = m.index + seq_RGEN2.length - 3; + } else { + bp_2 = m.index + 3; + } + bp = Math.round((bp_1 + bp_2) / 2); + } else { + if (m_1[1]) { + bp_1 = m.index + 21; + } else { + bp_1 = m.index + seq_RGEN.length - 16; + } + if (m_2[1]) { + bp_2 = m.index + 21; + } else { + bp_2 = m.index + seq_RGEN2.length - 16; + } + bp = Math.round((bp_1 + bp_2) / 2); + } + } else { + self.postMessage({msgtype: 1, error: "Couldn't find both sites in WT sequence!"}); + return; + } + } + start_pos = bp - end_range; + end_pos = bp + end_range; + if (start_pos < 0) { + start_pos = 0; + } + if (end_pos > seq_wt.length) { + end_pos = seq_wt.length; + } + s_seq = seq_wt.slice(bp - filt_r, bp + filt_r); + seq_range = seq_wt.slice(start_pos, end_pos); + pri_for = seq_range.slice(0, pri_len); + pri_back = seq_range.slice(-pri_len); + pri_for_patterns = []; + pri_back_patterns = []; + for (i = 0; i < pri_len; i++) { + pri_for_patterns.push(pri_for.slice(0, i) + '[AGCT]' + pri_for.slice(i + 1)); + pri_back_patterns.push(pri_back.slice(0, i) + '[AGCT]' + pri_back.slice(i + 1)); + } + min = function(a, b) { + if (a < b) { + return a; + } else { + return b; + } + }; + max = function(a, b) { + if (a > b) { + return a; + } else { + return b; + } + }; + seq_fancy_wt = seq_wt.slice(0, start_pos); + seq_fancy_wt += '' + seq_wt.slice(start_pos, min(start_pos + pri_len, bp - filt_r)) + ''; + seq_fancy_wt += seq_wt.slice(start_pos + pri_len, min(m.index, bp - filt_r)); + seq_fancy_wt += '' + seq_wt.slice(m.index, bp - filt_r) + ''; + seq_fancy_wt += '' + seq_wt.slice(bp - filt_r, bp + filt_r) + ''; + seq_fancy_wt += '' + seq_wt.slice(bp + filt_r, m.index + seq_RGEN.length) + ''; + seq_fancy_wt += seq_wt.slice(max(m.index + seq_RGEN.length, bp + filt_r), end_pos - pri_len); + seq_fancy_wt += '' + seq_wt.slice(max(end_pos - pri_len, bp + filt_r), end_pos) + ''; + seq_fancy_wt += seq_wt.slice(end_pos); + + set_primer_patterns(pri_for_patterns, pri_back_patterns); + + self.postMessage({msgtype: 0, seq_fancy_wt: seq_fancy_wt}); + } else if (msg.data.msgtype == 1 || msg.data.msgtype == 2) { + empty_cache(); + pgcallback1 = function(p) { self.postMessage({msgtype: 2, progress: p}); }; + pgcallback2 = function(p) { self.postMessage({msgtype: 3, progress: p}); }; + if (msg.data.msgtype == 1) + run_fastq_join(msg.data.files, pgcallback1, process_chunk, true); + else + parse_file(msg.data.file, pgcallback1, process_chunk); + data = run_cas_analyser(seq_range, seq_hdr, filt_n, filt_r, pgcallback2); + self.postMessage({msgtype: 4, results: data}); + } +}