sequenceserver 1.0.0.pre.2 → 1.0.0.pre.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sequenceserver might be problematic. Click here for more details.

Files changed (337) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +18 -4
  4. data/bin/sequenceserver +219 -124
  5. data/lib/sequenceserver.rb +156 -153
  6. data/lib/sequenceserver/blast.rb +163 -432
  7. data/lib/sequenceserver/blast/exceptions.rb +27 -0
  8. data/lib/sequenceserver/blast/hit.rb +32 -0
  9. data/lib/sequenceserver/blast/hsp.rb +260 -0
  10. data/lib/sequenceserver/blast/query.rb +28 -0
  11. data/lib/sequenceserver/blast/report.rb +123 -0
  12. data/lib/sequenceserver/config.rb +94 -0
  13. data/lib/sequenceserver/database.rb +89 -49
  14. data/lib/sequenceserver/exceptions.rb +154 -0
  15. data/lib/sequenceserver/links.rb +1 -1
  16. data/lib/sequenceserver/logger.rb +5 -7
  17. data/lib/sequenceserver/sequence.rb +40 -39
  18. data/public/css/bootstrap.min.css +5 -7
  19. data/public/css/custom.css +28 -27
  20. data/public/dist/css/sequenceserver.min.css +1 -0
  21. data/public/dist/css/sequenceserver.min.css.gz +0 -0
  22. data/public/dist/fonts/FontAwesome.otf +0 -0
  23. data/public/dist/fonts/fontawesome-webfont.eot +0 -0
  24. data/public/dist/fonts/fontawesome-webfont.svg +565 -0
  25. data/public/dist/fonts/fontawesome-webfont.ttf +0 -0
  26. data/public/dist/fonts/fontawesome-webfont.woff +0 -0
  27. data/public/dist/fonts/fontawesome-webfont.woff2 +0 -0
  28. data/public/dist/js/sequenceserver.min.js +12 -0
  29. data/public/dist/js/sequenceserver.min.js.gz +0 -0
  30. data/public/dist/js/shims/FlashCanvas/canvas2png.js +1 -0
  31. data/public/dist/js/shims/FlashCanvas/flashcanvas.js +1 -0
  32. data/public/dist/js/shims/FlashCanvas/flashcanvas.swf +0 -0
  33. data/public/dist/js/shims/FlashCanvasPro/canvas2png.js +1 -0
  34. data/public/dist/js/shims/FlashCanvasPro/flash10canvas.swf +0 -0
  35. data/public/dist/js/shims/FlashCanvasPro/flash9canvas.swf +0 -0
  36. data/public/dist/js/shims/FlashCanvasPro/flashcanvas.js +1 -0
  37. data/public/dist/js/shims/canvas-blob.js +1 -0
  38. data/public/dist/js/shims/color-picker.js +2 -0
  39. data/public/dist/js/shims/combos/1.js +6 -0
  40. data/public/dist/js/shims/combos/10.js +2 -0
  41. data/public/dist/js/shims/combos/11.js +2 -0
  42. data/public/dist/js/shims/combos/12.js +6 -0
  43. data/public/dist/js/shims/combos/13.js +1 -0
  44. data/public/dist/js/shims/combos/14.js +1 -0
  45. data/public/dist/js/shims/combos/15.js +2 -0
  46. data/public/dist/js/shims/combos/16.js +7 -0
  47. data/public/dist/js/shims/combos/17.js +2 -0
  48. data/public/dist/js/shims/combos/18.js +3 -0
  49. data/public/dist/js/shims/combos/2.js +7 -0
  50. data/public/dist/js/shims/combos/21.js +2 -0
  51. data/public/dist/js/shims/combos/22.js +1 -0
  52. data/public/dist/js/shims/combos/23.js +6 -0
  53. data/public/dist/js/shims/combos/25.js +2 -0
  54. data/public/dist/js/shims/combos/27.js +1 -0
  55. data/public/dist/js/shims/combos/28.js +1 -0
  56. data/public/dist/js/shims/combos/29.js +1 -0
  57. data/public/dist/js/shims/combos/3.js +1 -0
  58. data/public/dist/js/shims/combos/30.js +2 -0
  59. data/public/dist/js/shims/combos/31.js +1 -0
  60. data/public/dist/js/shims/combos/33.js +1 -0
  61. data/public/dist/js/shims/combos/34.js +1 -0
  62. data/public/dist/js/shims/combos/4.js +1 -0
  63. data/public/dist/js/shims/combos/5.js +2 -0
  64. data/public/dist/js/shims/combos/6.js +2 -0
  65. data/public/dist/js/shims/combos/7.js +7 -0
  66. data/public/dist/js/shims/combos/8.js +7 -0
  67. data/public/dist/js/shims/combos/9.js +2 -0
  68. data/public/dist/js/shims/combos/97.js +1 -0
  69. data/public/dist/js/shims/combos/98.js +1 -0
  70. data/public/dist/js/shims/combos/99.js +1 -0
  71. data/public/dist/js/shims/details.js +1 -0
  72. data/public/dist/js/shims/dom-extend.js +1 -0
  73. data/public/dist/js/shims/es5.js +1 -0
  74. data/public/dist/js/shims/es6.js +1 -0
  75. data/public/dist/js/shims/excanvas.js +1 -0
  76. data/public/dist/js/shims/filereader-xhr.js +1 -0
  77. data/public/dist/js/shims/form-combat.js +1 -0
  78. data/public/dist/js/shims/form-core.js +1 -0
  79. data/public/dist/js/shims/form-datalist-lazy.js +1 -0
  80. data/public/dist/js/shims/form-datalist.js +1 -0
  81. data/public/dist/js/shims/form-fixrangechange.js +1 -0
  82. data/public/dist/js/shims/form-inputmode.js +1 -0
  83. data/public/dist/js/shims/form-message.js +1 -0
  84. data/public/dist/js/shims/form-native-extend.js +1 -0
  85. data/public/dist/js/shims/form-number-date-api.js +1 -0
  86. data/public/dist/js/shims/form-number-date-ui.js +1 -0
  87. data/public/dist/js/shims/form-shim-extend.js +1 -0
  88. data/public/dist/js/shims/form-shim-extend2.js +1 -0
  89. data/public/dist/js/shims/form-validation.js +1 -0
  90. data/public/dist/js/shims/form-validators.js +1 -0
  91. data/public/dist/js/shims/forms-picker.js +1 -0
  92. data/public/dist/js/shims/geolocation.js +1 -0
  93. data/public/dist/js/shims/i18n/formcfg-ar.js +1 -0
  94. data/public/dist/js/shims/i18n/formcfg-ch-CN.js +1 -0
  95. data/public/dist/js/shims/i18n/formcfg-cs.js +1 -0
  96. data/public/dist/js/shims/i18n/formcfg-de.js +1 -0
  97. data/public/dist/js/shims/i18n/formcfg-el.js +1 -0
  98. data/public/dist/js/shims/i18n/formcfg-en.js +1 -0
  99. data/public/dist/js/shims/i18n/formcfg-es.js +1 -0
  100. data/public/dist/js/shims/i18n/formcfg-fa.js +1 -0
  101. data/public/dist/js/shims/i18n/formcfg-fr.js +1 -0
  102. data/public/dist/js/shims/i18n/formcfg-he.js +1 -0
  103. data/public/dist/js/shims/i18n/formcfg-hi.js +1 -0
  104. data/public/dist/js/shims/i18n/formcfg-hu.js +1 -0
  105. data/public/dist/js/shims/i18n/formcfg-it.js +1 -0
  106. data/public/dist/js/shims/i18n/formcfg-ja.js +1 -0
  107. data/public/dist/js/shims/i18n/formcfg-lt.js +1 -0
  108. data/public/dist/js/shims/i18n/formcfg-nl.js +1 -0
  109. data/public/dist/js/shims/i18n/formcfg-pl.js +1 -0
  110. data/public/dist/js/shims/i18n/formcfg-pt-BR.js +1 -0
  111. data/public/dist/js/shims/i18n/formcfg-pt-PT.js +1 -0
  112. data/public/dist/js/shims/i18n/formcfg-pt.js +1 -0
  113. data/public/dist/js/shims/i18n/formcfg-ru.js +1 -0
  114. data/public/dist/js/shims/i18n/formcfg-sv.js +1 -0
  115. data/public/dist/js/shims/i18n/formcfg-zh-CN.js +1 -0
  116. data/public/dist/js/shims/i18n/formcfg-zh-TW.js +1 -0
  117. data/public/dist/js/shims/jme/alternate-media.js +1 -0
  118. data/public/dist/js/shims/jme/base.js +1 -0
  119. data/public/dist/js/shims/jme/controls.css +1 -0
  120. data/public/dist/js/shims/jme/jme.eot +0 -0
  121. data/public/dist/js/shims/jme/jme.svg +36 -0
  122. data/public/dist/js/shims/jme/jme.ttf +0 -0
  123. data/public/dist/js/shims/jme/jme.woff +0 -0
  124. data/public/dist/js/shims/jme/mediacontrols-lazy.js +1 -0
  125. data/public/dist/js/shims/jme/mediacontrols.js +1 -0
  126. data/public/dist/js/shims/jme/playlist.js +1 -0
  127. data/public/dist/js/shims/jpicker/images/AlphaBar.png +0 -0
  128. data/public/dist/js/shims/jpicker/images/Bars.png +0 -0
  129. data/public/dist/js/shims/jpicker/images/Maps.png +0 -0
  130. data/public/dist/js/shims/jpicker/images/NoColor.png +0 -0
  131. data/public/dist/js/shims/jpicker/images/bar-opacity.png +0 -0
  132. data/public/dist/js/shims/jpicker/images/map-opacity.png +0 -0
  133. data/public/dist/js/shims/jpicker/images/mappoint.gif +0 -0
  134. data/public/dist/js/shims/jpicker/images/picker.gif +0 -0
  135. data/public/dist/js/shims/jpicker/images/preview-opacity.png +0 -0
  136. data/public/dist/js/shims/jpicker/images/rangearrows.gif +0 -0
  137. data/public/dist/js/shims/jpicker/jpicker.css +1 -0
  138. data/public/dist/js/shims/matchMedia.js +3 -0
  139. data/public/dist/js/shims/mediacapture-picker.js +1 -0
  140. data/public/dist/js/shims/mediacapture.js +1 -0
  141. data/public/dist/js/shims/mediaelement-core.js +1 -0
  142. data/public/dist/js/shims/mediaelement-debug.js +1 -0
  143. data/public/dist/js/shims/mediaelement-jaris.js +1 -0
  144. data/public/dist/js/shims/mediaelement-native-fix.js +1 -0
  145. data/public/dist/js/shims/mediaelement-yt.js +1 -0
  146. data/public/dist/js/shims/moxie/flash/Moxie.cdn.swf +0 -0
  147. data/public/dist/js/shims/moxie/flash/Moxie.min.swf +0 -0
  148. data/public/dist/js/shims/moxie/js/moxie-html4.js +3 -0
  149. data/public/dist/js/shims/moxie/js/moxie-swf.js +2 -0
  150. data/public/dist/js/shims/picture.js +1 -0
  151. data/public/dist/js/shims/plugins/jquery.ui.position.js +11 -0
  152. data/public/dist/js/shims/range-ui.js +1 -0
  153. data/public/dist/js/shims/sizzle.js +11 -0
  154. data/public/dist/js/shims/sticky.js +1 -0
  155. data/public/dist/js/shims/styles/color-picker.png +0 -0
  156. data/public/dist/js/shims/styles/forms-ext.css +1 -0
  157. data/public/dist/js/shims/styles/forms-picker.css +1 -0
  158. data/public/dist/js/shims/styles/progress.gif +0 -0
  159. data/public/dist/js/shims/styles/progress.png +0 -0
  160. data/public/dist/js/shims/styles/shim-ext.css +1 -0
  161. data/public/dist/js/shims/styles/shim.css +1 -0
  162. data/public/dist/js/shims/styles/transparent.png +0 -0
  163. data/public/dist/js/shims/styles/widget.eot +0 -0
  164. data/public/dist/js/shims/styles/widget.svg +12 -0
  165. data/public/dist/js/shims/styles/widget.ttf +0 -0
  166. data/public/dist/js/shims/styles/widget.woff +0 -0
  167. data/public/dist/js/shims/swf/JarisFLVPlayer.swf +0 -0
  168. data/public/dist/js/shims/swfmini-embed.js +1 -0
  169. data/public/dist/js/shims/swfmini.js +6 -0
  170. data/public/dist/js/shims/track-ui.js +1 -0
  171. data/public/dist/js/shims/track.js +1 -0
  172. data/public/dist/js/shims/url.js +1 -0
  173. data/public/dist/js/shims/usermedia-core.js +1 -0
  174. data/public/dist/js/shims/usermedia-shim.js +1 -0
  175. data/public/dist/js/webshims/shims/FlashCanvas/canvas2png.js +1 -0
  176. data/public/dist/js/webshims/shims/FlashCanvas/flashcanvas.js +1 -0
  177. data/public/dist/js/webshims/shims/FlashCanvas/flashcanvas.swf +0 -0
  178. data/public/dist/js/webshims/shims/FlashCanvasPro/canvas2png.js +1 -0
  179. data/public/dist/js/webshims/shims/FlashCanvasPro/flash10canvas.swf +0 -0
  180. data/public/dist/js/webshims/shims/FlashCanvasPro/flash9canvas.swf +0 -0
  181. data/public/dist/js/webshims/shims/FlashCanvasPro/flashcanvas.js +1 -0
  182. data/public/dist/js/webshims/shims/canvas-blob.js +1 -0
  183. data/public/dist/js/webshims/shims/color-picker.js +2 -0
  184. data/public/dist/js/webshims/shims/combos/1.js +6 -0
  185. data/public/dist/js/webshims/shims/combos/10.js +2 -0
  186. data/public/dist/js/webshims/shims/combos/11.js +2 -0
  187. data/public/dist/js/webshims/shims/combos/12.js +6 -0
  188. data/public/dist/js/webshims/shims/combos/13.js +1 -0
  189. data/public/dist/js/webshims/shims/combos/14.js +1 -0
  190. data/public/dist/js/webshims/shims/combos/15.js +2 -0
  191. data/public/dist/js/webshims/shims/combos/16.js +7 -0
  192. data/public/dist/js/webshims/shims/combos/17.js +2 -0
  193. data/public/dist/js/webshims/shims/combos/18.js +3 -0
  194. data/public/dist/js/webshims/shims/combos/2.js +7 -0
  195. data/public/dist/js/webshims/shims/combos/21.js +2 -0
  196. data/public/dist/js/webshims/shims/combos/22.js +1 -0
  197. data/public/dist/js/webshims/shims/combos/23.js +6 -0
  198. data/public/dist/js/webshims/shims/combos/25.js +2 -0
  199. data/public/dist/js/webshims/shims/combos/27.js +1 -0
  200. data/public/dist/js/webshims/shims/combos/28.js +1 -0
  201. data/public/dist/js/webshims/shims/combos/29.js +1 -0
  202. data/public/dist/js/webshims/shims/combos/3.js +1 -0
  203. data/public/dist/js/webshims/shims/combos/30.js +2 -0
  204. data/public/dist/js/webshims/shims/combos/31.js +1 -0
  205. data/public/dist/js/webshims/shims/combos/33.js +1 -0
  206. data/public/dist/js/webshims/shims/combos/34.js +1 -0
  207. data/public/dist/js/webshims/shims/combos/4.js +1 -0
  208. data/public/dist/js/webshims/shims/combos/5.js +2 -0
  209. data/public/dist/js/webshims/shims/combos/6.js +2 -0
  210. data/public/dist/js/webshims/shims/combos/7.js +7 -0
  211. data/public/dist/js/webshims/shims/combos/8.js +7 -0
  212. data/public/dist/js/webshims/shims/combos/9.js +2 -0
  213. data/public/dist/js/webshims/shims/combos/97.js +1 -0
  214. data/public/dist/js/webshims/shims/combos/98.js +1 -0
  215. data/public/dist/js/webshims/shims/combos/99.js +1 -0
  216. data/public/dist/js/webshims/shims/details.js +1 -0
  217. data/public/dist/js/webshims/shims/dom-extend.js +1 -0
  218. data/public/dist/js/webshims/shims/es5.js +1 -0
  219. data/public/dist/js/webshims/shims/es6.js +1 -0
  220. data/public/dist/js/webshims/shims/excanvas.js +1 -0
  221. data/public/dist/js/webshims/shims/filereader-xhr.js +1 -0
  222. data/public/dist/js/webshims/shims/form-combat.js +1 -0
  223. data/public/dist/js/webshims/shims/form-core.js +1 -0
  224. data/public/dist/js/webshims/shims/form-datalist-lazy.js +1 -0
  225. data/public/dist/js/webshims/shims/form-datalist.js +1 -0
  226. data/public/dist/js/webshims/shims/form-fixrangechange.js +1 -0
  227. data/public/dist/js/webshims/shims/form-inputmode.js +1 -0
  228. data/public/dist/js/webshims/shims/form-message.js +1 -0
  229. data/public/dist/js/webshims/shims/form-native-extend.js +1 -0
  230. data/public/dist/js/webshims/shims/form-number-date-api.js +1 -0
  231. data/public/dist/js/webshims/shims/form-number-date-ui.js +1 -0
  232. data/public/dist/js/webshims/shims/form-shim-extend.js +1 -0
  233. data/public/dist/js/webshims/shims/form-shim-extend2.js +1 -0
  234. data/public/dist/js/webshims/shims/form-validation.js +1 -0
  235. data/public/dist/js/webshims/shims/form-validators.js +1 -0
  236. data/public/dist/js/webshims/shims/forms-picker.js +1 -0
  237. data/public/dist/js/webshims/shims/geolocation.js +1 -0
  238. data/public/dist/js/webshims/shims/i18n/formcfg-ar.js +1 -0
  239. data/public/dist/js/webshims/shims/i18n/formcfg-ch-CN.js +1 -0
  240. data/public/dist/js/webshims/shims/i18n/formcfg-cs.js +1 -0
  241. data/public/dist/js/webshims/shims/i18n/formcfg-de.js +1 -0
  242. data/public/dist/js/webshims/shims/i18n/formcfg-el.js +1 -0
  243. data/public/dist/js/webshims/shims/i18n/formcfg-en.js +1 -0
  244. data/public/dist/js/webshims/shims/i18n/formcfg-es.js +1 -0
  245. data/public/dist/js/webshims/shims/i18n/formcfg-fa.js +1 -0
  246. data/public/dist/js/webshims/shims/i18n/formcfg-fr.js +1 -0
  247. data/public/dist/js/webshims/shims/i18n/formcfg-he.js +1 -0
  248. data/public/dist/js/webshims/shims/i18n/formcfg-hi.js +1 -0
  249. data/public/dist/js/webshims/shims/i18n/formcfg-hu.js +1 -0
  250. data/public/dist/js/webshims/shims/i18n/formcfg-it.js +1 -0
  251. data/public/dist/js/webshims/shims/i18n/formcfg-ja.js +1 -0
  252. data/public/dist/js/webshims/shims/i18n/formcfg-lt.js +1 -0
  253. data/public/dist/js/webshims/shims/i18n/formcfg-nl.js +1 -0
  254. data/public/dist/js/webshims/shims/i18n/formcfg-pl.js +1 -0
  255. data/public/dist/js/webshims/shims/i18n/formcfg-pt-BR.js +1 -0
  256. data/public/dist/js/webshims/shims/i18n/formcfg-pt-PT.js +1 -0
  257. data/public/dist/js/webshims/shims/i18n/formcfg-pt.js +1 -0
  258. data/public/dist/js/webshims/shims/i18n/formcfg-ru.js +1 -0
  259. data/public/dist/js/webshims/shims/i18n/formcfg-sv.js +1 -0
  260. data/public/dist/js/webshims/shims/i18n/formcfg-zh-CN.js +1 -0
  261. data/public/dist/js/webshims/shims/i18n/formcfg-zh-TW.js +1 -0
  262. data/public/dist/js/webshims/shims/jme/alternate-media.js +1 -0
  263. data/public/dist/js/webshims/shims/jme/base.js +1 -0
  264. data/public/dist/js/webshims/shims/jme/controls.css +1 -0
  265. data/public/dist/js/webshims/shims/jme/jme.eot +0 -0
  266. data/public/dist/js/webshims/shims/jme/jme.svg +36 -0
  267. data/public/dist/js/webshims/shims/jme/jme.ttf +0 -0
  268. data/public/dist/js/webshims/shims/jme/jme.woff +0 -0
  269. data/public/dist/js/webshims/shims/jme/mediacontrols-lazy.js +1 -0
  270. data/public/dist/js/webshims/shims/jme/mediacontrols.js +1 -0
  271. data/public/dist/js/webshims/shims/jme/playlist.js +1 -0
  272. data/public/dist/js/webshims/shims/jpicker/images/AlphaBar.png +0 -0
  273. data/public/dist/js/webshims/shims/jpicker/images/Bars.png +0 -0
  274. data/public/dist/js/webshims/shims/jpicker/images/Maps.png +0 -0
  275. data/public/dist/js/webshims/shims/jpicker/images/NoColor.png +0 -0
  276. data/public/dist/js/webshims/shims/jpicker/images/bar-opacity.png +0 -0
  277. data/public/dist/js/webshims/shims/jpicker/images/map-opacity.png +0 -0
  278. data/public/dist/js/webshims/shims/jpicker/images/mappoint.gif +0 -0
  279. data/public/dist/js/webshims/shims/jpicker/images/picker.gif +0 -0
  280. data/public/dist/js/webshims/shims/jpicker/images/preview-opacity.png +0 -0
  281. data/public/dist/js/webshims/shims/jpicker/images/rangearrows.gif +0 -0
  282. data/public/dist/js/webshims/shims/jpicker/jpicker.css +1 -0
  283. data/public/dist/js/webshims/shims/matchMedia.js +3 -0
  284. data/public/dist/js/webshims/shims/mediacapture-picker.js +1 -0
  285. data/public/dist/js/webshims/shims/mediacapture.js +1 -0
  286. data/public/dist/js/webshims/shims/mediaelement-core.js +1 -0
  287. data/public/dist/js/webshims/shims/mediaelement-debug.js +1 -0
  288. data/public/dist/js/webshims/shims/mediaelement-jaris.js +1 -0
  289. data/public/dist/js/webshims/shims/mediaelement-native-fix.js +1 -0
  290. data/public/dist/js/webshims/shims/mediaelement-yt.js +1 -0
  291. data/public/dist/js/webshims/shims/moxie/flash/Moxie.cdn.swf +0 -0
  292. data/public/dist/js/webshims/shims/moxie/flash/Moxie.min.swf +0 -0
  293. data/public/dist/js/webshims/shims/moxie/js/moxie-html4.js +3 -0
  294. data/public/dist/js/webshims/shims/moxie/js/moxie-swf.js +2 -0
  295. data/public/dist/js/webshims/shims/picture.js +1 -0
  296. data/public/dist/js/webshims/shims/plugins/jquery.ui.position.js +11 -0
  297. data/public/dist/js/webshims/shims/range-ui.js +1 -0
  298. data/public/dist/js/webshims/shims/sizzle.js +11 -0
  299. data/public/dist/js/webshims/shims/sticky.js +1 -0
  300. data/public/dist/js/webshims/shims/styles/color-picker.png +0 -0
  301. data/public/dist/js/webshims/shims/styles/forms-ext.css +1 -0
  302. data/public/dist/js/webshims/shims/styles/forms-picker.css +1 -0
  303. data/public/dist/js/webshims/shims/styles/progress.gif +0 -0
  304. data/public/dist/js/webshims/shims/styles/progress.png +0 -0
  305. data/public/dist/js/webshims/shims/styles/shim-ext.css +1 -0
  306. data/public/dist/js/webshims/shims/styles/shim.css +1 -0
  307. data/public/dist/js/webshims/shims/styles/transparent.png +0 -0
  308. data/public/dist/js/webshims/shims/styles/widget.eot +0 -0
  309. data/public/dist/js/webshims/shims/styles/widget.svg +12 -0
  310. data/public/dist/js/webshims/shims/styles/widget.ttf +0 -0
  311. data/public/dist/js/webshims/shims/styles/widget.woff +0 -0
  312. data/public/dist/js/webshims/shims/swf/JarisFLVPlayer.swf +0 -0
  313. data/public/dist/js/webshims/shims/swfmini-embed.js +1 -0
  314. data/public/dist/js/webshims/shims/swfmini.js +6 -0
  315. data/public/dist/js/webshims/shims/track-ui.js +1 -0
  316. data/public/dist/js/webshims/shims/track.js +1 -0
  317. data/public/dist/js/webshims/shims/url.js +1 -0
  318. data/public/dist/js/webshims/shims/usermedia-core.js +1 -0
  319. data/public/dist/js/webshims/shims/usermedia-shim.js +1 -0
  320. data/public/js/bootstrap.min.js +3 -8
  321. data/public/js/jquery-ui.min.js +6 -0
  322. data/public/js/jquery.min.js +4 -0
  323. data/public/js/jquery.t.js +4 -4
  324. data/public/js/sequenceserver.blast.js +20 -18
  325. data/public/js/sequenceserver.js +116 -74
  326. data/sequenceserver.gemspec +20 -16
  327. data/views/400.erb +2 -1
  328. data/views/500.erb +6 -1
  329. data/views/result.erb +38 -18
  330. data/views/search.erb +49 -32
  331. metadata +389 -11
  332. data/public/img/glyphicons-halflings-white.png +0 -0
  333. data/public/img/glyphicons-halflings.png +0 -0
  334. data/public/js/jquery-ui.js +0 -14987
  335. data/public/js/jquery.js +0 -5
  336. data/public/js/jquery.scrollspy.js +0 -74
  337. data/public/sequence.min.js +0 -1
