sequenceserver 0.6.8 → 0.6.9
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/database_formatter +1 -3
- data/bin/sequenceserver +2 -4
- data/lib/sequenceserver.rb +7 -5
- data/public/css/custom.css +1 -0
- data/public/js/jquery.activity.js +224 -0
- data/public/js/search.js +17 -0
- data/sequenceserver.gemspec +2 -1
- data/views/search.erb +3 -2
- metadata +24 -8
data/bin/database_formatter
CHANGED
@@ -2,10 +2,8 @@
|
|
2
2
|
# copyright yannick . wurm at unil . ch
|
3
3
|
# Finds files, reads first char. if its '>', read 500 lines. Guess sequence type, ask user for title to format as blast database.
|
4
4
|
|
5
|
-
# ensure 'lib/' is in the load path
|
6
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
|
-
|
8
5
|
require 'rubygems'
|
6
|
+
require 'bundler/setup'
|
9
7
|
require 'ptools' # for File.binary?(file)
|
10
8
|
require 'find'
|
11
9
|
require 'logger'
|
data/bin/sequenceserver
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
# application root
|
4
|
-
root = File.dirname(File.dirname(__FILE__))
|
5
|
-
|
6
3
|
require 'rubygems'
|
7
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'sequenceserver'
|
8
6
|
|
9
7
|
# display name for tools like `ps`
|
10
8
|
$PROGRAM_NAME = 'sequenceserver'
|
data/lib/sequenceserver.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
# sequenceserver.rb
|
2
2
|
|
3
|
-
# ensure 'lib/' is in the load path
|
4
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
-
|
6
|
-
require 'rubygems'
|
7
3
|
require 'sinatra/base'
|
8
4
|
require 'yaml'
|
9
5
|
require 'logger'
|
@@ -233,8 +229,10 @@ module SequenceServer
|
|
233
229
|
# evaluate empty sequence as nil, otherwise as fasta
|
234
230
|
sequence = sequence.empty? ? nil : to_fasta(sequence)
|
235
231
|
|
232
|
+
# TODO: detect sequence type in the browser itself (no AJAX)
|
236
233
|
if request.xhr?
|
237
|
-
|
234
|
+
# if the AJAX request didn't specify a blast method, it must be interested in sequence type only
|
235
|
+
return (sequence && type_of_sequences(sequence)).to_s unless method
|
238
236
|
end
|
239
237
|
|
240
238
|
# Raise ArgumentError if there is no database selected
|
@@ -293,6 +291,10 @@ module SequenceServer
|
|
293
291
|
|
294
292
|
@blast = format_blast_results(blast.result, databases)
|
295
293
|
|
294
|
+
if request.xhr?
|
295
|
+
return @blast
|
296
|
+
end
|
297
|
+
|
296
298
|
erb :search
|
297
299
|
end
|
298
300
|
|
data/public/css/custom.css
CHANGED
@@ -0,0 +1,224 @@
|
|
1
|
+
/*!
|
2
|
+
* NETEYE Activity Indicator jQuery Plugin
|
3
|
+
*
|
4
|
+
* Copyright (c) 2010 NETEYE GmbH
|
5
|
+
* Licensed under the MIT license
|
6
|
+
*
|
7
|
+
* Author: Felix Gnass [fgnass at neteye dot de]
|
8
|
+
* Version: @{VERSION}
|
9
|
+
*/
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Plugin that renders a customisable activity indicator (spinner) using SVG or VML.
|
13
|
+
*/
|
14
|
+
(function($) {
|
15
|
+
|
16
|
+
$.fn.activity = function(opts) {
|
17
|
+
this.each(function() {
|
18
|
+
var $this = $(this);
|
19
|
+
var el = $this.data('activity');
|
20
|
+
if (el) {
|
21
|
+
clearInterval(el.data('interval'));
|
22
|
+
el.remove();
|
23
|
+
$this.removeData('activity');
|
24
|
+
}
|
25
|
+
if (opts !== false) {
|
26
|
+
opts = $.extend({color: $this.css('color')}, $.fn.activity.defaults, opts);
|
27
|
+
|
28
|
+
el = render($this, opts).css('position', 'absolute').prependTo(opts.outside ? 'body' : $this);
|
29
|
+
var h = $this.outerHeight() - el.height();
|
30
|
+
var w = $this.outerWidth() - el.width();
|
31
|
+
var margin = {
|
32
|
+
top: opts.valign == 'top' ? opts.padding : opts.valign == 'bottom' ? h - opts.padding : Math.floor(h / 2),
|
33
|
+
left: opts.align == 'left' ? opts.padding : opts.align == 'right' ? w - opts.padding : Math.floor(w / 2)
|
34
|
+
};
|
35
|
+
var offset = $this.offset();
|
36
|
+
if (opts.outside) {
|
37
|
+
el.css({top: offset.top + 'px', left: offset.left + 'px'});
|
38
|
+
}
|
39
|
+
else {
|
40
|
+
margin.top -= el.offset().top - offset.top;
|
41
|
+
margin.left -= el.offset().left - offset.left;
|
42
|
+
}
|
43
|
+
el.css({marginTop: margin.top + 'px', marginLeft: margin.left + 'px'});
|
44
|
+
animate(el, opts.segments, Math.round(10 / opts.speed) / 10);
|
45
|
+
$this.data('activity', el);
|
46
|
+
}
|
47
|
+
});
|
48
|
+
return this;
|
49
|
+
};
|
50
|
+
|
51
|
+
$.fn.activity.defaults = {
|
52
|
+
segments: 12,
|
53
|
+
space: 3,
|
54
|
+
length: 7,
|
55
|
+
width: 4,
|
56
|
+
speed: 1.2,
|
57
|
+
align: 'center',
|
58
|
+
valign: 'center',
|
59
|
+
padding: 4
|
60
|
+
};
|
61
|
+
|
62
|
+
$.fn.activity.getOpacity = function(opts, i) {
|
63
|
+
var steps = opts.steps || opts.segments-1;
|
64
|
+
var end = opts.opacity !== undefined ? opts.opacity : 1/steps;
|
65
|
+
return 1 - Math.min(i, steps) * (1 - end) / steps;
|
66
|
+
};
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Default rendering strategy. If neither SVG nor VML is available, a div with class-name 'busy'
|
70
|
+
* is inserted, that can be styled with CSS to display an animated gif as fallback.
|
71
|
+
*/
|
72
|
+
var render = function() {
|
73
|
+
return $('<div>').addClass('busy');
|
74
|
+
};
|
75
|
+
|
76
|
+
/**
|
77
|
+
* The default animation strategy does nothing as we expect an animated gif as fallback.
|
78
|
+
*/
|
79
|
+
var animate = function() {
|
80
|
+
};
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Utility function to create elements in the SVG namespace.
|
84
|
+
*/
|
85
|
+
function svg(tag, attr) {
|
86
|
+
var el = document.createElementNS("http://www.w3.org/2000/svg", tag || 'svg');
|
87
|
+
if (attr) {
|
88
|
+
$.each(attr, function(k, v) {
|
89
|
+
el.setAttributeNS(null, k, v);
|
90
|
+
});
|
91
|
+
}
|
92
|
+
return $(el);
|
93
|
+
}
|
94
|
+
|
95
|
+
if (document.createElementNS && document.createElementNS( "http://www.w3.org/2000/svg", "svg").createSVGRect) {
|
96
|
+
|
97
|
+
// =======================================================================================
|
98
|
+
// SVG Rendering
|
99
|
+
// =======================================================================================
|
100
|
+
|
101
|
+
/**
|
102
|
+
* Rendering strategy that creates a SVG tree.
|
103
|
+
*/
|
104
|
+
render = function(target, d) {
|
105
|
+
var innerRadius = d.width*2 + d.space;
|
106
|
+
var r = (innerRadius + d.length + Math.ceil(d.width / 2) + 1);
|
107
|
+
|
108
|
+
var el = svg().width(r*2).height(r*2);
|
109
|
+
|
110
|
+
var g = svg('g', {
|
111
|
+
'stroke-width': d.width,
|
112
|
+
'stroke-linecap': 'round',
|
113
|
+
stroke: d.color
|
114
|
+
}).appendTo(svg('g', {transform: 'translate('+ r +','+ r +')'}).appendTo(el));
|
115
|
+
|
116
|
+
for (var i = 0; i < d.segments; i++) {
|
117
|
+
g.append(svg('line', {
|
118
|
+
x1: 0,
|
119
|
+
y1: innerRadius,
|
120
|
+
x2: 0,
|
121
|
+
y2: innerRadius + d.length,
|
122
|
+
transform: 'rotate(' + (360 / d.segments * i) + ', 0, 0)',
|
123
|
+
opacity: $.fn.activity.getOpacity(d, i)
|
124
|
+
}));
|
125
|
+
}
|
126
|
+
return $('<div>').append(el).width(2*r).height(2*r);
|
127
|
+
};
|
128
|
+
|
129
|
+
// Check if Webkit CSS animations are available, as they work much better on the iPad
|
130
|
+
// than setTimeout() based animations.
|
131
|
+
|
132
|
+
if (document.createElement('div').style.WebkitAnimationName !== undefined) {
|
133
|
+
|
134
|
+
var animations = {};
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Animation strategy that uses dynamically created CSS animation rules.
|
138
|
+
*/
|
139
|
+
animate = function(el, steps, duration) {
|
140
|
+
if (!animations[steps]) {
|
141
|
+
var name = 'spin' + steps;
|
142
|
+
var rule = '@-webkit-keyframes '+ name +' {';
|
143
|
+
for (var i=0; i < steps; i++) {
|
144
|
+
var p1 = Math.round(100000 / steps * i) / 1000;
|
145
|
+
var p2 = Math.round(100000 / steps * (i+1) - 1) / 1000;
|
146
|
+
var value = '% { -webkit-transform:rotate(' + Math.round(360 / steps * i) + 'deg); }\n';
|
147
|
+
rule += p1 + value + p2 + value;
|
148
|
+
}
|
149
|
+
rule += '100% { -webkit-transform:rotate(100deg); }\n}';
|
150
|
+
document.styleSheets[0].insertRule(rule);
|
151
|
+
animations[steps] = name;
|
152
|
+
}
|
153
|
+
el.css('-webkit-animation', animations[steps] + ' ' + duration +'s linear infinite');
|
154
|
+
};
|
155
|
+
}
|
156
|
+
else {
|
157
|
+
|
158
|
+
/**
|
159
|
+
* Animation strategy that transforms a SVG element using setInterval().
|
160
|
+
*/
|
161
|
+
animate = function(el, steps, duration) {
|
162
|
+
var rotation = 0;
|
163
|
+
var g = el.find('g g').get(0);
|
164
|
+
el.data('interval', setInterval(function() {
|
165
|
+
g.setAttributeNS(null, 'transform', 'rotate(' + (++rotation % steps * (360 / steps)) + ')');
|
166
|
+
}, duration * 1000 / steps));
|
167
|
+
};
|
168
|
+
}
|
169
|
+
|
170
|
+
}
|
171
|
+
else {
|
172
|
+
|
173
|
+
// =======================================================================================
|
174
|
+
// VML Rendering
|
175
|
+
// =======================================================================================
|
176
|
+
|
177
|
+
var s = $('<shape>').css('behavior', 'url(#default#VML)');
|
178
|
+
|
179
|
+
$('body').append(s);
|
180
|
+
|
181
|
+
if (s.get(0).adj) {
|
182
|
+
|
183
|
+
// VML support detected. Insert CSS rules for group, shape and stroke.
|
184
|
+
var sheet = document.createStyleSheet();
|
185
|
+
$.each(['group', 'shape', 'stroke'], function() {
|
186
|
+
sheet.addRule(this, "behavior:url(#default#VML);");
|
187
|
+
});
|
188
|
+
|
189
|
+
/**
|
190
|
+
* Rendering strategy that creates a VML tree.
|
191
|
+
*/
|
192
|
+
render = function(target, d) {
|
193
|
+
|
194
|
+
var innerRadius = d.width*2 + d.space;
|
195
|
+
var r = (innerRadius + d.length + Math.ceil(d.width / 2) + 1);
|
196
|
+
var s = r*2;
|
197
|
+
var o = -Math.ceil(s/2);
|
198
|
+
|
199
|
+
var el = $('<group>', {coordsize: s + ' ' + s, coordorigin: o + ' ' + o}).css({top: o, left: o, width: s, height: s});
|
200
|
+
for (var i = 0; i < d.segments; i++) {
|
201
|
+
el.append($('<shape>', {path: 'm ' + innerRadius + ',0 l ' + (innerRadius + d.length) + ',0'}).css({
|
202
|
+
width: s,
|
203
|
+
height: s,
|
204
|
+
rotation: (360 / d.segments * i) + 'deg'
|
205
|
+
}).append($('<stroke>', {color: d.color, weight: d.width + 'px', endcap: 'round', opacity: $.fn.activity.getOpacity(d, i)})));
|
206
|
+
}
|
207
|
+
return $('<group>', {coordsize: s + ' ' + s}).css({width: s, height: s, overflow: 'hidden'}).append(el);
|
208
|
+
};
|
209
|
+
|
210
|
+
/**
|
211
|
+
* Animation strategy that modifies the VML rotation property using setInterval().
|
212
|
+
*/
|
213
|
+
animate = function(el, steps, duration) {
|
214
|
+
var rotation = 0;
|
215
|
+
var g = el.get(0);
|
216
|
+
el.data('interval', setInterval(function() {
|
217
|
+
g.style.rotation = ++rotation % steps * (360 / steps);
|
218
|
+
}, duration * 1000 / steps));
|
219
|
+
};
|
220
|
+
}
|
221
|
+
$(s).remove();
|
222
|
+
}
|
223
|
+
|
224
|
+
})(jQuery);
|
data/public/js/search.js
CHANGED
@@ -129,6 +129,23 @@ $(document).ready(function(){
|
|
129
129
|
$.onedb();
|
130
130
|
});
|
131
131
|
|
132
|
+
$('input:submit').click(function(){
|
133
|
+
var button = $(this);
|
134
|
+
|
135
|
+
//prevent submitting another query while this one is being processed
|
136
|
+
button.disable();
|
137
|
+
|
138
|
+
//fetch results now
|
139
|
+
$.post('', $('form').serialize(), function(data){
|
140
|
+
$('#result').html(data);
|
141
|
+
location.hash = '#result';
|
142
|
+
|
143
|
+
//result of previous query loaded; allow submitting a new query now
|
144
|
+
button.enable();
|
145
|
+
});
|
146
|
+
return false;
|
147
|
+
});
|
148
|
+
|
132
149
|
$(window).scroll(function() {
|
133
150
|
var areaHeight = $(this).height();
|
134
151
|
|
data/sequenceserver.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
# meta
|
3
3
|
s.name = 'sequenceserver'
|
4
|
-
s.version = '0.6.
|
4
|
+
s.version = '0.6.9'
|
5
5
|
s.authors = ['Anurag Priyam', 'Ben J Woodcroft', 'Yannick Wurm']
|
6
6
|
s.email = 'anurag08priyam@gmail.com'
|
7
7
|
s.homepage = 'http://sequenceserver.com'
|
@@ -13,6 +13,7 @@ SequenceServer lets you rapidly set up a BLAST+ server with an intuitive user in
|
|
13
13
|
DESC
|
14
14
|
|
15
15
|
# dependencies
|
16
|
+
s.add_dependency('bundler')
|
16
17
|
s.add_dependency('sinatra', '>= 1.2.0')
|
17
18
|
s.add_dependency('ptools')
|
18
19
|
|
data/views/search.erb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html lang="en">
|
3
3
|
<head>
|
4
|
-
<title>SequenceServer</title>
|
4
|
+
<title>SequenceServer: Custom BLAST Server</title>
|
5
5
|
<meta name="author" content="Anurag Priyam" />
|
6
6
|
<meta name="author" content="Ben J. Woodcroft" />
|
7
7
|
<meta name="author" content="Yannick Wurm" />
|
8
8
|
<meta name="author" content="Cedric Wurm" />
|
9
|
+
<meta name="description" content="Custom BLAST server provided by SequenceServer (http://www.sequenceserver.com)"/>
|
9
10
|
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
|
10
11
|
<script type="text/javascript" src="<%= uri('/js/jquery.js') %>"></script>
|
11
12
|
<script type="text/javascript" src="<%= uri('/js/jquery.enablePlaceholder.min.js') %>"></script>
|
@@ -213,7 +214,7 @@
|
|
213
214
|
</div>
|
214
215
|
|
215
216
|
<div id="underbar">
|
216
|
-
<p>© <a href='http://www.sequenceserver.com'>
|
217
|
+
<p>© <a href='http://www.sequenceserver.com'>SequenceServer: BLAST search made easy!</a></p>
|
217
218
|
</div>
|
218
219
|
</div> <!-- /page -->
|
219
220
|
</div> <!-- /container -->
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequenceserver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 6
|
9
|
-
-
|
10
|
-
version: 0.6.
|
9
|
+
- 9
|
10
|
+
version: 0.6.9
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Anurag Priyam
|
@@ -17,12 +17,26 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2011-12-
|
20
|
+
date: 2011-12-16 00:00:00 Z
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
23
|
-
name:
|
23
|
+
name: bundler
|
24
24
|
prerelease: false
|
25
25
|
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: sinatra
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
26
40
|
none: false
|
27
41
|
requirements:
|
28
42
|
- - ">="
|
@@ -34,11 +48,11 @@ dependencies:
|
|
34
48
|
- 0
|
35
49
|
version: 1.2.0
|
36
50
|
type: :runtime
|
37
|
-
version_requirements: *
|
51
|
+
version_requirements: *id002
|
38
52
|
- !ruby/object:Gem::Dependency
|
39
53
|
name: ptools
|
40
54
|
prerelease: false
|
41
|
-
requirement: &
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
56
|
none: false
|
43
57
|
requirements:
|
44
58
|
- - ">="
|
@@ -48,7 +62,7 @@ dependencies:
|
|
48
62
|
- 0
|
49
63
|
version: "0"
|
50
64
|
type: :runtime
|
51
|
-
version_requirements: *
|
65
|
+
version_requirements: *id003
|
52
66
|
description: |
|
53
67
|
SequenceServer lets you rapidly set up a BLAST+ server with an intuitive user interface for use locally or over the web.
|
54
68
|
|
@@ -76,6 +90,7 @@ files:
|
|
76
90
|
- public/js/jquery.js
|
77
91
|
- public/js/jquery.enablePlaceholder.min.js
|
78
92
|
- public/js/search.js
|
93
|
+
- public/js/jquery.activity.js
|
79
94
|
- tests/test_sequencehelpers.rb
|
80
95
|
- tests/database/protein/Sinvicta2-2-3.prot.subset.fasta.pin
|
81
96
|
- tests/database/protein/Sinvicta2-2-3.prot.subset.fasta
|
@@ -140,3 +155,4 @@ specification_version: 3
|
|
140
155
|
summary: iPod of BLAST searching
|
141
156
|
test_files: []
|
142
157
|
|
158
|
+
has_rdoc:
|