@@ -1,8 +1,14 @@
1
1
  require 'forwardable'
2
2
  require 'tempfile'
3
+ require 'English'
3
4
  require 'ox'
4
5
 
5
6
  require 'sequenceserver/links'
7
+ require 'sequenceserver/blast/exceptions'
8
+ require 'sequenceserver/blast/report'
9
+ require 'sequenceserver/blast/query'
10
+ require 'sequenceserver/blast/hit'
11
+ require 'sequenceserver/blast/hsp'
6
12
 
7
13
  module SequenceServer
8
14
  # Simple wrapper around BLAST+ search algorithms.
@@ -10,478 +16,203 @@ module SequenceServer
10
16
  # `BLAST::ArgumentError` and `BLAST::RuntimeError` signal errors encountered
11
17
  # when attempting a BLAST search.
12
18
  module BLAST
13
- # To signal error in query sequence or options.
14
- #
15
- # ArgumentError is raised when BLAST+'s exit status is 1; see [1].
16
- class ArgumentError < ArgumentError
17
- end
18
-
19
- # To signal internal errors.
20
- #
21
- # RuntimeError is raised when BLAST+'s exits status is one of 2, 3, 4, or
22
- # 255; see [1]. These are rare, infrastructure errors, used internally,
23
- # and of concern only to the admins/developers.
24
- class RuntimeError < RuntimeError
25
- def initialize(status, message)
26
- @status = status
27
- @message = message
28
- end
29
-
30
- attr_reader :status, :message
31
-
32
- def to_s
33
- "#{status}, #{message}"
34
- end
35
- end
36
-
37
- # Capture results per query of a BLAST search.
38
- # @member [String] number
39
- # @member [String] def
40
- # @member [Fixnum] len
41
- # @member [Array(Hit)] hits
42
- Query = Struct.new(:number, :def, :len, :hits) do
43
- def initialize(*args)
44
- args[0] = args[0].to_i
45
- args[1] = "Query_#{args[0]}" if args[1] == 'No definition line'
46
- args[2] = args[2].to_i
47
- @id, *rest = args[1].split
48
- @title = rest.join(' ')
49
- super
50
- end
51
-
52
- def sort_hits_by_evalue!
53
- @hits = hits.sort_by(&:evalue)
54
- end
55
-
56
- attr_reader :id, :title
57
-
58
- alias_method :length, :len
59
- end
60
-
61
- # Hit Object to store all the hits per Query.
62
- # @member [Fixnum] number
63
- # @member [String] id
64
- # @member [String] def
65
- # @member [String] accession
66
- # @member [Fixnum] len
67
- # @member [HSP] hsp
68
- Hit = Struct.new(:number, :id, :title, :accession, :len, :hsps) do
69
- def initialize(*args)
70
- args[0] = args[0].to_i
71
- args[2] = '' if args[2] == 'No definition line'
72
- args[4] = args[4].to_i
73
- super
74
- end
75
-
76
- alias_method :length, :len
77
-
78
- # Hit evalue is the minimum evalue of all HSP(s).
79
- def evalue
80
- hsps.map(&:evalue).min
81
- end
82
-
83
- # Hit score is the sum of bit scores of all HSP(s).
84
- def score
85
- hsps.map(&:bit_score).reduce(:+)
86
- end
87
- end
88
-
89
- # Structure to hold the HSP information about each hit. For more
90
- # information, check the link contained in the references section at the
91
- # end of the file.
92
- HSP = Struct.new(:number, :bit_score, :score, :evalue, :qstart, :qend,
93
- :sstart, :send, :qframe, :sframe, :identity, :positives,
94
- :gaps, :len, :qseq, :sseq, :midline) do
19
+ ERROR_LINE = /\(CArgException.*\)\s(.*)/
95
20
 
96
- INTEGER_ARGS = [0, 2].concat((4..13).to_a)
97
- FLOAT_ARGS = [1, 3]
21
+ ALGORITHMS = %w(blastn blastp blastx tblastn tblastx)
98
22
 
99
- def initialize(*args)
100
- INTEGER_ARGS.each do |i|
101
- args[i] = args[i].to_i
102
- end
23
+ OUTFMT = {
24
+ 'pairwise' => [0, 'txt'],
25
+ 'qa_identity' => [1, 'txt'],
26
+ 'qa_no_identity' => [2, 'txt'],
27
+ 'fqa_identity' => [3, 'txt'],
28
+ 'fqa_no_identity' => [4, 'txt'],
29
+ 'xml' => [5, 'xml'],
30
+ 'tsv' => [6, 'tsv'],
31
+ 'tsv_commented' => [7, 'tsv'],
32
+ 'asn_text' => [8, 'asn'],
33
+ 'asn_binary' => [9, 'asn'],
34
+ 'csv' => [10, 'csv'],
35
+ 'archive' => [11, 'txt']
36
+ } # See [1]
37
+
38
+ class << self
39
+ extend Forwardable
40
+
41
+ def_delegators SequenceServer, :config, :logger
42
+
43
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
44
+ # rubocop:disable Metrics/MethodLength
45
+ def run(params)
46
+ pre_process params
47
+ validate_blast_params params
48
+
49
+ # Compile parameters for BLAST search into a shell executable command.
50
+ #
51
+ # BLAST method to use.
52
+ method = params[:method]
53
+ #
54
+ # BLAST+ expects query sequence as a file.
55
+ qfile = Tempfile.new('sequenceserver_query')
56
+ qfile.puts(params[:sequence])
57
+ qfile.close
58
+ #
59
+ # Retrieve database objects from database id.
60
+ databases = Database[params[:databases]]
61
+ #
62
+ # Concatenate other blast options.
63
+ options = params[:advanced].to_s.strip + defaults
64
+ #
65
+ # blastn implies blastn, not megablast; but let's not interfere if a
66
+ # user specifies `task` herself.
67
+ options << ' -task blastn' if method == 'blastn' && !(options =~ /task/)
68
+
69
+ # Run BLAST search.
70
+ #
71
+ # Command to execute.
72
+ command = "#{method} -db '#{databases.map(&:name).join(' ')}'" \
73
+ " -query '#{qfile.path}' #{options}"
74
+ #
75
+ # Debugging log.
76
+ logger.debug("Executing: #{command}")
77
+ #
78
+ # Temporary files to capture stdout and stderr.
79
+ rfile = Tempfile.new('sequenceserver_blast_result')
80
+ efile = Tempfile.new('sequenceserver_blast_error')
81
+ [rfile, efile].each(&:close)
82
+ #
83
+ # Execute.
84
+ system("#{command} > #{rfile.path} 2> #{efile.path}")
85
+
86
+ # Capture error.
87
+ status = $CHILD_STATUS.exitstatus
88
+ case status
89
+ when 1 # error in query sequence or options; see [1]
90
+ efile.open
91
+
92
+ # Most of the time BLAST+ generates a verbose error message with
93
+ # details we don't require. So we parse out the relevant lines.
94
+ error = efile.each_line do |l|
95
+ break Regexp.last_match[1] if l.match(ERROR_LINE)
96
+ end
103
97
 
104
- FLOAT_ARGS.each do |i|
105
- args[i] = args[i].to_f
98
+ # But sometimes BLAST+ returns the exact/relevant error message.
99
+ # Trying to parse such messages returns nil, and we use the error
100
+ # message from BLAST+ as it is.
101
+ error = efile.rewind && efile.read unless error.is_a? String
102
+
103
+ efile.close
104
+ fail ArgumentError, error
105
+ when 2, 3, 4, 255 # see [1]
106
+ efile.open
107
+ error = efile.read
108
+ efile.close
109
+ fail RuntimeError.new(status, error)
106
110
  end
107
111
 
108
- super
109
- end
110
-
111
- alias_method :length, :len
112
-
113
- end
114
-
115
- # Captures BLAST results from BLAST+'s XML output.
116
- class Report
117
-
118
- include Links
119
-
120
- # Expects a File object and Database objects used to BLAST against.
121
- #
122
- # Parses the XML file into an intermediate representation (ir) and
123
- # constructs an object model from that.
124
- #
125
- # NOTE:
126
- # Databases param is optional for test suite.
127
- def initialize(rfile, databases = nil)
128
- ir = node_to_array Ox.parse(rfile.read).root
129
-
130
- @program = ir[0]
131
- @program_version = ir[1]
132
- @querydb = Array databases
133
- @parameters = {
134
- :matrix => ir[7][0],
135
- :evalue => ir[7][1],
136
- :gapopen => ir[7][2],
137
- :gapextend => ir[7][3],
138
- :filters => ir[7][4]
139
- }
140
-
141
- ir[8].each_with_index do |n, i|
142
- @stats ||= n[5][0]
143
- @queries ||= []
144
- @queries.push(Query.new(n[0], n[2], n[3], []))
145
-
146
- # Ensure a hit object is received. No hits, returns a newline. Note
147
- # that checking to "\n" doesn't work since n[4] = ["\n"]
148
- if n[4] == ["\n"]
149
- @queries[i][:hits] = []
150
- else
151
- n[4].each_with_index do |hits, j|
152
- @queries[i][:hits].push(Hit.new(hits[0], hits[1], hits[2],
153
- hits[3], hits[4], []))
154
- hits[5].each do |hsp|
155
- @queries[i][:hits][j][:hsps].push(HSP.new(*hsp))
156
- end
157
- end
158
- @queries[i].sort_hits_by_evalue!
159
- end
160
- end
112
+ Report.new(File.basename(rfile), databases)
161
113
  end
162
114
 
163
- attr_reader :program, :program_version
164
-
165
- # :nodoc:
166
- # params are defaults provided by BLAST or user input to tweak the
167
- # result. stats are computed metrics provided by BLAST.
168
- #
169
- # BLAST+ doesn't list all input params (like word_size) in the XML
170
- # output. Only matrix, evalue, gapopen, gapextend, and filters.
171
- attr_reader :params, :stats
115
+ def format(params)
116
+ validate_format_params params
172
117
 
173
- attr_reader :querydb
118
+ rfile = create_file_path params['report']
119
+ ofmt = OUTFMT[params['format']]
120
+ type = params['type']
174
121
 
175
- attr_reader :queries
122
+ oname = "seqserv_#{type}_#{Time.now.strftime('%H%M')}.#{ofmt[1]}"
123
+ ofile = Tempfile.new oname
176
124
 
177
- # Helper methods for pretty printing results
125
+ command = "blast_formatter -archive '#{rfile}' -out #{ofile.path}" \
126
+ " -outfmt '#{ofmt[0]} #{params['specifiers']}' 2> /dev/null"
178
127
 
179
- # FIXME: HTML!!
180
- def pretty_evalue(hsp)
181
- hsp.evalue.to_s.sub(/(\d*\.\d*)e?([+-]\d*)?/) do
182
- s = '%.3f' % Regexp.last_match[1]
183
- s << " &times; 10<sup>#{Regexp.last_match[2]}</sup>" if Regexp.last_match[2]
184
- s
185
- end
186
- end
187
-
188
- def identity_fraction(hsp)
189
- "#{hsp.identity}/#{hsp.length}"
190
- end
128
+ logger.debug("Executing: #{command}")
129
+ system command
191
130
 
192
- def positives_fraction(hsp)
193
- "#{hsp.positives}/#{hsp.length}"
131
+ {
132
+ :filepath => ofile.path,
133
+ :filename => oname,
134
+ :type => ofmt[1]
135
+ }
194
136
  end
137
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
138
+ # rubocop:enable Metrics/MethodLength
195
139
 
196
- def gaps_fraction(hsp)
197
- "#{hsp.gaps}/#{hsp.length}"
140
+ def pre_process(params)
141
+ params[:sequence].strip! unless params[:sequence].nil?
198
142
  end
199
143
 
200
- def identity_percentage(hsp)
201
- "#{'%.2f' % (hsp.identity * 100.0 / hsp.length)}"
144
+ def validate_format_params(params)
145
+ return true if params.include?('report') &&
146
+ params.include?('format') &&
147
+ File.exist?(create_file_path params['report'])
148
+ fail ArgumentError, <<MSG
149
+ Incorrect request parameters. Please ensure that requested file name is
150
+ correct and the file type is either xml or tsv.
151
+ MSG
202
152
  end
203
153
 
204
- def positives_percentage(hsp)
205
- "#{'%.2f' % (hsp.positives * 100.0 / hsp.length)}"
154
+ def validate_blast_params(params)
155
+ validate_blast_method params[:method]
156
+ validate_blast_sequences params[:sequence]
157
+ validate_blast_databases params[:databases]
158
+ validate_blast_options params[:advanced]
206
159
  end
207
160
 
208
- def gaps_percentage(hsp)
209
- "#{'%.2f' % (hsp.gaps * 100.0 / hsp.length)}"
161
+ def defaults
162
+ " -outfmt 11 -num_threads #{config[:num_threads]}"
210
163
  end
211
164
 
212
- # FIXME: Test me.
213
- def pp_hsp(hsp)
214
- # In many of the BLAST algorithms, translated queries are performed
215
- # which has to be taken care while determining end co ordinates of
216
- # query and subject sequences. Since each amino acid is encoded using
217
- # three nucl. referred to as codons, necessary value is multiplied
218
- # to determine the coordinates.
219
-
220
- # blastn and blastp search the nucleotide and protein databases using
221
- # nucleotide and protein queries respectively.
222
- qframe_unit = 1
223
- sframe_unit = 1
224
- # tblastn searches translated nucleotide database using a protein query
225
- if @program == 'tblastn'
226
- sframe_unit = 3
227
- # blastx searches protein database using a translated nucleotide query,
228
- elsif @program == 'blastx'
229
- qframe_unit = 3
230
- # tblastx searches translated nucleotide database using a translated
231
- # nucleotide query.
232
- elsif @program == 'tblastx'
233
- qframe_unit = 3
234
- sframe_unit = 3
235
- end
236
-
237
- qframe_sign = hsp.qframe >= 0 ? 1 : -1
238
- sframe_sign = hsp.sframe >= 0 ? 1 : -1
239
-
240
- chars = 60
241
- lines = (hsp.length / chars.to_f).ceil
242
- width = [hsp.qend, hsp.send, hsp.qstart,
243
- hsp.sstart].map(&:to_s).map(&:length).max
244
-
245
- # blastn results are inconsistent with the other methods as it
246
- # automatically reverse the start and end coordinates (based on
247
- # frame), while for others it has to be inferred.
248
- if @program != 'blastn'
249
- nqseq = hsp.qframe >= 0 ? hsp.qstart : hsp.qend
250
- nsseq = hsp.sframe >= 0 ? hsp.sstart : hsp.send
251
- else
252
- nqseq = hsp.qstart
253
- nsseq = hsp.sstart
254
- end
255
-
256
- s = ''
257
- (1..lines).each do |i|
258
- lqstart = nqseq
259
- lqseq = hsp.qseq[chars * (i - 1), chars]
260
- nqseq += (lqseq.length - lqseq.count('-')) * qframe_unit * qframe_sign
261
- lqend = nqseq - qframe_sign
262
- s << "Query %#{width}d #{lqseq} #{lqend}\n" % lqstart
263
-
264
- lmseq = hsp.midline[chars * (i - 1), chars]
265
- s << "#{' ' * (width + 8)} #{lmseq}\n"
266
-
267
- lsstart = nsseq
268
- lsseq = hsp.sseq[chars * (i - 1), chars]
269
- nsseq += (lsseq.length - lsseq.count('-')) * sframe_unit * sframe_sign
270
- lsend = nsseq - sframe_sign
271
- s << "Subject %#{width}d #{lsseq} #{lsend}\n" % lsstart
272
-
273
- s << "\n" unless i == lines
274
- end
275
- s
165
+ def validate_blast_method(method)
166
+ return true if ALGORITHMS.include? method
167
+ fail ArgumentError, 'BLAST algorithm should be one of:' \
168
+ " #{ALGORITHMS.join(', ')}."
276
169
  end
277
170
 
278
- # FIXME: Document me.
279
- def filter_hsp_stats(hsp)
280
- hsp_stats = {
281
- 'Score' => "#{'%.2f' % hsp[:bit_score]} (#{hsp[:score]})",
282
- 'E value' => "#{pretty_evalue hsp}",
283
- 'Identities' => "#{identity_fraction hsp} " \
284
- "(#{identity_percentage hsp}%)",
285
- 'Gaps' => "#{gaps_fraction hsp} (#{gaps_percentage hsp}%)"
286
- }
287
-
288
- if @program == 'blastp'
289
- hsp_stats['Positives'] = "#{positives_fraction hsp}" \
290
- "(#{positives_percentage hsp}%)"
291
- elsif @program == 'blastx'
292
- hsp_stats['Query frame'] = "#{hsp[:qframe]}"
293
- elsif @program == 'tblastn'
294
- hsp_stats['Hit frame'] = "#{hsp[:sframe]}"
295
- elsif @program == 'tblastx'
296
- hsp_stats['Positives'] = "#{positives_fraction hsp}" \
297
- "(#{positives_percentage hsp}%)"
298
- hsp_stats['Frame'] = "#{hsp[:qframe]}/#{hsp[:sframe]}"
299
- elsif @program == 'blastn'
300
- hsp_stats['Strand'] = "#{hsp[:qframe] > 0 ? '+' : '-'}/" \
301
- "#{hsp[:sframe] > 0 ? '+' : '-'}"
302
- end
303
-
304
- hsp_stats
171
+ def validate_blast_sequences(sequences)
172
+ return true if sequences.is_a?(String) && !sequences.empty?
173
+ fail ArgumentError, 'Sequences should be a non-empty string.'
305
174
  end
306
175
 
307
- def link_per_hit(sequence_id)
308
- links = Links.instance_methods.map {|m| send(m, sequence_id)}
309
-
310
- # Sort links based on :order key (ascending)
311
- links.compact!.sort_by! {|link| link[:order]}
176
+ def validate_blast_databases(database_ids)
177
+ ids = Database.ids
178
+ return true if database_ids.is_a?(Array) && !database_ids.empty? &&
179
+ (ids & database_ids).length == database_ids.length
180
+ fail ArgumentError, 'Database id should be one of:' \
181
+ " #{ids.join("\n")}."
312
182
  end
313
183
 
314
- # Returns an array of database objects which contain the queried
315
- # sequence id.
316
- # NOTE: This function may return more than one database object for
317
- # a single sequence id.
184
+ # Advanced options are specified by the user. Here they are checked for
185
+ # interference with SequenceServer operations.
318
186
  #
319
- # e.g., which_blastdb('SI_2.2.23') => [<Database: ...>, ...]
320
- def which_blastdb(sequence_id)
321
- querydb.select {|db| db.include? sequence_id}
322
- end
323
-
324
- private
325
-
326
- PARSEABLE_AS_ARRAY = %w(Parameters BlastOutput_param Iteration_stat
327
- Statistics Iteration_hits BlastOutput_iterations
328
- Iteration Hit Hit_hsps Hsp)
329
-
330
- def node_to_array(element)
331
- element.nodes.map {|n| node_to_value n}
332
- end
187
+ # Raise ArgumentError if an error has occurred.
188
+ def validate_blast_options(options)
189
+ return true if !options || (options.is_a?(String) &&
190
+ options.strip.empty?)
333
191
 
334
- def node_to_value(node)
335
- # Ensure that the recursion doesn't fails when String value is received.
336
- return node if node.is_a?(String)
337
-
338
- if PARSEABLE_AS_ARRAY.include? node.name
339
- value = node_to_array(node)
340
- else
341
- value = first_text(node)
192
+ unless allowed_chars.match(options)
193
+ fail ArgumentError, 'Invalid characters detected in options.'
342
194
  end
343
- value
344
- end
345
-
346
- def first_text(node)
347
- node.nodes.find {|n| n.is_a? String}
348
- end
349
- end
350
-
351
- ERROR_LINE = /\(CArgException.*\)\s(.*)/
352
-
353
- ALGORITHMS = %w(blastn blastp blastx tblastn tblastx)
354
-
355
- extend self
356
-
357
- extend Forwardable
358
-
359
- def_delegators SequenceServer, :config, :logger
360
-
361
- def run(params)
362
- pre_process params
363
- validate_blast_params params
364
195
 
365
- # Compile parameters for BLAST search into a shell executable command.
366
- #
367
- # BLAST method to use.
368
- method = params[:method]
369
- #
370
- # BLAST+ expects query sequence as a file.
371
- qfile = Tempfile.new('sequenceserver_query')
372
- qfile.puts(params[:sequence])
373
- qfile.close
374
- #
375
- # Retrieve database objects from database id.
376
- databases = Database[params[:databases]]
377
- #
378
- # Concatenate other blast options.
379
- options = params[:advanced].to_s.strip + defaults
380
- #
381
- # blastn implies blastn, not megablast; but let's not interfere if a user
382
- # specifies `task` herself.
383
- if method == 'blastn' and not options =~ /task/
384
- options << ' -task blastn'
385
- end
386
-
387
- # Run BLAST search.
388
- #
389
- # Command to execute.
390
- command = "#{method} -db '#{databases.map(&:name).join(' ')}'" \
391
- " -query '#{qfile.path}' #{options}"
392
- #
393
- # Debugging log.
394
- logger.debug("Executing: #{command}")
395
- #
396
- # Temporary files to capture stdout and stderr.
397
- rfile = Tempfile.new('sequenceserver_blast_result')
398
- efile = Tempfile.new('sequenceserver_blast_error')
399
- [rfile, efile].each(&:close)
400
- #
401
- # Execute.
402
- system("#{command} > #{rfile.path} 2> #{efile.path}")
403
-
404
- # Capture error.
405
- status = $?.exitstatus
406
- case status
407
- when 1 # error in query sequence or options; see [1]
408
- efile.open
409
-
410
- # Most of the time BLAST+ generates a verbose error message with
411
- # details we don't require. So we parse out the relevant lines.
412
- error = efile.each_line do |l|
413
- break Regexp.last_match[1] if l.match(ERROR_LINE)
196
+ if disallowed_options.match(options)
197
+ failedopt = Regexp.last_match[0]
198
+ fail ArgumentError, "Option \"#{failedopt}\" is prohibited."
414
199
  end
415
200
 
416
- # But sometimes BLAST+ returns the exact/relevant error message.
417
- # Trying to parse such messages returns nil, and we use the error
418
- # message from BLAST+ as it is.
419
- error = efile.rewind && efile.read unless error.is_a? String
420
-
421
- efile.close
422
- raise ArgumentError, error
423
- when 2, 3, 4, 255 # see [1]
424
- efile.open
425
- error = efile.read
426
- efile.close
427
- raise RuntimeError.new(status, error)
201
+ true
428
202
  end
429
203
 
430
- # Report the results, ensures that file is closed after execution.
431
- File.open(rfile.path) {|f| Report.new(f, databases)}
432
- end
433
-
434
- def pre_process(params)
435
- unless params[:sequence].nil?
436
- params[:sequence].strip!
204
+ # Returns filename if path exists otherwise returns a path to tmp dir.
205
+ def create_file_path(filename)
206
+ return File.join(Dir.tmpdir, filename) unless File.exist? filename
207
+ filename
437
208
  end
438
- end
439
-
440
- def validate_blast_params(params)
441
- validate_blast_method params[:method]
442
- validate_blast_sequences params[:sequence]
443
- validate_blast_databases params[:databases]
444
- validate_blast_options params[:advanced]
445
- end
446
-
447
- def defaults
448
- " -outfmt 5 -num_threads #{config[:num_threads]}"
449
- end
450
-
451
- def validate_blast_method(method)
452
- return true if ALGORITHMS.include? method
453
- raise ArgumentError, "BLAST algorithm should be one of:" \
454
- " #{ALGORITHMS.join(', ')}."
455
- end
456
209
 
457
- def validate_blast_sequences(sequences)
458
- return true if sequences.is_a? String and not sequences.empty?
459
- raise ArgumentError, 'Sequences should be a non-empty string.'
460
- end
461
-
462
- def validate_blast_databases(database_ids)
463
- ids = Database.ids
464
- return true if database_ids.is_a?(Array) && !database_ids.empty? &&
465
- (ids & database_ids).length == database_ids.length
466
- raise ArgumentError, "Database id should be one of:" \
467
- " #{ids.join("\n")}."
468
- end
469
-
470
- # Advanced options are specified by the user. Here they are checked for
471
- # interference with SequenceServer operations.
472
- # raise ArgumentError if an error has occurred, else return without value
473
- def validate_blast_options(options)
474
- return true if !options || (options.is_a?(String) && options.strip.empty?)
475
-
476
- unless options =~ /\A[a-z0-9\-_\. ']*\Z/i
477
- raise ArgumentError, 'Invalid characters detected in options.'
210
+ def allowed_chars
211
+ /\A[a-z0-9\-_\. ']*\Z/i
478
212
  end
479
213
 
480
- disallowed_options = %w(-out -html -outfmt -db -query)
481
- disallowed_options.each do |o|
482
- if options =~ /#{o}/i
483
- raise ArgumentError, "Option \"#{o}\" is prohibited."
484
- end
214
+ def disallowed_options
215
+ /-out|-html|-outfmt|-db|-query/i
485
216
  end
486
217
  end
487
218
  end