galaxy-commits
Threads by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bbdeabbd8ff9/
Changeset: bbdeabbd8ff9
Branch: next-stable
User: jmchilton
Date: 2013-08-06 06:50:04
Summary: Fix tool.requires_login behvaior broken with dynamic tool box filters (sorry again Dan and thanks for the bug report).
Affected #: 1 file
diff -r 9e57b3a7cf7274b8c4b2baf9dfd1d7077c9eebc8 -r bbdeabbd8ff9e1b8e6bee32309b5bf2af5357fe2 lib/galaxy/tools/filters/__init__.py
--- a/lib/galaxy/tools/filters/__init__.py
+++ b/lib/galaxy/tools/filters/__init__.py
@@ -25,8 +25,7 @@
"""
filters = self.default_filters.copy()
- if not trans.user:
- filters[ "tool" ].append( _requires_login )
+ filters[ "tool" ].append( _handle_requires_login )
if kwds.get( "trackster", False ):
filters[ "tool" ].append( _has_trackster_conf )
@@ -59,8 +58,8 @@
return not tool.hidden
-def _requires_login( context, tool ):
- return not tool.require_login
+def _handle_requires_login( context, tool ):
+ return not tool.require_login or context.trans.user
def _has_trackster_conf( context, tool ):
https://bitbucket.org/galaxy/galaxy-central/commits/ccabe7fd484c/
Changeset: ccabe7fd484c
Branch: next-stable
User: jmchilton
Date: 2013-08-06 07:01:44
Summary: Slight simplification of logic related to implementation of tool.requires_login.
Affected #: 1 file
diff -r bbdeabbd8ff9e1b8e6bee32309b5bf2af5357fe2 -r ccabe7fd484c910ad85e7b6550e59f37ea39dfd8 lib/galaxy/tools/filters/__init__.py
--- a/lib/galaxy/tools/filters/__init__.py
+++ b/lib/galaxy/tools/filters/__init__.py
@@ -12,7 +12,7 @@
# Prepopulate dict containing filters that are always checked,
# other filters that get checked depending on context (e.g. coming from
# trackster or no user found are added in build filters).
- self.default_filters = dict( tool=[ _not_hidden ], section=[], label=[] )
+ self.default_filters = dict( tool=[ _not_hidden, _handle_requires_login ], section=[], label=[] )
# Add dynamic filters to these default filters.
config = toolbox.app.config
self.__init_filters( "tool", config.tool_filters )
@@ -25,8 +25,6 @@
"""
filters = self.default_filters.copy()
- filters[ "tool" ].append( _handle_requires_login )
-
if kwds.get( "trackster", False ):
filters[ "tool" ].append( _has_trackster_conf )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1dd1b4a87b3e/
Changeset: 1dd1b4a87b3e
User: jmchilton
Date: 2013-08-06 06:50:04
Summary: Fix tool.requires_login behvaior broken with dynamic tool box filters (sorry again Dan and thanks for the bug report).
Affected #: 1 file
diff -r 4a514b0de915b8d8ea3b9ff333d04b0907a5fb66 -r 1dd1b4a87b3eeb4c57bbf2a1362077bb4ee21dc1 lib/galaxy/tools/filters/__init__.py
--- a/lib/galaxy/tools/filters/__init__.py
+++ b/lib/galaxy/tools/filters/__init__.py
@@ -25,8 +25,7 @@
"""
filters = self.default_filters.copy()
- if not trans.user:
- filters[ "tool" ].append( _requires_login )
+ filters[ "tool" ].append( _handle_requires_login )
if kwds.get( "trackster", False ):
filters[ "tool" ].append( _has_trackster_conf )
@@ -59,8 +58,8 @@
return not tool.hidden
-def _requires_login( context, tool ):
- return not tool.require_login
+def _handle_requires_login( context, tool ):
+ return not tool.require_login or context.trans.user
def _has_trackster_conf( context, tool ):
https://bitbucket.org/galaxy/galaxy-central/commits/cf53a00bcf1d/
Changeset: cf53a00bcf1d
User: jmchilton
Date: 2013-08-06 07:01:44
Summary: Slight simplification of logic related to implementation of tool.requires_login.
Affected #: 1 file
diff -r 1dd1b4a87b3eeb4c57bbf2a1362077bb4ee21dc1 -r cf53a00bcf1d279072ec279e6531f211992b4f3e lib/galaxy/tools/filters/__init__.py
--- a/lib/galaxy/tools/filters/__init__.py
+++ b/lib/galaxy/tools/filters/__init__.py
@@ -12,7 +12,7 @@
# Prepopulate dict containing filters that are always checked,
# other filters that get checked depending on context (e.g. coming from
# trackster or no user found are added in build filters).
- self.default_filters = dict( tool=[ _not_hidden ], section=[], label=[] )
+ self.default_filters = dict( tool=[ _not_hidden, _handle_requires_login ], section=[], label=[] )
# Add dynamic filters to these default filters.
config = toolbox.app.config
self.__init_filters( "tool", config.tool_filters )
@@ -25,8 +25,6 @@
"""
filters = self.default_filters.copy()
- filters[ "tool" ].append( _handle_requires_login )
-
if kwds.get( "trackster", False ):
filters[ "tool" ].append( _has_trackster_conf )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: When deleting histories, go to default history (unnamed, no datasets) if available and create new history only if necessary.
by commits-noreply@bitbucket.org 05 Aug '13
by commits-noreply@bitbucket.org 05 Aug '13
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4a514b0de915/
Changeset: 4a514b0de915
User: jgoecks
Date: 2013-08-06 01:06:40
Summary: When deleting histories, go to default history (unnamed, no datasets) if available and create new history only if necessary.
Affected #: 3 files
diff -r 2a5554c53aead0373e26eacdffc75e5c713bd721 -r 4a514b0de915b8d8ea3b9ff333d04b0907a5fb66 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -666,10 +666,11 @@
api_collection_visible_keys = ( 'id', 'name', 'published', 'deleted' )
api_element_visible_keys = ( 'id', 'name', 'published', 'deleted', 'genome_build', 'purged' )
+ default_name = 'Unnamed history'
def __init__( self, id=None, name=None, user=None ):
self.id = id
- self.name = name or "Unnamed history"
+ self.name = name or History.default_name
self.deleted = False
self.purged = False
self.importing = False
diff -r 2a5554c53aead0373e26eacdffc75e5c713bd721 -r 4a514b0de915b8d8ea3b9ff333d04b0907a5fb66 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -832,6 +832,39 @@
history = property( get_history, set_history )
+ def get_or_create_default_history( self ):
+ """
+ Gets or creates a default history and associates it with the current
+ session.
+ """
+
+ # There must be a user to fetch a default history.
+ if not self.galaxy_session.user:
+ return self.new_history()
+
+ # Look for default history that (a) has default name + is not deleted and
+ # (b) has no datasets. If suitable history found, use it; otherwise, create
+ # new history.
+ unnamed_histories = self.sa_session.query( self.app.model.History ).filter_by(
+ user=self.galaxy_session.user,
+ name=self.app.model.History.default_name,
+ deleted=False )
+ default_history = None
+ for history in unnamed_histories:
+ if len( history.datasets ) == 0:
+ # Found suitable default history.
+ default_history = history
+ break
+
+ # Set or create hsitory.
+ if default_history:
+ history = default_history
+ self.set_history( history )
+ else:
+ history = self.new_history()
+
+ return history
+
def new_history( self, name=None ):
"""
Create a new history and associate it with the current session and
diff -r 2a5554c53aead0373e26eacdffc75e5c713bd721 -r 4a514b0de915b8d8ea3b9ff333d04b0907a5fb66 lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -309,7 +309,7 @@
# If deleting the current history, make a new current.
if history == trans.get_history():
deleted_current = True
- trans.new_history()
+ trans.get_or_create_default_history()
trans.log_event( "History (%s) marked as deleted" % history.name )
n_deleted += 1
if purge and trans.app.config.allow_user_dataset_purge:
@@ -571,8 +571,8 @@
# No need to check other outputs since the job's parent history is this history
job.mark_deleted( trans.app.config.track_jobs_in_database )
trans.app.job_manager.job_stop_queue.put( job.id )
- # Regardless of whether it was previously deleted, we make a new history active
- trans.new_history()
+ # Regardless of whether it was previously deleted, get or create default history.
+ trans.get_or_create_default_history()
return trans.show_ok_message( "History deleted, a new history is active", refresh_frames=['history'] )
@web.expose
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2a5554c53aea/
Changeset: 2a5554c53aea
User: natefoo
Date: 2013-08-05 23:15:31
Summary: Merge next-stable.
Affected #: 1 file
diff -r 20e2d056b843504ea77c49adc0cb08818bb7bdc6 -r 2a5554c53aead0373e26eacdffc75e5c713bd721 lib/galaxy/jobs/runners/pbs.py
--- a/lib/galaxy/jobs/runners/pbs.py
+++ b/lib/galaxy/jobs/runners/pbs.py
@@ -588,8 +588,8 @@
def stop_job( self, job ):
"""Attempts to delete a job from the PBS queue"""
- job_tag = ( "(%s/%s)"
- % ( job.get_id_tag(), job.get_job_runner_external_id() ) )
+ job_id = job.get_job_runner_external_id().encode('utf-8')
+ job_tag = "(%s/%s)" % ( job.get_id_tag(), job_id )
log.debug( "%s Stopping PBS job" % job_tag )
# Declare the connection handle c so that it can be cleaned up:
@@ -606,7 +606,7 @@
log.debug("(%s) Connection to PBS server for job delete failed"
% job_tag )
return
- pbs.pbs_deljob( c, job.get_job_runner_external_id(), '' )
+ pbs.pbs_deljob( c, job_id, '' )
log.debug( "%s Removed from PBS queue before job completion"
% job_tag )
except:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Bugfix for stopping jobs with the PBS plugin.
by commits-noreply@bitbucket.org 05 Aug '13
by commits-noreply@bitbucket.org 05 Aug '13
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9e57b3a7cf72/
Changeset: 9e57b3a7cf72
Branch: next-stable
User: natefoo
Date: 2013-08-05 23:15:12
Summary: Bugfix for stopping jobs with the PBS plugin.
Affected #: 1 file
diff -r 6053d0aa63cc1e9f295c7a36787d064d754de7ef -r 9e57b3a7cf7274b8c4b2baf9dfd1d7077c9eebc8 lib/galaxy/jobs/runners/pbs.py
--- a/lib/galaxy/jobs/runners/pbs.py
+++ b/lib/galaxy/jobs/runners/pbs.py
@@ -588,8 +588,8 @@
def stop_job( self, job ):
"""Attempts to delete a job from the PBS queue"""
- job_tag = ( "(%s/%s)"
- % ( job.get_id_tag(), job.get_job_runner_external_id() ) )
+ job_id = job.get_job_runner_external_id().encode('utf-8')
+ job_tag = "(%s/%s)" % ( job.get_id_tag(), job_id )
log.debug( "%s Stopping PBS job" % job_tag )
# Declare the connection handle c so that it can be cleaned up:
@@ -606,7 +606,7 @@
log.debug("(%s) Connection to PBS server for job delete failed"
% job_tag )
return
- pbs.pbs_deljob( c, job.get_job_runner_external_id(), '' )
+ pbs.pbs_deljob( c, job_id, '' )
log.debug( "%s Removed from PBS queue before job completion"
% job_tag )
except:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Tophat2 wrapper enhancements: (a) better error handling; (b) include alignment statistics in output; and (c) document compatible tool versions.
by commits-noreply@bitbucket.org 05 Aug '13
by commits-noreply@bitbucket.org 05 Aug '13
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/20e2d056b843/
Changeset: 20e2d056b843
User: jgoecks
Date: 2013-08-05 23:08:28
Summary: Tophat2 wrapper enhancements: (a) better error handling; (b) include alignment statistics in output; and (c) document compatible tool versions.
Affected #: 1 file
diff -r af1daa86ba5b713240fb3f7ccd607f3adb8c05a7 -r 20e2d056b843504ea77c49adc0cb08818bb7bdc6 tools/ngs_rna/tophat2_wrapper.xml
--- a/tools/ngs_rna/tophat2_wrapper.xml
+++ b/tools/ngs_rna/tophat2_wrapper.xml
@@ -1,5 +1,5 @@
-<tool id="tophat2" name="Tophat2" version="0.5">
- <!-- Wrapper compatible with Tophat version 2.0.0 -->
+<tool id="tophat2" name="Tophat2" version="0.6">
+ <!-- Wrapper compatible with Tophat version 2.0.0+ --><description>Gapped-read mapper for RNA-seq data</description><version_command>tophat2 --version</version_command><requirements>
@@ -268,11 +268,12 @@
</inputs><stdio>
- <regex match="Exception" source="both" level="fatal" description="Tool exception"/>
+ <regex match="Exception|Error" source="both" level="fatal" description="Tool execution failed"/><regex match=".*" source="both" level="log" description="tool progress"/></stdio><outputs>
+ <data format="txt" name="align_summary" label="${tool.name} on ${on_string}: align_summary" from_work_dir="tophat_out/align_summary.txt"/><data format="tabular" name="fusions" label="${tool.name} on ${on_string}: fusions" from_work_dir="tophat_out/fusions.out"><filter>(params['settingsType'] == 'full' and params['fusion_search']['do_search'] == 'Yes')</filter></data>
@@ -312,6 +313,7 @@
</actions></macro></macros>
+
<tests><!-- Test base-space single-end reads with pre-built index and preset parameters --><test>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/af1daa86ba5b/
Changeset: af1daa86ba5b
User: guerler
Date: 2013-08-05 23:04:50
Summary: Pack JS-scripts
Affected #: 5 files
diff -r ba8555d1fed4b95e2882afd33c45be3300c00ded -r af1daa86ba5b713240fb3f7ccd607f3adb8c05a7 static/scripts/packed/mvc/ui.js
--- a/static/scripts/packed/mvc/ui.js
+++ b/static/scripts/packed/mvc/ui.js
@@ -1,1 +1,1 @@
-var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.attributes);a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(this.model.attributes.on_click){this.model.attributes.on_click(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}if(b.title){a+=" tooltip"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var GalaxyPaths=Backbone.Model.extend({defaults:{root_path:"",image_path:""}});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b||$("<div/>");this.options=a||[];var c=this;this.$button.click(function(d){c._renderAndShow(d);return false});this.$button.data("PopupMenu",this)},render:function(){var a=this;this.$el.addClass("popmenu-wrapper").css({position:"absolute",display:"none"});this.$el.html(PopupMenu.templates.menu({options:this.options,id:this.$button.attr("id")}));if(this.options.length){this.$el.find("li").each(function(c,b){var f=$(b),e=f.children("a.popupmenu-option"),d=a.options[c].func;if(e.length&&d){e.click(function(g){d(g,a.options[c])})}a.options[c].$li=f})}return this},_getShownPosition:function(b){var c=this.$el.width(),a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_renderAndShow:function(a){this.render();this.$el.appendTo("body");this.$el.css(this._getShownPosition(a));this._setUpCloseBehavior();this.$el.show()},_setUpCloseBehavior:function(){var b=this,a=function(c){c.bind("click.close_popup",function(){b.remove();c.unbind("click.close_popup")})};a($(window.document));a($(window.top.document));_.each(window.top.frames,function(c){a($(c.document))})},addItem:function(b,a){a=(a>=0)?(a):(this.options.length);this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if((_.has(this.options[a],"html"))&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.templates={menu:Handlebars.templates["template-popupmenu-menu"]};PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(j){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}var i;switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;case"demo":if(i===undefined||i.closed){i=window.open(j,k);i.creator=self}break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};
\ No newline at end of file
+var GalaxyPaths=Backbone.Model.extend({defaults:{root_path:"",image_path:""}});var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.attributes);a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(this.model.attributes.on_click){this.model.attributes.on_click(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}if(b.title){a+=" tooltip"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b||$("<div/>");this.options=a||[];var c=this;this.$button.click(function(d){c._renderAndShow(d);return false});this.$button.data("PopupMenu",this)},render:function(){var a=this;this.$el.addClass("popmenu-wrapper").css({position:"absolute",display:"none"});this.$el.html(this.template(this.$button.attr("id"),this.options));if(this.options.length){this.$el.find("li").each(function(c,b){var f=$(b),e=f.children("a.popupmenu-option"),d=a.options[c].func;if(e.length&&d){e.click(function(g){d(g,a.options[c])})}a.options[c].$li=f})}return this},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_renderAndShow:function(a){this.render();this.$el.appendTo("body");this.$el.css(this._getShownPosition(a));this._setUpCloseBehavior();this.$el.show()},_setUpCloseBehavior:function(){var b=this;var a=function(c){c.bind("click.close_popup",function(){b.remove();c.unbind("click.close_popup")})};a($(window.document));a($(window.top.document));_.each(window.top.frames,function(c){a($(c.document))})},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"},template:function(e,b){var a='<ul id="'+e+'-menu" class="dropdown-menu">';if(b.length>0){for(var c in b){var d=b[c];if(d.divider){a+='<li class="divider"></li>'}else{if(d.header){a+='<li class="head"><a href="javascript:void(0);">'+d.html+"</a></li>"}else{if(d.href){a+='<li><a href="'+d.href+'"';a+='target="'+d.target+'"'}else{a+='<li><a href="javascript:void(0);"'}a+='class="popupmenu-option">';if(d.checked){a+='<span class="fa-icon-ok"></span>'}a+=d.html}}}}else{a+="<li>No Options.</li>"}return a+"</ul>"}});PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(j){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}var i;switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;case"demo":if(i===undefined||i.closed){i=window.open(j,k);i.creator=self}break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};
\ No newline at end of file
diff -r ba8555d1fed4b95e2882afd33c45be3300c00ded -r af1daa86ba5b713240fb3f7ccd607f3adb8c05a7 static/scripts/packed/viz/circster.js
--- a/static/scripts/packed/viz/circster.js
+++ b/static/scripts/packed/viz/circster.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","libs/d3","viz/visualization"],function(f,k,h){var l=Backbone.Model.extend({is_visible:function(p,m){var n=p.getBoundingClientRect(),o=$("svg")[0].getBoundingClientRect();if(n.right<0||n.left>o.right||n.bottom<0||n.top>o.bottom){return false}return true}});var g={drawTicks:function(q,p,u,o,m){var t=q.append("g").selectAll("g").data(p).enter().append("g").selectAll("g").data(u).enter().append("g").attr("class","tick").attr("transform",function(v){return"rotate("+(v.angle*180/Math.PI-90)+")translate("+v.radius+",0)"});var s=[],r=[],n=function(v){return v.angle>Math.PI?"end":null};if(m){s=[0,0,0,-4];r=[4,0,"",".35em"];n=null}else{s=[1,0,4,0];r=[0,4,".35em",""]}t.append("line").attr("x1",s[0]).attr("y1",s[1]).attr("x2",s[2]).attr("y1",s[3]).style("stroke","#000");t.append("text").attr("x",r[0]).attr("y",r[1]).attr("dx",r[2]).attr("dy",r[3]).attr("text-anchor",n).attr("transform",o).text(function(v){return v.label})},formatNum:function(n,m){if(m===undefined){m=2}var p=null;if(n<1){p=n.toPrecision(m)}else{var o=Math.round(n.toPrecision(m));if(n<1000){p=o}else{if(n<1000000){p=Math.round((o/1000).toPrecision(3)).toFixed(0)+"K"}else{if(n<1000000000){p=Math.round((o/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return p}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(m){this.total_gap=m.total_gap;this.genome=m.genome;this.dataset_arc_height=m.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(m){return m.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(m){return m.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var n=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-n.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=k.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var m=this;return f.map(tracks_start_radii,function(o){return[o,o+m.dataset_arc_height]})},render:function(){var v=this,p=this.dataset_arc_height,m=v.$el.width(),u=v.$el.height(),r=this.get_circular_tracks(),o=this.get_chord_tracks(),q=this.get_tracks_bounds(),n=k.select(v.$el[0]).append("svg").attr("width",m).attr("height",u).attr("pointer-events","all").append("svg:g").call(k.behavior.zoom().on("zoom",function(){var w=k.event.scale;n.attr("transform","translate("+k.event.translate+") scale("+w+")");if(v.scale!==w){if(v.zoom_drag_timeout){clearTimeout(v.zoom_drag_timeout)}v.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+m/2+","+u/2+")").append("svg:g").attr("class","tracks");this.circular_views=r.map(function(x,y){var w=new d({el:n.append("g")[0],track:x,radius_bounds:q[y],genome:v.genome,total_gap:v.total_gap});w.render();return w});this.chords_views=o.map(function(x){var w=new i({el:n.append("g")[0],track:x,radius_bounds:q[0],genome:v.genome,total_gap:v.total_gap});w.render();return w});var t=this.circular_views[this.circular_views.length-1].radius_bounds[1],s=[t,t+this.label_arc_height];this.label_track_view=new b({el:n.append("g")[0],track:new c(),radius_bounds:s,genome:v.genome,total_gap:v.total_gap});this.label_track_view.render()},add_track:function(s){if(s.get("track_type")==="DiagonalHeatmapTrack"){var o=this.circular_views[0].radius_bounds,r=new i({el:k.select("g.tracks").append("g")[0],track:s,radius_bounds:o,genome:this.genome,total_gap:this.total_gap});r.render();this.chords_views.push(r)}else{var q=this.get_tracks_bounds();f.each(this.circular_views,function(t,u){t.update_radius_bounds(q[u])});f.each(this.chords_views,function(t){t.update_radius_bounds(q[0])});var p=this.circular_views.length,m=new d({el:k.select("g.tracks").append("g")[0],track:s,radius_bounds:q[p],genome:this.genome,total_gap:this.total_gap});m.render();this.circular_views.push(m);var n=q[q.length-1];n[1]=n[0];this.label_track_view.update_radius_bounds(n)}},remove_track:function(n,p,o){var m=this.circular_views[o.index];this.circular_views.splice(o.index,1);m.$el.remove();var q=this.get_tracks_bounds();f.each(this.circular_views,function(r,s){r.update_radius_bounds(q[s])})}});var j=Backbone.View.extend({tagName:"g",initialize:function(m){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=m.total_gap;this.track=m.track;this.radius_bounds=m.radius_bounds;this.genome=m.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=k.select(this.$el[0])},get_fill_color:function(){var m=this.track.get("config").get_value("block_color");if(!m){m=this.track.get("config").get_value("color")}return m},render:function(){var q=this.parent_elt;if(!q){console.log("no parent elt")}var p=this.chroms_layout,s=k.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),m=q.selectAll("g").data(p).enter().append("svg:g"),o=m.append("path").attr("d",s).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);o.append("title").text(function(u){return u.data.chrom});var n=this,r=n.track.get("data_manager"),t=(r?r.data_is_ready():true);$.when(t).then(function(){$.when(n._render_data(q)).then(function(){o.style("fill",n.bg_fill);n.render_labels()})})},render_labels:function(){},update_radius_bounds:function(n){this.radius_bounds=n;var m=k.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",m);this._transition_chrom_data();this._transition_labels()},update_scale:function(p){var o=this.scale;this.scale=p;if(p<=o){return}var n=this,m=new l();this.parent_elt.selectAll("path.chrom-data").filter(function(r,q){return m.is_visible(this)}).each(function(w,s){var v=k.select(this),r=v.attr("chrom"),u=n.genome.get_chrom_region(r),t=n.track.get("data_manager"),q;if(!t.can_get_more_detailed_data(u)){return}q=n.track.get("data_manager").get_more_detailed_data(u,"Coverage",0,p);$.when(q).then(function(z){v.remove();n._update_data_bounds();var y=f.find(n.chroms_layout,function(A){return A.data.chrom===r});var x=n.get_fill_color();n._render_chrom_data(n.parent_elt,y,z).style("stroke",x).style("fill",x)})});return n},_transition_chrom_data:function(){var n=this.track,p=this.chroms_layout,m=this.parent_elt.selectAll("g>path.chrom-data"),q=m[0].length;if(q>0){var o=this;$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(s){var r=f.reject(f.map(s,function(t,u){var v=null,w=o._get_path_function(p[u],t);if(w){v=w(t.data)}return v}),function(t){return t===null});m.each(function(u,t){k.select(this).transition().duration(1000).attr("d",r[t])})})}},_transition_labels:function(){},_update_data_bounds:function(){var m=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<m[0]||this.data_bounds[1]>m[1]){this._transition_chrom_data()}},_render_data:function(p){var o=this,n=this.chroms_layout,m=this.track,q=$.Deferred();$.when(m.get("data_manager").get_genome_wide_data(this.genome)).then(function(s){o.data_bounds=o.get_data_bounds(s);layout_and_data=f.zip(n,s),chroms_data_layout=f.map(layout_and_data,function(t){var u=t[0],v=t[1];return o._render_chrom_data(p,u,v)});var r=o.get_fill_color();o.parent_elt.selectAll("path.chrom-data").style("stroke",r).style("fill",r);q.resolve(p)});return q},_render_chrom_data:function(m,n,o){},_get_path_function:function(n,m){},_chroms_layout:function(){var n=this.genome.get_chroms_info(),p=k.layout.pie().value(function(r){return r.len}).sort(null),q=p(n),m=this.total_gap/n.length,o=f.map(q,function(t,s){var r=t.endAngle-m;t.endAngle=(r>t.startAngle?r:t.startAngle);return t});return o}});var b=j.extend({initialize:function(m){j.prototype.initialize.call(this,m);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(o){var n=this,m=o.selectAll("g");m.selectAll("path").attr("id",function(s){return"label-"+s.data.chrom});m.append("svg:text").filter(function(s){return s.endAngle-s.startAngle>n.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(s){return"#label-"+s.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(s){return s.data.chrom});var p=function(u){var s=(u.endAngle-u.startAngle)/u.value,t=k.range(0,u.value,25000000).map(function(w,x){return{radius:n.innerRadius,angle:w*s+u.startAngle,label:x===0?0:(x%3?null:n.formatNum(w))}});if(t.length<4){t[t.length-1].label=n.formatNum(Math.round((t[t.length-1].angle-u.startAngle)/s))}return t};var r=function(s){return s.angle>Math.PI?"rotate(180)translate(-16)":null};var q=f.filter(this.chroms_layout,function(s){return s.endAngle-s.startAngle>n.min_arc_len});this.drawTicks(this.parent_elt,q,p,r)}});f.extend(b.prototype,g);var e=j.extend({_quantile:function(n,m){n.sort(k.ascending);return k.quantile(n,m)},_render_chrom_data:function(m,p,n){var q=this._get_path_function(p,n);if(!q){return null}var o=m.datum(n.data),r=o.append("path").attr("class","chrom-data").attr("chrom",p.data.chrom).attr("d",q);return r},_get_path_function:function(p,o){if(typeof o==="string"||!o.data||o.data.length===0){return null}var m=k.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var q=k.scale.linear().domain([0,o.data.length]).range([p.startAngle,p.endAngle]);var n=k.svg.line.radial().interpolate("linear").radius(function(r){return m(r[1])}).angle(function(s,r){return q(r)});return k.svg.area.radial().interpolate(n.interpolate()).innerRadius(m(0)).outerRadius(n.radius()).angle(n.angle())},render_labels:function(){var m=this,p=function(){return"rotate(90)"};var o=f.filter(this.chroms_layout,function(q){return q.endAngle-q.startAngle>0.08}),n=f.filter(o,function(r,q){return q%3===0});this.drawTicks(this.parent_elt,n,this._data_bounds_ticks_fn(),p,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var n=this,p=f.filter(this.chroms_layout,function(q){return q.endAngle-q.startAngle>0.08}),o=f.filter(p,function(r,q){return q%3===0}),m=f.flatten(f.map(o,function(q){return n._data_bounds_ticks_fn()(q)}));this.parent_elt.selectAll("g.tick").data(m).transition().attr("transform",function(q){return"rotate("+(q.angle*180/Math.PI-90)+")translate("+q.radius+",0)"})},_data_bounds_ticks_fn:function(){var m=this;visibleChroms=0;return function(n){return[{radius:m.radius_bounds[0],angle:n.startAngle,label:m.formatNum(m.data_bounds[0])},{radius:m.radius_bounds[1],angle:n.startAngle,label:m.formatNum(m.data_bounds[1])}]}},get_data_bounds:function(m){}});f.extend(e.prototype,g);var d=e.extend({get_data_bounds:function(n){var m=f.flatten(f.map(n,function(o){if(o){return f.map(o.data,function(q){return q[1]})}else{return 0}}));return[f.min(m),this._quantile(m,0.98)]}});var i=j.extend({render:function(){var m=this;$.when(m.track.get("data_manager").data_is_ready()).then(function(){$.when(m.track.get("data_manager").get_genome_wide_data(m.genome)).then(function(p){var o=[],n=m.genome.get_chroms_info();f.each(p,function(t,s){var q=n[s].chrom;var r=f.map(t.data,function(v){var u=m._get_region_angle(q,v[1]),w=m._get_region_angle(v[3],v[4]);return{source:{startAngle:u,endAngle:u+0.01},target:{startAngle:w,endAngle:w+0.01}}});o=o.concat(r)});m.parent_elt.append("g").attr("class","chord").selectAll("path").data(o).enter().append("path").style("fill",m.get_fill_color()).attr("d",k.svg.chord().radius(m.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(m){this.radius_bounds=m;this.parent_elt.selectAll("path").transition().attr("d",k.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(o,m){var n=f.find(this.chroms_layout,function(p){return p.data.chrom===o});return n.endAngle-((n.endAngle-n.startAngle)*(n.data.len-m)/n.data.len)}});return{CircsterView:a}});
\ No newline at end of file
+define(["libs/underscore","libs/d3","viz/visualization"],function(g,l,i){var m=Backbone.Model.extend({is_visible:function(q,n){var o=q.getBoundingClientRect(),p=$("svg")[0].getBoundingClientRect();if(o.right<0||o.left>p.right||o.bottom<0||o.top>p.bottom){return false}return true}});var h={drawTicks:function(r,q,v,p,n){var u=r.append("g").selectAll("g").data(q).enter().append("g").selectAll("g").data(v).enter().append("g").attr("class","tick").attr("transform",function(w){return"rotate("+(w.angle*180/Math.PI-90)+")translate("+w.radius+",0)"});var t=[],s=[],o=function(w){return w.angle>Math.PI?"end":null};if(n){t=[0,0,0,-4];s=[4,0,"",".35em"];o=null}else{t=[1,0,4,0];s=[0,4,".35em",""]}u.append("line").attr("x1",t[0]).attr("y1",t[1]).attr("x2",t[2]).attr("y1",t[3]).style("stroke","#000");u.append("text").attr("x",s[0]).attr("y",s[1]).attr("dx",s[2]).attr("dy",s[3]).attr("text-anchor",o).attr("transform",p).text(function(w){return w.label})},formatNum:function(o,n){if(n===undefined){n=2}var q=null;if(o<1){q=o.toPrecision(n)}else{var p=Math.round(o.toPrecision(n));if(o<1000){q=p}else{if(o<1000000){q=Math.round((p/1000).toPrecision(3)).toFixed(0)+"K"}else{if(o<1000000000){q=Math.round((p/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return q}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(n){this.total_gap=n.total_gap;this.genome=n.genome;this.dataset_arc_height=n.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var o=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-o.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=l.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var n=this;return g.map(tracks_start_radii,function(p){return[p,p+n.dataset_arc_height]})},render:function(){var w=this,q=this.dataset_arc_height,n=w.$el.width(),v=w.$el.height(),s=this.get_circular_tracks(),p=this.get_chord_tracks(),r=this.get_tracks_bounds(),o=l.select(w.$el[0]).append("svg").attr("width",n).attr("height",v).attr("pointer-events","all").append("svg:g").call(l.behavior.zoom().on("zoom",function(){var x=l.event.scale;o.attr("transform","translate("+l.event.translate+") scale("+x+")");if(w.scale!==x){if(w.zoom_drag_timeout){clearTimeout(w.zoom_drag_timeout)}w.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+n/2+","+v/2+")").append("svg:g").attr("class","tracks");this.circular_views=s.map(function(y,z){var x=new d({el:o.append("g")[0],track:y,radius_bounds:r[z],genome:w.genome,total_gap:w.total_gap});x.render();return x});this.chords_views=p.map(function(y){var x=new j({el:o.append("g")[0],track:y,radius_bounds:r[0],genome:w.genome,total_gap:w.total_gap});x.render();return x});var u=this.circular_views[this.circular_views.length-1].radius_bounds[1],t=[u,u+this.label_arc_height];this.label_track_view=new b({el:o.append("g")[0],track:new c(),radius_bounds:t,genome:w.genome,total_gap:w.total_gap});this.label_track_view.render()},add_track:function(t){if(t.get("track_type")==="DiagonalHeatmapTrack"){var p=this.circular_views[0].radius_bounds,s=new j({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:p,genome:this.genome,total_gap:this.total_gap});s.render();this.chords_views.push(s)}else{var r=this.get_tracks_bounds();g.each(this.circular_views,function(u,v){u.update_radius_bounds(r[v])});g.each(this.chords_views,function(u){u.update_radius_bounds(r[0])});var q=this.circular_views.length,n=new d({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:r[q],genome:this.genome,total_gap:this.total_gap});n.render();this.circular_views.push(n);var o=r[r.length-1];o[1]=o[0];this.label_track_view.update_radius_bounds(o)}},remove_track:function(o,q,p){var n=this.circular_views[p.index];this.circular_views.splice(p.index,1);n.$el.remove();var r=this.get_tracks_bounds();g.each(this.circular_views,function(s,t){s.update_radius_bounds(r[t])})}});var k=Backbone.View.extend({tagName:"g",initialize:function(n){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=n.total_gap;this.track=n.track;this.radius_bounds=n.radius_bounds;this.genome=n.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=l.select(this.$el[0])},get_fill_color:function(){var n=this.track.get("config").get_value("block_color");if(!n){n=this.track.get("config").get_value("color")}return n},render:function(){var r=this.parent_elt;if(!r){console.log("no parent elt")}var q=this.chroms_layout,t=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),n=r.selectAll("g").data(q).enter().append("svg:g"),p=n.append("path").attr("d",t).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var o=this,s=o.track.get("data_manager"),u=(s?s.data_is_ready():true);$.when(u).then(function(){$.when(o._render_data(r)).then(function(){p.style("fill",o.bg_fill);o.render_labels()})})},render_labels:function(){},update_radius_bounds:function(o){this.radius_bounds=o;var n=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",n);this._transition_chrom_data();this._transition_labels()},update_scale:function(q){var p=this.scale;this.scale=q;if(q<=p){return}var o=this,n=new m();this.parent_elt.selectAll("path.chrom-data").filter(function(s,r){return n.is_visible(this)}).each(function(x,t){var w=l.select(this),s=w.attr("chrom"),v=o.genome.get_chrom_region(s),u=o.track.get("data_manager"),r;if(!u.can_get_more_detailed_data(v)){return}r=o.track.get("data_manager").get_more_detailed_data(v,"Coverage",0,q);$.when(r).then(function(A){w.remove();o._update_data_bounds();var z=g.find(o.chroms_layout,function(B){return B.data.chrom===s});var y=o.get_fill_color();o._render_chrom_data(o.parent_elt,z,A).style("stroke",y).style("fill",y)})});return o},_transition_chrom_data:function(){var o=this.track,q=this.chroms_layout,n=this.parent_elt.selectAll("g>path.chrom-data"),r=n[0].length;if(r>0){var p=this;$.when(o.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=p._get_path_function(q[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});n.each(function(v,u){l.select(this).transition().duration(1000).attr("d",s[u])})})}},_transition_labels:function(){},_update_data_bounds:function(){var n=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<n[0]||this.data_bounds[1]>n[1]){this._transition_chrom_data()}},_render_data:function(q){var p=this,o=this.chroms_layout,n=this.track,r=$.Deferred();$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){p.data_bounds=p.get_data_bounds(t);layout_and_data=g.zip(o,t),chroms_data_layout=g.map(layout_and_data,function(u){var v=u[0],w=u[1];return p._render_chrom_data(q,v,w)});var s=p.get_fill_color();p.parent_elt.selectAll("path.chrom-data").style("stroke",s).style("fill",s);r.resolve(q)});return r},_render_chrom_data:function(n,o,p){},_get_path_function:function(o,n){},_chroms_layout:function(){var o=this.genome.get_chroms_info(),q=l.layout.pie().value(function(s){return s.len}).sort(null),r=q(o),n=this.total_gap/o.length,p=g.map(r,function(u,t){var s=u.endAngle-n;u.endAngle=(s>u.startAngle?s:u.startAngle);return u});return p}});var b=k.extend({initialize:function(n){k.prototype.initialize.call(this,n);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(p){var o=this,n=p.selectAll("g");n.selectAll("path").attr("id",function(t){return"label-"+t.data.chrom});n.append("svg:text").filter(function(t){return t.endAngle-t.startAngle>o.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(t){return"#label-"+t.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(t){return t.data.chrom});var q=function(v){var t=(v.endAngle-v.startAngle)/v.value,u=l.range(0,v.value,25000000).map(function(w,x){return{radius:o.innerRadius,angle:w*t+v.startAngle,label:x===0?0:(x%3?null:o.formatNum(w))}});if(u.length<4){u[u.length-1].label=o.formatNum(Math.round((u[u.length-1].angle-v.startAngle)/t))}return u};var s=function(t){return t.angle>Math.PI?"rotate(180)translate(-16)":null};var r=g.filter(this.chroms_layout,function(t){return t.endAngle-t.startAngle>o.min_arc_len});this.drawTicks(this.parent_elt,r,q,s)}});g.extend(b.prototype,h);var f=k.extend({_quantile:function(o,n){o.sort(l.ascending);return l.quantile(o,n)},_render_chrom_data:function(n,q,o){var r=this._get_path_function(q,o);if(!r){return null}var p=n.datum(o.data),s=p.append("path").attr("class","chrom-data").attr("chrom",q.data.chrom).attr("d",r);return s},_get_path_function:function(q,p){if(typeof p==="string"||!p.data||p.data.length===0){return null}var n=l.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var r=l.scale.linear().domain([0,p.data.length]).range([q.startAngle,q.endAngle]);var o=l.svg.line.radial().interpolate("linear").radius(function(s){return n(s[1])}).angle(function(t,s){return r(s)});return l.svg.area.radial().interpolate(o.interpolate()).innerRadius(n(0)).outerRadius(o.radius()).angle(o.angle())},render_labels:function(){var n=this,q=function(){return"rotate(90)"};var p=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),o=g.filter(p,function(s,r){return r%3===0});this.drawTicks(this.parent_elt,o,this._data_bounds_ticks_fn(),q,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var o=this,q=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),p=g.filter(q,function(s,r){return r%3===0}),n=g.flatten(g.map(p,function(r){return o._data_bounds_ticks_fn()(r)}));this.parent_elt.selectAll("g.tick").data(n).transition().attr("transform",function(r){return"rotate("+(r.angle*180/Math.PI-90)+")translate("+r.radius+",0)"})},_data_bounds_ticks_fn:function(){var n=this;visibleChroms=0;return function(o){return[{radius:n.radius_bounds[0],angle:o.startAngle,label:n.formatNum(n.data_bounds[0])},{radius:n.radius_bounds[1],angle:o.startAngle,label:n.formatNum(n.data_bounds[1])}]}},get_data_bounds:function(n){}});g.extend(f.prototype,h);var d=f.extend({get_data_bounds:function(o){var n=g.flatten(g.map(o,function(p){if(p){return g.map(p.data,function(q){return q[1]})}else{return 0}}));return[g.min(n),this._quantile(n,0.98)]}});var j=k.extend({render:function(){var n=this;$.when(n.track.get("data_manager").data_is_ready()).then(function(){$.when(n.track.get("data_manager").get_genome_wide_data(n.genome)).then(function(q){var p=[],o=n.genome.get_chroms_info();g.each(q,function(u,t){var r=o[t].chrom;var s=g.map(u.data,function(w){var v=n._get_region_angle(r,w[1]),x=n._get_region_angle(w[3],w[4]);return{source:{startAngle:v,endAngle:v+0.01},target:{startAngle:x,endAngle:x+0.01}}});p=p.concat(s)});n.parent_elt.append("g").attr("class","chord").selectAll("path").data(p).enter().append("path").style("fill",n.get_fill_color()).attr("d",l.svg.chord().radius(n.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(n){this.radius_bounds=n;this.parent_elt.selectAll("path").transition().attr("d",l.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(p,n){var o=g.find(this.chroms_layout,function(q){return q.data.chrom===p});return o.endAngle-((o.endAngle-o.startAngle)*(o.data.len-n)/o.data.len)}});var e=Backbone.View.extend({initialize:function(){var n=new i.Genome(config.app.genome),o=new i.GenomeVisualization(config.app.viz_config),q=new a({el:$("#center .unified-panel-body"),total_gap:2*Math.PI*0.1,genome:n,model:o,dataset_arc_height:25});q.render();$("#center .unified-panel-header-inner").append(config.app.viz_config.title+" "+config.app.viz_config.dbkey);var p=create_icon_buttons_menu([{icon_class:"plus-button",title:"Add tracks",on_click:function(){i.select_datasets(config.root+"visualization/list_current_history_datasets",config.root+"api/datasets",o.get("dbkey"),function(r){o.add_tracks(r)})}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var r=config.app.viz_config;$.ajax({url:config.root+"visualization/save",type:"POST",dataType:"json",data:{id:r.vis_id,title:r.title,dbkey:r.dbkey,type:"trackster",vis_json:JSON.stringify(r)}}).success(function(s){hide_modal();r.vis_id=s.vis_id;r.has_changes=false;window.history.pushState({},"",s.url+window.location.hash)}).error(function(){show_modal("Could Not Save","Could not save visualization. Please try again later.",{Close:hide_modal})})}},{icon_class:"cross-circle",title:"Close",on_click:function(){window.location=config.root+"visualization/list"}}],{tooltip_config:{placement:"bottom"}});p.$el.attr("style","float: right");$("#center .unified-panel-header-inner").append(p.$el);$(".menu-button").tooltip({placement:"bottom"})}});return{GalaxyApp:e}});
\ No newline at end of file
diff -r ba8555d1fed4b95e2882afd33c45be3300c00ded -r af1daa86ba5b713240fb3f7ccd607f3adb8c05a7 static/scripts/packed/viz/trackster.js
--- a/static/scripts/packed/viz/trackster.js
+++ b/static/scripts/packed/viz/trackster.js
@@ -1,1 +1,1 @@
-var ui=null;var view=null;var browser_router=null;require(["utils/galaxy.css","libs/jquery/jstorage","libs/jquery/jquery.event.drag","libs/jquery/jquery.event.hover","libs/jquery/jquery.mousewheel","libs/jquery/jquery-ui","libs/jquery/jquery-ui-combobox","libs/farbtastic","libs/jquery/jquery.form","libs/jquery/jquery.rating"],function(a){a.load_file("/static/style/jquery.rating.css");a.load_file("/static/style/history.css");a.load_file("/static/style/autocomplete_tagging.css");a.load_file("/static/style/jquery-ui/smoothness/jquery-ui.css");a.load_file("/static/style/library.css");a.load_file("/static/style/trackster.css")});define(["libs/backbone/backbone-relational","viz/visualization","viz/trackster_ui"],function(c,a,b){var d=Backbone.View.extend({initialize:function(){ui=new b.TracksterUI(config.url.root);ui.createButtonMenu();ui.buttonMenu.$el.attr("style","float: right");$("#center .unified-panel-header-inner").append(ui.buttonMenu.$el);$("#right-border").click(function(){view.resize_window()});force_right_panel("hide");if(config.app.id){this.view_existing()}else{this.view_new()}},set_up_router:function(e){browser_router=new a.TrackBrowserRouter(e);Backbone.history.start()},view_existing:function(){var e=config.app.viz_config;view=ui.create_visualization({container:$("#browser-container"),name:e.title,vis_id:e.vis_id,dbkey:e.dbkey},e.viewport,e.tracks,e.bookmarks,true);this.init_editor()},view_new:function(){var e=this;$.ajax({url:config.url.new_browser,data:{},error:function(){alert("Couldn't create new browser.")},success:function(f){show_modal("New Visualization",f,{Cancel:function(){window.location=config.url.viz_list},Create:function(){e.create_browser($("#new-title").val(),$("#new-dbkey").val())}});$("#new-title").focus();$("select[name='dbkey']").combobox({appendTo:$("#overlay"),size:40});$("#overlay").css("overflow","auto")}})},create_browser:function(f,e){$(document).trigger("convert_to_values");view=ui.create_visualization({container:$("#browser-container"),name:f,dbkey:e},config.app.gene_region);this.init_editor();view.editor=true;hide_modal()},init_editor:function(){$("#title").text(view.name+" ("+view.dbkey+")");if(config.app.add_dataset){$.ajax({url:config.url.datasets+"/"+config.app.add_dataset,data:{hda_ldda:"hda",data_type:"track_config"},dataType:"json",success:function(e){view.add_drawable(b.object_from_template(e,view,view))}})}$("#add-bookmark-button").click(function(){var f=view.chrom+":"+view.low+"-"+view.high,e="Bookmark description";return ui.add_bookmark(f,e,true)});ui.init_keyboard_nav(view);this.set_up_router({view:view})}});return{GalaxyApp:d}});
\ No newline at end of file
+var ui=null;var view=null;var browser_router=null;require(["utils/galaxy.css","libs/jquery/jstorage","libs/jquery/jquery.event.drag","libs/jquery/jquery.event.hover","libs/jquery/jquery.mousewheel","libs/jquery/jquery-ui","libs/jquery/jquery-ui-combobox","libs/farbtastic","libs/jquery/jquery.form","libs/jquery/jquery.rating","mvc/ui"],function(a){a.load_file("/static/style/jquery.rating.css");a.load_file("/static/style/history.css");a.load_file("/static/style/autocomplete_tagging.css");a.load_file("/static/style/jquery-ui/smoothness/jquery-ui.css");a.load_file("/static/style/library.css");a.load_file("/static/style/trackster.css")});define(["libs/backbone/backbone-relational","viz/visualization","viz/trackster_ui"],function(c,a,b){var d=Backbone.View.extend({initialize:function(){ui=new b.TracksterUI(config.root);ui.createButtonMenu();ui.buttonMenu.$el.attr("style","float: right");$("#center .unified-panel-header-inner").append(ui.buttonMenu.$el);$("#right .unified-panel-title").append("Bookmarks");$("#right .unified-panel-icons").append("<a id='add-bookmark-button' class='icon-button menu-button plus-button' href='javascript:void(0);' title='Add bookmark'></a>");$("#right-border").click(function(){view.resize_window()});force_right_panel("hide");if(config.app.id){this.view_existing()}else{this.view_new()}},set_up_router:function(e){browser_router=new a.TrackBrowserRouter(e);Backbone.history.start()},view_existing:function(){var e=config.app.viz_config;view=ui.create_visualization({container:$("#center .unified-panel-body"),name:e.title,vis_id:e.vis_id,dbkey:e.dbkey},e.viewport,e.tracks,e.bookmarks,true);this.init_editor()},view_new:function(){var e=this;$.ajax({url:config.app.new_browser,data:{},error:function(){alert("Couldn't create new browser.")},success:function(f){show_modal("New Visualization",f,{Cancel:function(){window.location=config.root+"visualization/list"},Create:function(){e.create_browser($("#new-title").val(),$("#new-dbkey").val())}});$("#new-title").focus();$("select[name='dbkey']").combobox({appendTo:$("#overlay"),size:40});$("#overlay").css("overflow","auto")}})},create_browser:function(f,e){$(document).trigger("convert_to_values");view=ui.create_visualization({container:$("#center .unified-panel-body"),name:f,dbkey:e},config.app.gene_region);this.init_editor();view.editor=true;hide_modal()},init_editor:function(){$("#center .unified-panel-title").text(view.name+" ("+view.dbkey+")");if(config.app.add_dataset){$.ajax({url:config.root+"api/datasets/"+config.app.add_dataset,data:{hda_ldda:"hda",data_type:"track_config"},dataType:"json",success:function(e){view.add_drawable(b.object_from_template(e,view,view))}})}$("#add-bookmark-button").click(function(){var f=view.chrom+":"+view.low+"-"+view.high,e="Bookmark description";return ui.add_bookmark(f,e,true)});ui.init_keyboard_nav(view);this.set_up_router({view:view})}});return{GalaxyApp:d}});
\ No newline at end of file
diff -r ba8555d1fed4b95e2882afd33c45be3300c00ded -r af1daa86ba5b713240fb3f7ccd607f3adb8c05a7 static/scripts/packed/viz/trackster/tracks.js
--- a/static/scripts/packed/viz/trackster/tracks.js
+++ b/static/scripts/packed/viz/trackster/tracks.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","mvc/data","viz/trackster/filters"],function(ab,w,k,t,L,X,i){var p=ab.extend;var m={};var j=function(ac,ad){m[ac.attr("id")]=ad};var l=function(ac,ae,ag,af){ag=".group";var ad={};m[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=m[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();if(ap.offsetY<aq){$(this).insertBefore(ai);var ar=m[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);var ar=m[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}m[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);m[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));m[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};var aa=16,G=9,D=20,z=100,I=12000,S=400,K=5000,v=100,n="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",R=10,H=20,A=["Histogram","Line","Filled","Intensity"];function V(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var q=function(ad,ac,af){if(!q.id_counter){q.id_counter=0}this.id=q.id_counter++;this.name=af.name;this.view=ad;this.container=ac;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.content_visible=true;this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").css("float","left").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};q.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ad){var af=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(){ad.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(ag){if((ag.keyCode||ag.which)===27){af()}else{if((ag.keyCode||ag.which)===13){ac()}}};$(window).bind("keypress.check_enter_esc",ae);show_modal("Configure",ad.config.build_form(),{Cancel:af,OK:ac})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.remove()}}];p(q.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(ac){},to_dict:function(){},set_name:function(ac){this.old_name=this.name;this.name=ac;this.name_div.text(this.name)},revert_name:function(){if(this.old_name){this.name=this.old_name;this.name_div.text(this.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("href","javascript:void(0);").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var y=function(ad,ac,ae){q.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};p(y.prototype,q.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=o(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(ac){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad]._draw(ac)}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(af){var ac=this.drawables.slice(0),ad=[],ae;while(ac.length!==0){ae=ac.shift();if(ae instanceof af){ad.push(ae)}else{if(ae.drawables){ac=ac.concat(ae.drawables)}}}return ad}});var Q=function(ad,ac,af){p(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);j(this.container_div,this);j(this.content_div,this);l(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};p(Q.prototype,q.prototype,y.prototype,{action_icons_def:[q.prototype.action_icons_def[0],q.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw({clear_tile_cache:true})}ac.filters_manager.toggle()}},q.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof c){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ad=new f(this.view,this.view,{name:this.name,drawables:this.drawables});var ac=this.container.replace_drawable(this,ad,true);ad.request_draw()},add_drawable:function(ac){y.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){y.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=p(y.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac){ab.each(this.drawables,function(ad){ad.request_draw(ac)})}});var Y=Backbone.View.extend({initialize:function(ac){p(ac,{obj_type:"View"});y.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new F({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"},],saved_values:ac.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;j(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){w.select_datasets(config.url.select_datasets,config.url.datasets,{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(o(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("href","javascript:void(0);").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_tracks(c),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out();ac.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in();ac.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div />").css({height:ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ac){return this.config.values[ac.toLowerCase()+"_color"]||this.config.values.n_color}});p(Y.prototype,y.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=v;var ac=this,ad=$.Deferred();$.ajax({url:config.url.genomes+"/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new B(ac))}ac.chrom_data=ag.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,af=ac.chrom_data.length;ai<af;ai++){var ah=ac.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(ag.prev_chroms){aj+='<option value="previous">Previous '+v+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+v+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-v});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+v});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad&&aj){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/,/g,"");ag=ag.replace(/:|\-/g," ");var ad=ag.split(/\s+/),af=ad[0],ae=(ad[1]?parseInt(ad[1],10):null),ac=(ad[2]?parseInt(ad[2],10):null);if(!ac){ae=ae-15;ac=ae+15}this.change_chrom(af,ae,ac)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ac.request_redraw()},200);var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){y.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){y.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ad,ae){var ac=this,af=(ae?[ae]:ac.drawables);ab.each(af,function(ag){var ah=ab.find(ac.tracks_to_be_redrawn,function(ai){return ai[0]===ag});if(ah){ah[1]=ad}else{ac.tracks_to_be_redrawn.push([ag,ad])}});if(!this.requested_redraw){requestAnimationFrame(function(){ac._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ac=this.low,ag=this.high;if(ac<this.max_low){ac=this.max_low}if(ag>this.max_high){ag=this.max_high}var ad=this.high-this.low;if(this.high!==0&&ad<this.min_separation){ag=ac+this.min_separation}this.low=Math.floor(ac);this.high=Math.ceil(ag);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=1/this.resolution_b_px;var af=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ah=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:af,width:Math.max(ae,ah)}).show();if(ah<ae){this.overview_box.css("left",af-(ae-ah)/2)}if(this.overview_highlight){this.overview_highlight.css({left:af,width:ah})}ab.each(this.tracks_to_be_redrawn,function(ak){var ai=ak[0],aj=ak[1];if(ai){ai._draw(aj)}});this.tracks_to_be_redrawn=[];ab.each(this.label_tracks,function(ai){ai._draw()})},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset.id===ae.dataset.id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var r=function(ae,aj,af){this.track=ae;this.id=aj.id;this.name=aj.name;this.params=[];var aq=aj.params;for(var ag=0;ag<aq.length;ag++){var al=aq[ag],ad=al.name,ap=al.label,ah=unescape(al.html),ar=al.value,an=al.type;if(an==="number"){this.params.push(new e(ad,ap,ah,(ad in af?af[ad]:ar),al.min,al.max))}else{if(an==="select"){this.params.push(new O(ad,ap,ah,(ad in af?af[ad]:ar)))}else{console.log("WARNING: unrecognized tool parameter type:",ad,an)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(au){au.stopPropagation()}).click(function(au){au.stopPropagation()}).bind("dblclick",function(au){au.stopPropagation()});var ao=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var am=this.params;var ak=this;$.each(this.params,function(av,ay){var ax=$("<div>").addClass("param-row").appendTo(ak.parent_div);var au=$("<div>").addClass("param-label").text(ay.label).appendTo(ax);var aw=$("<div/>").addClass("param-input").html(ay.html).appendTo(ax);aw.find(":input").val(ay.value);$("<div style='clear: both;'/>").appendTo(ax)});this.parent_div.find("input").click(function(){$(this).select()});var at=$("<div>").addClass("param-row").appendTo(this.parent_div);var ai=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(at);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(at);ac.click(function(){ak.run_on_region()});ai.click(function(){ak.run_on_dataset()});if("visible" in af&&af.visible){this.parent_div.show()}};p(r.prototype,{update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},state_dict:function(){var ad={};for(var ac=0;ac<this.params.length;ac++){ad[this.params[ac].name]=this.params[ac].value}ad.visible=this.parent_div.is(":visible");return ad},get_param_values_dict:function(){var ac={};this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();ac[ad]=ae});return ac},get_param_values:function(){var ac=[];this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();if(ad){ac[ac.length]=ae}});return ac},run_on_dataset:function(){var ac=this;ac.run({target_dataset_id:this.track.dataset.id,action:"rerun",tool_id:ac.id},null,function(ad){show_modal(ac.name+" is Running",ac.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ai=new w.GenomeRegion({chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}),ad={target_dataset_id:this.track.dataset.id,action:"rerun",tool_id:this.id,regions:[ai.toJSON()]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ag=new Q(view,view,{name:this.name});var af=ah.container.replace_drawable(ah,ag,false);ag.container_div.insertBefore(ah.view.content_div.children()[af]);ag.add_drawable(ah);ah.container_div.appendTo(ag.content_div);ac=ag}else{ac=ah.container}var aj=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});aj.init_for_tool_data();aj.change_mode(ah.mode);aj.set_filters_manager(ah.filters_manager.copy(aj));aj.update_icons();ac.add_drawable(aj);aj.tiles_div.text("Starting job.");this.update_params();this.run(ad,aj,function(ak){aj.set_dataset(new X.Dataset(ak));aj.tiles_div.text("Running job.");aj.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new k.ServerStateDeferred({ajax_settings:{url:config.url.tool,data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(x+ag.message)}else{af(ag)}}})}});var O=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};p(O.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){O.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};p(e.prototype,O.prototype,{update_value:function(){O.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};C.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ac){this.track=ac.track;this.params=ac.params;this.values={};this.restore_values((ac.saved_values?ac.saved_values:{}));this.onchange=ac.onchange};p(F.prototype,{set_param_default_value:function(ad,ac){var ae=ab.find(this.params,function(af){return af.key===ad});if(ae){ae.default_value=ac}},set_param_value:function(ac,ad){var ae=ab.find(this.params,function(af){return af.key===ac});if(ae){if(typeof ad==="string"||ad instanceof String){if(ad.trim()===""){ad=ae.default_value}else{if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad,10)}}}}}if(this.values[ac]!==ad){this.values[ac]=ad;return true}else{return false}},restore_values:function(ac){var ad=this;$.each(this.params,function(ae,af){if(ac[af.key]!==undefined){ad.values[af.key]=ac[af.key]}else{ad.values[af.key]=af.default_value}})},build_form:function(){var af=this;var ac=$("<div />");var ae;function ad(ak,ag){for(var ao=0;ao<ak.length;ao++){ae=ak[ao];if(ae.hidden){continue}var ai="param_"+ao;var at=af.values[ae.key];var av=$("<div class='form-row' />").appendTo(ag);av.append($("<label />").attr("for",ai).text(ae.label+":"));if(ae.type==="bool"){av.append($('<input type="checkbox" />').attr("id",ai).attr("name",ai).attr("checked",at))}else{if(ae.type==="text"){av.append($('<input type="text"/>').attr("id",ai).val(at).click(function(){$(this).select()}))}else{if(ae.type==="select"){var aq=$("<select />").attr("id",ai);for(var am=0;am<ae.options.length;am++){$("<option/>").text(ae.options[am].label).attr("value",ae.options[am].value).appendTo(aq)}aq.val(at);av.append(aq)}else{if(ae.type==="color"){var au=$("<div/>").appendTo(av),ap=$("<input />").attr("id",ai).attr("name",ai).val(at).css("float","left").appendTo(au).click(function(ax){$(".bs-tooltip").removeClass("in");var aw=$(this).siblings(".bs-tooltip").addClass("in");aw.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(aw).height()/2)+($(this).height()/2)}).show();aw.click(function(ay){ay.stopPropagation()});$(document).bind("click.color-picker",function(){aw.hide();$(document).unbind("click.color-picker")});ax.stopPropagation()}),an=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(au).attr("title","Set new random color").tooltip(),ar=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(au).hide(),aj=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ar),ah=$("<div class='tooltip-arrow'></div>").appendTo(ar),al=$.farbtastic(aj,{width:100,height:100,callback:ap,color:at});au.append($("<div/>").css("clear","both"));(function(aw){an.click(function(){aw.setColor(k.get_random_color())})})(al)}else{av.append($("<input />").attr("id",ai).attr("name",ai).val(at))}}}}if(ae.help){av.append($("<div class='help'/>").text(ae.help))}}}ad(this.params,ac);return ac},update_from_form:function(ac){var ae=this;var ad=false;$.each(this.params,function(af,ah){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}ad=ae.set_param_value(ah.key,ag)||ad}});if(ad){this.onchange();this.track.changed()}}});var b=function(ac,ag,ae,ad,af){this.track=ac;this.region=ag;this.low=ag.get("start");this.high=ag.get("end");this.resolution=ae;this.html_elt=$("<div class='track-tile'/>").append(ad).height($(ad).attr("height"));this.data=af;this.stale=false};b.prototype.predisplay_actions=function(){};var M=function(ac,ag,ae,ad,af){b.call(this,ac,ag,ae,ad,af)};M.prototype.predisplay_actions=function(){};var P=function(af,an,ag,ae,ai,ap,aj,aq,ad,am){b.call(this,af,an,ag,ae,ai);this.mode=aj;this.all_slotted=ad;this.feature_mapper=am;this.has_icons=false;if(aq){this.has_icons=true;var ak=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ae.width}).prependTo(this.html_elt);var al=new w.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),ao=ai.length,ah=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ah.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();af.request_draw()}).dblclick(function(ar){ar.stopPropagation()});ac.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();af.request_draw()}).dblclick(function(ar){ar.stopPropagation()})}};p(P.prototype,b.prototype);P.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ak=at[0],ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}var af=$("<div/>").attr("id",ak).addClass("feature-popup"),au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?V(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"))-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"))+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){p(ae,{drag_handle_class:"draghandle"});q.call(this,ad,ac,ae);this.dataset=new X.Dataset(ae.dataset);this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=0;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};p(g.prototype,q.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},q.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ac){ac.view.set_overview(ac)}},q.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.dynamic_tool_div.toggle();if(ac.dynamic_tool_div.is(":visible")){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new w.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}hide_modal();window.location.href=config.url.sweepster+"?"+$.param({dataset_id:ac.dataset.id,hda_ldda:ac.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ae,{No:ah,Yes:ad})}},q.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset.id&&q.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},set_dataset:function(ac){this.dataset=ac;this.data_manager.set("dataset",ac)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.values.height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.values.mode?this.config.values.mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){q.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof W){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Z){return"VariantTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.tiles_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset.id){return}var ac=$.Deferred(),af={hda_ldda:ad.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(n);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ag.message+"</pre>",{Close:hide_modal})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(u);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when.apply($,ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){ac.container_div.addClass("line-track");var af=ad.data;if(af&&af.min&&af.max){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.config.set_param_default_value("min_value",ae);ac.config.set_param_default_value("max_value",ag);ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},get_drawables:function(){return this}});var N=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;l(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in af&&af.tool?new r(this,af.tool,af.tool_state):null);this.tile_cache=new w.Cache(R);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};p(N.prototype,q.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ac){var ad=this.to_dict();p(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;if(ad==="Auto"){this.data_manager.clear()}ac.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ac){if(ac&&ac.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ac,this)},before_draw:function(){this.max_height_px=0},_draw:function(ap){if(!this.can_draw()){return}var am=ap&&ap.clear_after,ak=this.view.low,ag=this.view.high,aj=ag-ak,ad=this.view.container.width(),ao=this.view.resolution_px_b,af=this.view.resolution_b_px;if(this.is_overview){ak=this.view.max_low;ag=this.view.max_high;af=(view.max_high-view.max_low)/ad;ao=1/af}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(ak/(af*S)),al,ah,ai=[],an=[];while((ac*S*af)<ag){al=this._get_tile_bounds(ac,af);ah=this.draw_helper(al,af,ao,ap);ai.push(ah);$.when(ah).then(function(aq){an.push(aq)});ac+=1}if(!am){this.tiles_div.children(".remove").removeClass("remove").remove()}var ae=this;$.when.apply($,ai).then(function(){ae.tiles_div.children(".remove").remove();an=ab.filter(an,function(aq){return aq!==null});if(an.length!==0){ae.postdraw_actions(an,ad,ao,am)}})},_add_yaxis_label:function(af,ah){var ad=this,ag=(af==="max"?"top":"bottom"),ai=(af==="max"?"max":"min"),ac=(af==="max"?"max_value":"min_value"),ah=ah||function(){ad.request_draw({clear_tile_cache:true})},ae=this.container_div.find(".yaxislabel."+ag);if(ae.length!==0){ae.text(ad.prefs[ac])}else{ae=$("<div/>").text(ad.prefs[ac]).make_text_editable({num_cols:12,on_finish:function(aj){$(".bs-tooltip").remove();ad.config.set_param_value(ac,aj);ah()},help_text:"Set "+ai+" value"}).addClass("yaxislabel "+ag).css("color",this.prefs.label_color);this.container_div.prepend(ae)}},postdraw_actions:function(af,ag,ai,ac){var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length>0){this.max_height_px=0;var ad=this;ab.each(af,function(aj){if(!(aj instanceof M)){aj.html_elt.remove();ad.draw_helper(aj.region,aj.resolution,ai,{force:true,mode:"Coverage"})}});ad._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ah=ab.find(af,function(aj){return aj.has_icons});if(ah){ab.each(af,function(aj){if(!aj.has_icons){aj.html_elt.css("padding-top",D)}})}}},get_mode:function(ac){return this.mode},update_auto_mode:function(ac){},_get_drawables:function(){return[this]},draw_helper:function(al,af,ao,ap){if(!ap){ap={}}var ad=ap.force,an=!(ap.data_fetch===false),ai=ap.mode||this.mode,ae=this,ag=this._get_drawables(),am=this._gen_tile_cache_key(ao,al),ah=function(aq){return(aq&&"track" in aq)};var aj=(ad?undefined:ae.tile_cache.get_elt(am));if(aj){if(ah(aj)){ae.show_tile(aj,ao)}return aj}if(!an){return null}var ak=function(){var aq=(ab.find(A,function(at){return at===ai})?"Coverage":ai);var ar=ab.map(ag,function(at){return at.data_manager.get_data(al,aq,af,ae.data_url_extra_params)});if(view.reference_track){ar.push(view.reference_track.data_manager.get_data(al,ai,af,view.reference_track.data_url_extra_params))}return ar};var ac=$.Deferred();ae.tile_cache.set_elt(am,ac);$.when.apply($,ak()).then(function(){var aq=ak(),aw=aq,aC;if(view.reference_track){aC=view.reference_track.data_manager.subset_entry(aq.pop(),al)}var ax=[],au=[];ab.each(ag,function(aH,aE){var aG=aH.mode,aF=aw[aE];if(aG==="Auto"){aG=aH.get_mode(aF);aH.update_auto_mode(aG)}ax.push(aG);au.push(aH.get_canvas_height(aF,aG,ao,ar))});var av=ae.view.canvas_manager.new_canvas(),ay=al.get("start"),aD=al.get("end"),at=0,ar=Math.ceil((aD-ay)*ao)+ae.left_offset,aA=ab.max(au),az;av.width=ar;av.height=(ap.height||aA);var aB=av.getContext("2d");aB.translate(ae.left_offset,0);if(ag.length>1){aB.globalAlpha=0.5;aB.globalCompositeOperation="source-over"}ab.each(ag,function(aF,aE){az=aF.draw_tile(aw[aE],aB,ax[aE],af,al,ao,aC)});if(az!==undefined){ae.tile_cache.set_elt(am,az);ae.show_tile(az,ao)}ac.resolve(az)});return ac},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},_draw_line_track_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.LinePainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new M(this,ah,ag,af,ac.data)},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{this.tiles_div.append(ac)}ae.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,ae.html_elt.height());ae.html_elt.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*S*ad),ag=Math.ceil(S*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new w.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae){var ac=this,ad=(ae!==undefined?ae.toString():"all");return" - region=["+ad+"], parameters=["+ac.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="bigwig"}else{if(ac.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="bigwig"||ac.message||ac.extra_info==="no_detail"){return false}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ae,af,ah,ac){var ad=this;ad.normal_postdraw_actions(ae,af,ah,ac);ad.dataset_check_type="converted_datasets_state";ad.data_query_wait=K;var ag=new k.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset.id,hda_ldda:ad.dataset.get("hda_ldda")},interval:ad.data_query_wait,success_fn:function(ai){return ai!=="pending"}});$.when(ag.go()).then(function(){ad.data_manager.set("data_type","data")});ad.postdraw_actions=ad.normal_postdraw_actions}}});var W=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};p(W.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ag){var ae=this.view,af=ae.high-ae.low,aj=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/aj)*aj,ah=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ai=(ac-ae.low)/af*ah;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ai-1}));ac+=aj}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){this.display_modes=A;N.call(this,ad,ac,ag);this.drawables=[];if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=o(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}ab.each(this.drawables,function(ah){if(ah instanceof c||ah instanceof T){ah.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};p(f.prototype,N.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_group()}}].concat(N.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ac){N.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:q.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var af=new Q(this.view,this.container,{name:this.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ad=ab.min(ab.map(this.drawables,function(ae){return ae.prefs.min_value})),ac=ab.max(ab.map(this.drawables,function(ae){return ae.prefs.max_value}));this.prefs.min_value=ad;this.prefs.max_value=ac;ab.each(this.drawables,function(ae){ae.prefs.min_value=ad;ae.prefs.max_value=ac})},update_all_min_max:function(){var ac=this;ab.each(this.drawables,function(ad){ad.prefs.min_value=ac.prefs.min_value;ad.prefs.max_value=ac.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ai,ac,al,ah){N.prototype.postdraw_actions.call(this,ai,ac,al,ah);var ag=-1;for(var ae=0;ae<ai.length;ae++){var aj=ai[ae].html_elt.find("canvas").height();if(aj>ag){ag=aj}}for(var ae=0;ae<ai.length;ae++){var af=ai[ae];if(af.html_elt.find("canvas").height()!==ag){this.draw_helper(af.region,af.resolution,al,{force:true,height:ag});af.html_elt.remove()}}var ad=this,ak=function(){ad.update_all_min_max()};this._add_yaxis_label("min",ak);this._add_yaxis_label("max",ak)}});var B=function(ac){N.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});ac.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=config.url.genomes+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};p(B.prototype,q.prototype,N.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:q.prototype.can_draw,draw_helper:function(ae,ad,af,ac){if(af>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,ae,ad,af,ac)}else{this.tiles_div.hide();return null}},can_subset:function(ac){return true},draw_tile:function(af,al,ag,ad,ai,am){var ae=this.data_manager.subset_entry(af,ai),ak=ae.data;var ac=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";for(var ah=0,aj=ak.length;ah<aj;ah++){al.fillStyle=this.view.get_base_color(ak[ah]);al.fillText(ak[ah],Math.floor(ah*am),10)}return new b(this,ai,ad,ac,ae)}});var h=function(ae,ad,af){var ac=this;this.display_modes=A;this.mode="Histogram";N.call(this,ae,ad,af);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:k.get_random_color()},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(h.prototype,q.prototype,N.prototype,{before_draw:function(){},draw_tile:function(ac,ad,ag,ae,af,ah){return this._draw_line_track_tile(ac,ad,ag,ae,af,ah)},can_subset:function(ac){return(ac.data[1][0]-ac.data[0][0]===1)},postdraw_actions:function(ad,ae,af,ac){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var s=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";N.call(this,ae,ad,af);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);this.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(s.prototype,q.prototype,N.prototype,{draw_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new b(this,ah,ag,af,ac.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,af,ae,ah);var ag=k.get_random_color(),ac=k.get_random_color([ag,"#FFFFFF"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.set_painter_from_config();ad.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};p(c.prototype,q.prototype,N.prototype,{set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(am,ae,an,al){N.prototype.postdraw_actions.call(this,am,ae,an,al);var ag=this,ah;if(ag.filters_manager){var af=ag.filters_manager.filters;for(var aj=0;aj<af.length;aj++){af[aj].update_ui_elt()}var ai=false,ak,ad;for(ah=0;ah<am.length;ah++){if(am[ah].data.length){ak=am[ah].data[0];for(var aj=0;aj<af.length;aj++){ad=af[aj];if(ad.applies_to(ak)&&ad.min!==ad.max){ai=true;break}}}}if(ag.filters_available!==ai){ag.filters_available=ai;if(!ag.filters_available){ag.filters_manager.hide()}ag.update_icons()}}if(am[0] instanceof P){var ac=true;for(ah=0;ah<am.length;ah++){if(!am[ah].all_slotted){ac=false;break}}if(!ac){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){var ac;if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (t.FeatureSlotter)(ag,af,z,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="Coverage"||ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(aa,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,ar,af,aj,ae){var ap=this,ad=aq.canvas,ay=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(am.dataset_type==="bigwig"){return this._draw_line_track_tile(am,aq,ao,ar,af,aj)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var at=0,av=am.data.length;at<av;at++){var ah=am.data[at];var au=false;var al;for(var ax=0,aC=ak.length;ax<aC;ax++){al=ak[ax];al.update_attrs(ah);if(!al.keep(ah)){au=true;break}}if(!au){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aB=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null),az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae,function(aD){return ap.view.get_base_color(aD)});var aw=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){aw=aA.draw(aq,ad.width,ad.height,aj,an);aw.translation=-ag}return new P(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)}});var Z=function(ad,ac,ae){this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Histogram color",type:"color",default_value:k.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};p(Z.prototype,q.prototype,N.prototype,{draw_tile:function(ac,af,ai,ag,ah,aj){if(ac.dataset_type==="bigwig"){return this._draw_line_track_tile(ac,af,"Histogram",ag,ah,aj)}else{var ae=this.view,ad=new (this.painter)(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai,function(ak){return ae.get_base_color(ak)});ad.draw(af,af.canvas.width,af.canvas.height,aj);return new b(this,ah,ag,af.canvas,ac.data)}},get_canvas_height:function(ac,ag,ah,ae){if(ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=new (this.painter)(null,null,null,this.prefs,ag);var ad=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ad===0&&ac.data.length!==0){ad=ac.data[0][7].match(/,/g);if(ad===null){ad=1}else{ad=ad.length+1}}return af.get_required_height(ad)}},predraw_init:function(){var ac=[g.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ac.push(this.dataset.fetch())}return ac},postdraw_actions:function(af,ag,ai,ad){N.prototype.postdraw_actions.call(this,af,ag,ai,ad);var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length===0&&this.prefs.show_labels){var ac;if(this.container_div.find(".yaxislabel.variant").length===0){ac=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ac+"px",top:(this.prefs.summary_height-ac)/2+"px"}));if(this.prefs.show_sample_data){var ah=this.dataset.get("metadata").get("sample_names").join("<br/>");this.tiles_div.prepend($("<div/>").html(ah).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height+2,}))}}ac=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ac,"line-height":ac});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=k.get_random_color(),ac=k.get_random_color([af,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block and sense strand color",type:"color",default_value:af},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=(ae.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};p(T.prototype,q.prototype,N.prototype,c.prototype);var d={CompositeTrack:f,DrawableGroup:Q,DiagonalHeatmapTrack:s,FeatureTrack:c,LineTrack:h,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var o=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new d[af](ad,ac,ae)}};return{TracksterView:Y,DrawableGroup:Q,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:s,ReadTrack:T,VariantTrack:Z,CompositeTrack:f,object_from_template:o}});
\ No newline at end of file
+define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","mvc/data","viz/trackster/filters"],function(ab,w,k,t,L,X,i){var p=ab.extend;var m={};var j=function(ac,ad){m[ac.attr("id")]=ad};var l=function(ac,ae,ag,af){ag=".group";var ad={};m[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=m[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();if(ap.offsetY<aq){$(this).insertBefore(ai);var ar=m[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);var ar=m[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}m[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);m[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));m[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};var aa=16,G=9,D=20,z=100,I=12000,S=400,K=5000,v=100,n="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",R=10,H=20,A=["Histogram","Line","Filled","Intensity"];function V(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var q=function(ad,ac,af){if(!q.id_counter){q.id_counter=0}this.id=q.id_counter++;this.name=af.name;this.view=ad;this.container=ac;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.content_visible=true;this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").css("float","left").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};q.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ad){var af=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(){ad.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(ag){if((ag.keyCode||ag.which)===27){af()}else{if((ag.keyCode||ag.which)===13){ac()}}};$(window).bind("keypress.check_enter_esc",ae);show_modal("Configure",ad.config.build_form(),{Cancel:af,OK:ac})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.remove()}}];p(q.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(ac){},to_dict:function(){},set_name:function(ac){this.old_name=this.name;this.name=ac;this.name_div.text(this.name)},revert_name:function(){if(this.old_name){this.name=this.old_name;this.name_div.text(this.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("href","javascript:void(0);").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var y=function(ad,ac,ae){q.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};p(y.prototype,q.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=o(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(ac){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad]._draw(ac)}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(af){var ac=this.drawables.slice(0),ad=[],ae;while(ac.length!==0){ae=ac.shift();if(ae instanceof af){ad.push(ae)}else{if(ae.drawables){ac=ac.concat(ae.drawables)}}}return ad}});var Q=function(ad,ac,af){p(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);j(this.container_div,this);j(this.content_div,this);l(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};p(Q.prototype,q.prototype,y.prototype,{action_icons_def:[q.prototype.action_icons_def[0],q.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw({clear_tile_cache:true})}ac.filters_manager.toggle()}},q.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof c){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ad=new f(this.view,this.view,{name:this.name,drawables:this.drawables});var ac=this.container.replace_drawable(this,ad,true);ad.request_draw()},add_drawable:function(ac){y.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){y.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=p(y.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac){ab.each(this.drawables,function(ad){ad.request_draw(ac)})}});var Y=Backbone.View.extend({initialize:function(ac){p(ac,{obj_type:"View"});y.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new F({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"},],saved_values:ac.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;j(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){w.select_datasets(config.root+"/visualization/list_current_history_datasets",config.root+"/api/datasets",{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(o(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("href","javascript:void(0);").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_tracks(c),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out();ac.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in();ac.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div />").css({height:ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ac){return this.config.values[ac.toLowerCase()+"_color"]||this.config.values.n_color}});p(Y.prototype,y.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=v;var ac=this,ad=$.Deferred();$.ajax({url:config.root+"api/genomes/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new B(ac))}ac.chrom_data=ag.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,af=ac.chrom_data.length;ai<af;ai++){var ah=ac.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(ag.prev_chroms){aj+='<option value="previous">Previous '+v+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+v+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-v});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+v});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad&&aj){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/,/g,"");ag=ag.replace(/:|\-/g," ");var ad=ag.split(/\s+/),af=ad[0],ae=(ad[1]?parseInt(ad[1],10):null),ac=(ad[2]?parseInt(ad[2],10):null);if(!ac){ae=ae-15;ac=ae+15}this.change_chrom(af,ae,ac)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ac.request_redraw()},200);var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){y.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){y.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ad,ae){var ac=this,af=(ae?[ae]:ac.drawables);ab.each(af,function(ag){var ah=ab.find(ac.tracks_to_be_redrawn,function(ai){return ai[0]===ag});if(ah){ah[1]=ad}else{ac.tracks_to_be_redrawn.push([ag,ad])}});if(!this.requested_redraw){requestAnimationFrame(function(){ac._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ac=this.low,ag=this.high;if(ac<this.max_low){ac=this.max_low}if(ag>this.max_high){ag=this.max_high}var ad=this.high-this.low;if(this.high!==0&&ad<this.min_separation){ag=ac+this.min_separation}this.low=Math.floor(ac);this.high=Math.ceil(ag);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=1/this.resolution_b_px;var af=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ah=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:af,width:Math.max(ae,ah)}).show();if(ah<ae){this.overview_box.css("left",af-(ae-ah)/2)}if(this.overview_highlight){this.overview_highlight.css({left:af,width:ah})}ab.each(this.tracks_to_be_redrawn,function(ak){var ai=ak[0],aj=ak[1];if(ai){ai._draw(aj)}});this.tracks_to_be_redrawn=[];ab.each(this.label_tracks,function(ai){ai._draw()})},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset.id===ae.dataset.id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var r=function(ae,aj,af){this.track=ae;this.id=aj.id;this.name=aj.name;this.params=[];var aq=aj.params;for(var ag=0;ag<aq.length;ag++){var al=aq[ag],ad=al.name,ap=al.label,ah=unescape(al.html),ar=al.value,an=al.type;if(an==="number"){this.params.push(new e(ad,ap,ah,(ad in af?af[ad]:ar),al.min,al.max))}else{if(an==="select"){this.params.push(new O(ad,ap,ah,(ad in af?af[ad]:ar)))}else{console.log("WARNING: unrecognized tool parameter type:",ad,an)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(au){au.stopPropagation()}).click(function(au){au.stopPropagation()}).bind("dblclick",function(au){au.stopPropagation()});var ao=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var am=this.params;var ak=this;$.each(this.params,function(av,ay){var ax=$("<div>").addClass("param-row").appendTo(ak.parent_div);var au=$("<div>").addClass("param-label").text(ay.label).appendTo(ax);var aw=$("<div/>").addClass("param-input").html(ay.html).appendTo(ax);aw.find(":input").val(ay.value);$("<div style='clear: both;'/>").appendTo(ax)});this.parent_div.find("input").click(function(){$(this).select()});var at=$("<div>").addClass("param-row").appendTo(this.parent_div);var ai=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(at);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(at);ac.click(function(){ak.run_on_region()});ai.click(function(){ak.run_on_dataset()});if("visible" in af&&af.visible){this.parent_div.show()}};p(r.prototype,{update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},state_dict:function(){var ad={};for(var ac=0;ac<this.params.length;ac++){ad[this.params[ac].name]=this.params[ac].value}ad.visible=this.parent_div.is(":visible");return ad},get_param_values_dict:function(){var ac={};this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();ac[ad]=ae});return ac},get_param_values:function(){var ac=[];this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();if(ad){ac[ac.length]=ae}});return ac},run_on_dataset:function(){var ac=this;ac.run({target_dataset_id:this.track.dataset.id,action:"rerun",tool_id:ac.id},null,function(ad){show_modal(ac.name+" is Running",ac.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ai=new w.GenomeRegion({chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}),ad={target_dataset_id:this.track.dataset.id,action:"rerun",tool_id:this.id,regions:[ai.toJSON()]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ag=new Q(view,view,{name:this.name});var af=ah.container.replace_drawable(ah,ag,false);ag.container_div.insertBefore(ah.view.content_div.children()[af]);ag.add_drawable(ah);ah.container_div.appendTo(ag.content_div);ac=ag}else{ac=ah.container}var aj=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});aj.init_for_tool_data();aj.change_mode(ah.mode);aj.set_filters_manager(ah.filters_manager.copy(aj));aj.update_icons();ac.add_drawable(aj);aj.tiles_div.text("Starting job.");this.update_params();this.run(ad,aj,function(ak){aj.set_dataset(new X.Dataset(ak));aj.tiles_div.text("Running job.");aj.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new k.ServerStateDeferred({ajax_settings:{url:config.root+"/api/tools",data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(x+ag.message)}else{af(ag)}}})}});var O=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};p(O.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){O.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};p(e.prototype,O.prototype,{update_value:function(){O.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};C.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ac){this.track=ac.track;this.params=ac.params;this.values={};this.restore_values((ac.saved_values?ac.saved_values:{}));this.onchange=ac.onchange};p(F.prototype,{set_param_default_value:function(ad,ac){var ae=ab.find(this.params,function(af){return af.key===ad});if(ae){ae.default_value=ac}},set_param_value:function(ac,ad){var ae=ab.find(this.params,function(af){return af.key===ac});if(ae){if(typeof ad==="string"||ad instanceof String){if(ad.trim()===""){ad=ae.default_value}else{if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad,10)}}}}}if(this.values[ac]!==ad){this.values[ac]=ad;return true}else{return false}},restore_values:function(ac){var ad=this;$.each(this.params,function(ae,af){if(ac[af.key]!==undefined){ad.values[af.key]=ac[af.key]}else{ad.values[af.key]=af.default_value}})},build_form:function(){var af=this;var ac=$("<div />");var ae;function ad(ak,ag){for(var ao=0;ao<ak.length;ao++){ae=ak[ao];if(ae.hidden){continue}var ai="param_"+ao;var at=af.values[ae.key];var av=$("<div class='form-row' />").appendTo(ag);av.append($("<label />").attr("for",ai).text(ae.label+":"));if(ae.type==="bool"){av.append($('<input type="checkbox" />').attr("id",ai).attr("name",ai).attr("checked",at))}else{if(ae.type==="text"){av.append($('<input type="text"/>').attr("id",ai).val(at).click(function(){$(this).select()}))}else{if(ae.type==="select"){var aq=$("<select />").attr("id",ai);for(var am=0;am<ae.options.length;am++){$("<option/>").text(ae.options[am].label).attr("value",ae.options[am].value).appendTo(aq)}aq.val(at);av.append(aq)}else{if(ae.type==="color"){var au=$("<div/>").appendTo(av),ap=$("<input />").attr("id",ai).attr("name",ai).val(at).css("float","left").appendTo(au).click(function(ax){$(".bs-tooltip").removeClass("in");var aw=$(this).siblings(".bs-tooltip").addClass("in");aw.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(aw).height()/2)+($(this).height()/2)}).show();aw.click(function(ay){ay.stopPropagation()});$(document).bind("click.color-picker",function(){aw.hide();$(document).unbind("click.color-picker")});ax.stopPropagation()}),an=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(au).attr("title","Set new random color").tooltip(),ar=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(au).hide(),aj=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ar),ah=$("<div class='tooltip-arrow'></div>").appendTo(ar),al=$.farbtastic(aj,{width:100,height:100,callback:ap,color:at});au.append($("<div/>").css("clear","both"));(function(aw){an.click(function(){aw.setColor(k.get_random_color())})})(al)}else{av.append($("<input />").attr("id",ai).attr("name",ai).val(at))}}}}if(ae.help){av.append($("<div class='help'/>").text(ae.help))}}}ad(this.params,ac);return ac},update_from_form:function(ac){var ae=this;var ad=false;$.each(this.params,function(af,ah){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}ad=ae.set_param_value(ah.key,ag)||ad}});if(ad){this.onchange();this.track.changed()}}});var b=function(ac,ag,ae,ad,af){this.track=ac;this.region=ag;this.low=ag.get("start");this.high=ag.get("end");this.resolution=ae;this.html_elt=$("<div class='track-tile'/>").append(ad).height($(ad).attr("height"));this.data=af;this.stale=false};b.prototype.predisplay_actions=function(){};var M=function(ac,ag,ae,ad,af){b.call(this,ac,ag,ae,ad,af)};M.prototype.predisplay_actions=function(){};var P=function(af,an,ag,ae,ai,ap,aj,aq,ad,am){b.call(this,af,an,ag,ae,ai);this.mode=aj;this.all_slotted=ad;this.feature_mapper=am;this.has_icons=false;if(aq){this.has_icons=true;var ak=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ae.width}).prependTo(this.html_elt);var al=new w.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),ao=ai.length,ah=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ah.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();af.request_draw()}).dblclick(function(ar){ar.stopPropagation()});ac.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();af.request_draw()}).dblclick(function(ar){ar.stopPropagation()})}};p(P.prototype,b.prototype);P.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ak=at[0],ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}var af=$("<div/>").attr("id",ak).addClass("feature-popup"),au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?V(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"))-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"))+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){p(ae,{drag_handle_class:"draghandle"});q.call(this,ad,ac,ae);this.dataset=new X.Dataset(ae.dataset);this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=0;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};p(g.prototype,q.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},q.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ac){ac.view.set_overview(ac)}},q.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.dynamic_tool_div.toggle();if(ac.dynamic_tool_div.is(":visible")){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new w.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}hide_modal();window.location.href=config.root+"visualization/sweepster?"+$.param({dataset_id:ac.dataset.id,hda_ldda:ac.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ae,{No:ah,Yes:ad})}},q.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset.id&&q.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},set_dataset:function(ac){this.dataset=ac;this.data_manager.set("dataset",ac)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.values.height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.values.mode?this.config.values.mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){q.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof W){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Z){return"VariantTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.tiles_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset.id){return}var ac=$.Deferred(),af={hda_ldda:ad.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(n);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ag.message+"</pre>",{Close:hide_modal})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(u);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when.apply($,ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){ac.container_div.addClass("line-track");var af=ad.data;if(af&&af.min&&af.max){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.config.set_param_default_value("min_value",ae);ac.config.set_param_default_value("max_value",ag);ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},get_drawables:function(){return this}});var N=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;l(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in af&&af.tool?new r(this,af.tool,af.tool_state):null);this.tile_cache=new w.Cache(R);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};p(N.prototype,q.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ac){var ad=this.to_dict();p(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;if(ad==="Auto"){this.data_manager.clear()}ac.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ac){if(ac&&ac.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ac,this)},before_draw:function(){this.max_height_px=0},_draw:function(ap){if(!this.can_draw()){return}var am=ap&&ap.clear_after,ak=this.view.low,ag=this.view.high,aj=ag-ak,ad=this.view.container.width(),ao=this.view.resolution_px_b,af=this.view.resolution_b_px;if(this.is_overview){ak=this.view.max_low;ag=this.view.max_high;af=(view.max_high-view.max_low)/ad;ao=1/af}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(ak/(af*S)),al,ah,ai=[],an=[];while((ac*S*af)<ag){al=this._get_tile_bounds(ac,af);ah=this.draw_helper(al,af,ao,ap);ai.push(ah);$.when(ah).then(function(aq){an.push(aq)});ac+=1}if(!am){this.tiles_div.children(".remove").removeClass("remove").remove()}var ae=this;$.when.apply($,ai).then(function(){ae.tiles_div.children(".remove").remove();an=ab.filter(an,function(aq){return aq!==null});if(an.length!==0){ae.postdraw_actions(an,ad,ao,am)}})},_add_yaxis_label:function(af,ah){var ad=this,ag=(af==="max"?"top":"bottom"),ai=(af==="max"?"max":"min"),ac=(af==="max"?"max_value":"min_value"),ah=ah||function(){ad.request_draw({clear_tile_cache:true})},ae=this.container_div.find(".yaxislabel."+ag);if(ae.length!==0){ae.text(ad.prefs[ac])}else{ae=$("<div/>").text(ad.prefs[ac]).make_text_editable({num_cols:12,on_finish:function(aj){$(".bs-tooltip").remove();ad.config.set_param_value(ac,aj);ah()},help_text:"Set "+ai+" value"}).addClass("yaxislabel "+ag).css("color",this.prefs.label_color);this.container_div.prepend(ae)}},postdraw_actions:function(af,ag,ai,ac){var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length>0){this.max_height_px=0;var ad=this;ab.each(af,function(aj){if(!(aj instanceof M)){aj.html_elt.remove();ad.draw_helper(aj.region,aj.resolution,ai,{force:true,mode:"Coverage"})}});ad._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ah=ab.find(af,function(aj){return aj.has_icons});if(ah){ab.each(af,function(aj){if(!aj.has_icons){aj.html_elt.css("padding-top",D)}})}}},get_mode:function(ac){return this.mode},update_auto_mode:function(ac){},_get_drawables:function(){return[this]},draw_helper:function(al,af,ao,ap){if(!ap){ap={}}var ad=ap.force,an=!(ap.data_fetch===false),ai=ap.mode||this.mode,ae=this,ag=this._get_drawables(),am=this._gen_tile_cache_key(ao,al),ah=function(aq){return(aq&&"track" in aq)};var aj=(ad?undefined:ae.tile_cache.get_elt(am));if(aj){if(ah(aj)){ae.show_tile(aj,ao)}return aj}if(!an){return null}var ak=function(){var aq=(ab.find(A,function(at){return at===ai})?"Coverage":ai);var ar=ab.map(ag,function(at){return at.data_manager.get_data(al,aq,af,ae.data_url_extra_params)});if(view.reference_track){ar.push(view.reference_track.data_manager.get_data(al,ai,af,view.reference_track.data_url_extra_params))}return ar};var ac=$.Deferred();ae.tile_cache.set_elt(am,ac);$.when.apply($,ak()).then(function(){var aq=ak(),aw=aq,aC;if(view.reference_track){aC=view.reference_track.data_manager.subset_entry(aq.pop(),al)}var ax=[],au=[];ab.each(ag,function(aH,aE){var aG=aH.mode,aF=aw[aE];if(aG==="Auto"){aG=aH.get_mode(aF);aH.update_auto_mode(aG)}ax.push(aG);au.push(aH.get_canvas_height(aF,aG,ao,ar))});var av=ae.view.canvas_manager.new_canvas(),ay=al.get("start"),aD=al.get("end"),at=0,ar=Math.ceil((aD-ay)*ao)+ae.left_offset,aA=ab.max(au),az;av.width=ar;av.height=(ap.height||aA);var aB=av.getContext("2d");aB.translate(ae.left_offset,0);if(ag.length>1){aB.globalAlpha=0.5;aB.globalCompositeOperation="source-over"}ab.each(ag,function(aF,aE){az=aF.draw_tile(aw[aE],aB,ax[aE],af,al,ao,aC)});if(az!==undefined){ae.tile_cache.set_elt(am,az);ae.show_tile(az,ao)}ac.resolve(az)});return ac},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},_draw_line_track_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.LinePainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new M(this,ah,ag,af,ac.data)},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{this.tiles_div.append(ac)}ae.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,ae.html_elt.height());ae.html_elt.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*S*ad),ag=Math.ceil(S*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new w.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae){var ac=this,ad=(ae!==undefined?ae.toString():"all");return" - region=["+ad+"], parameters=["+ac.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="bigwig"}else{if(ac.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="bigwig"||ac.message||ac.extra_info==="no_detail"){return false}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ae,af,ah,ac){var ad=this;ad.normal_postdraw_actions(ae,af,ah,ac);ad.dataset_check_type="converted_datasets_state";ad.data_query_wait=K;var ag=new k.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset.id,hda_ldda:ad.dataset.get("hda_ldda")},interval:ad.data_query_wait,success_fn:function(ai){return ai!=="pending"}});$.when(ag.go()).then(function(){ad.data_manager.set("data_type","data")});ad.postdraw_actions=ad.normal_postdraw_actions}}});var W=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};p(W.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ag){var ae=this.view,af=ae.high-ae.low,aj=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/aj)*aj,ah=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ai=(ac-ae.low)/af*ah;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ai-1}));ac+=aj}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){this.display_modes=A;N.call(this,ad,ac,ag);this.drawables=[];if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=o(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}ab.each(this.drawables,function(ah){if(ah instanceof c||ah instanceof T){ah.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};p(f.prototype,N.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_group()}}].concat(N.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ac){N.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:q.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var af=new Q(this.view,this.container,{name:this.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ad=ab.min(ab.map(this.drawables,function(ae){return ae.prefs.min_value})),ac=ab.max(ab.map(this.drawables,function(ae){return ae.prefs.max_value}));this.prefs.min_value=ad;this.prefs.max_value=ac;ab.each(this.drawables,function(ae){ae.prefs.min_value=ad;ae.prefs.max_value=ac})},update_all_min_max:function(){var ac=this;ab.each(this.drawables,function(ad){ad.prefs.min_value=ac.prefs.min_value;ad.prefs.max_value=ac.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ai,ac,al,ah){N.prototype.postdraw_actions.call(this,ai,ac,al,ah);var ag=-1;for(var ae=0;ae<ai.length;ae++){var aj=ai[ae].html_elt.find("canvas").height();if(aj>ag){ag=aj}}for(var ae=0;ae<ai.length;ae++){var af=ai[ae];if(af.html_elt.find("canvas").height()!==ag){this.draw_helper(af.region,af.resolution,al,{force:true,height:ag});af.html_elt.remove()}}var ad=this,ak=function(){ad.update_all_min_max()};this._add_yaxis_label("min",ak);this._add_yaxis_label("max",ak)}});var B=function(ac){N.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});ac.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=config.root+"api/genomes//"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};p(B.prototype,q.prototype,N.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:q.prototype.can_draw,draw_helper:function(ae,ad,af,ac){if(af>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,ae,ad,af,ac)}else{this.tiles_div.hide();return null}},can_subset:function(ac){return true},draw_tile:function(af,al,ag,ad,ai,am){var ae=this.data_manager.subset_entry(af,ai),ak=ae.data;var ac=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";for(var ah=0,aj=ak.length;ah<aj;ah++){al.fillStyle=this.view.get_base_color(ak[ah]);al.fillText(ak[ah],Math.floor(ah*am),10)}return new b(this,ai,ad,ac,ae)}});var h=function(ae,ad,af){var ac=this;this.display_modes=A;this.mode="Histogram";N.call(this,ae,ad,af);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:k.get_random_color()},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(h.prototype,q.prototype,N.prototype,{before_draw:function(){},draw_tile:function(ac,ad,ag,ae,af,ah){return this._draw_line_track_tile(ac,ad,ag,ae,af,ah)},can_subset:function(ac){return(ac.data[1][0]-ac.data[0][0]===1)},postdraw_actions:function(ad,ae,af,ac){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var s=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";N.call(this,ae,ad,af);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);this.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};p(s.prototype,q.prototype,N.prototype,{draw_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new b(this,ah,ag,af,ac.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,af,ae,ah);var ag=k.get_random_color(),ac=k.get_random_color([ag,"#FFFFFF"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.set_painter_from_config();ad.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};p(c.prototype,q.prototype,N.prototype,{set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(am,ae,an,al){N.prototype.postdraw_actions.call(this,am,ae,an,al);var ag=this,ah;if(ag.filters_manager){var af=ag.filters_manager.filters;for(var aj=0;aj<af.length;aj++){af[aj].update_ui_elt()}var ai=false,ak,ad;for(ah=0;ah<am.length;ah++){if(am[ah].data.length){ak=am[ah].data[0];for(var aj=0;aj<af.length;aj++){ad=af[aj];if(ad.applies_to(ak)&&ad.min!==ad.max){ai=true;break}}}}if(ag.filters_available!==ai){ag.filters_available=ai;if(!ag.filters_available){ag.filters_manager.hide()}ag.update_icons()}}if(am[0] instanceof P){var ac=true;for(ah=0;ah<am.length;ah++){if(!am[ah].all_slotted){ac=false;break}}if(!ac){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){var ac;if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (t.FeatureSlotter)(ag,af,z,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="Coverage"||ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(aa,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,ar,af,aj,ae){var ap=this,ad=aq.canvas,ay=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(am.dataset_type==="bigwig"){return this._draw_line_track_tile(am,aq,ao,ar,af,aj)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var at=0,av=am.data.length;at<av;at++){var ah=am.data[at];var au=false;var al;for(var ax=0,aC=ak.length;ax<aC;ax++){al=ak[ax];al.update_attrs(ah);if(!al.keep(ah)){au=true;break}}if(!au){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aB=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null),az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae,function(aD){return ap.view.get_base_color(aD)});var aw=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){aw=aA.draw(aq,ad.width,ad.height,aj,an);aw.translation=-ag}return new P(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)}});var Z=function(ad,ac,ae){this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Histogram color",type:"color",default_value:k.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};p(Z.prototype,q.prototype,N.prototype,{draw_tile:function(ac,af,ai,ag,ah,aj){if(ac.dataset_type==="bigwig"){return this._draw_line_track_tile(ac,af,"Histogram",ag,ah,aj)}else{var ae=this.view,ad=new (this.painter)(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai,function(ak){return ae.get_base_color(ak)});ad.draw(af,af.canvas.width,af.canvas.height,aj);return new b(this,ah,ag,af.canvas,ac.data)}},get_canvas_height:function(ac,ag,ah,ae){if(ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=new (this.painter)(null,null,null,this.prefs,ag);var ad=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ad===0&&ac.data.length!==0){ad=ac.data[0][7].match(/,/g);if(ad===null){ad=1}else{ad=ad.length+1}}return af.get_required_height(ad)}},predraw_init:function(){var ac=[g.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ac.push(this.dataset.fetch())}return ac},postdraw_actions:function(af,ag,ai,ad){N.prototype.postdraw_actions.call(this,af,ag,ai,ad);var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length===0&&this.prefs.show_labels){var ac;if(this.container_div.find(".yaxislabel.variant").length===0){ac=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ac+"px",top:(this.prefs.summary_height-ac)/2+"px"}));if(this.prefs.show_sample_data){var ah=this.dataset.get("metadata").get("sample_names").join("<br/>");this.tiles_div.prepend($("<div/>").html(ah).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height+2,}))}}ac=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ac,"line-height":ac});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=k.get_random_color(),ac=k.get_random_color([af,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block and sense strand color",type:"color",default_value:af},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=(ae.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};p(T.prototype,q.prototype,N.prototype,c.prototype);var d={CompositeTrack:f,DrawableGroup:Q,DiagonalHeatmapTrack:s,FeatureTrack:c,LineTrack:h,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var o=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new d[af](ad,ac,ae)}};return{TracksterView:Y,DrawableGroup:Q,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:s,ReadTrack:T,VariantTrack:Z,CompositeTrack:f,object_from_template:o}});
\ No newline at end of file
diff -r ba8555d1fed4b95e2882afd33c45be3300c00ded -r af1daa86ba5b713240fb3f7ccd607f3adb8c05a7 static/scripts/packed/viz/trackster_ui.js
--- a/static/scripts/packed/viz/trackster_ui.js
+++ b/static/scripts/packed/viz/trackster_ui.js
@@ -1,1 +1,1 @@
-define(["base","libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks","viz/visualization"],function(a,f,e,c,d,h){var j=d.object_from_template;var b=function(l,k){if(!k){k={}}var m=new IconButtonCollection(f.map(l,function(n){return new IconButton(f.extend(n,k))}));return new IconButtonMenuView({collection:m})};var g=a.Base.extend({initialize:function(k){this.baseURL=k},createButtonMenu:function(){var k=this,l=b([{icon_class:"plus-button",title:"Add tracks",on_click:function(){h.select_datasets(config.url.select_datasets,config.url.datasets,{"f-dbkey":view.dbkey},function(m){f.each(m,function(n){view.add_drawable(j(n,view,view))})})}},{icon_class:"block--plus",title:"Add group",on_click:function(){view.add_drawable(new d.DrawableGroup(view,view,{name:"New Group"}))}},{icon_class:"bookmarks",title:"Bookmarks",on_click:function(){force_right_panel(($("div#right").css("right")=="0px"?"hide":"show"))}},{icon_class:"globe",title:"Circster",on_click:function(){window.location=k.baseURL+"visualization/circster?id="+view.vis_id}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var m=[];$(".bookmark").each(function(){m.push({position:$(this).children(".position").text(),annotation:$(this).children(".annotation").text()})});var n=(view.overview_drawable?view.overview_drawable.name:null),o={view:view.to_dict(),viewport:{chrom:view.chrom,start:view.low,end:view.high,overview:n},bookmarks:m};$.ajax({url:config.url.visualization,type:"POST",dataType:"json",data:{id:view.vis_id,title:view.name,dbkey:view.dbkey,type:"trackster",vis_json:JSON.stringify(o)}}).success(function(p){hide_modal();view.vis_id=p.vis_id;view.has_changes=false;window.history.pushState({},"",p.url+window.location.hash)}).error(function(){show_modal("Could Not Save","Could not save visualization. Please try again later.",{Close:hide_modal})})}}],{tooltip_config:{placement:"bottom"}});this.buttonMenu=l;return l},add_bookmarks:function(){var k=this,l=this.baseURL;show_modal("Select dataset for new bookmarks","progress");$.ajax({url:this.baseURL+"/visualization/list_histories",data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(m){show_modal("Select dataset for new bookmarks",m,{Cancel:function(){hide_modal()},Insert:function(){$("input[name=id]:checked,input[name=ldda_ids]:checked").first().each(function(){var n,o=$(this).val();if($(this).attr("name")==="id"){n={hda_id:o}}else{n={ldda_id:o}}$.ajax({url:this.baseURL+"/visualization/bookmarks_from_dataset",data:n,dataType:"json"}).then(function(p){for(i=0;i<p.data.length;i++){var q=p.data[i];k.add_bookmark(q[0],q[1])}})});hide_modal()}})}})},add_bookmark:function(o,m,k){var q=$("#bookmarks-container"),s=$("<div/>").addClass("bookmark").appendTo(q);var t=$("<div/>").addClass("position").appendTo(s),p=$("<a href=''/>").text(o).appendTo(t).click(function(){view.go_to(o);return false}),n=$("<div/>").text(m).appendTo(s);if(k){var r=$("<div/>").addClass("delete-icon-container").prependTo(s).click(function(){s.slideUp("fast");s.remove();view.has_changes=true;return false}),l=$("<a href=''/>").addClass("icon-button delete").appendTo(r);n.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return s},create_visualization:function(p,k,o,q,n){var m=this,l=new d.TracksterView(p);l.editor=true;$.when(l.load_chroms_deferred).then(function(B){if(k){var z=k.chrom,r=k.start,w=k.end,t=k.overview;if(z&&(r!==undefined)&&w){l.change_chrom(z,r,w)}else{l.change_chrom(B[0].chrom)}}else{l.change_chrom(B[0].chrom)}if(o){var u,s,v;for(var x=0;x<o.length;x++){l.add_drawable(j(o[x],l,l))}}l.update_intro_div();var A;for(var x=0;x<l.drawables.length;x++){if(l.drawables[x].name===t){l.set_overview(l.drawables[x]);break}}if(q){var y;for(var x=0;x<q.length;x++){y=q[x];m.add_bookmark(y.position,y.annotation,n)}}l.has_changes=false});return l},init_keyboard_nav:function(k){$(document).keydown(function(l){if($(l.srcElement).is(":input")){return}switch(l.which){case 37:k.move_fraction(0.25);break;case 38:var m=Math.round(k.viewport_container.height()/15);k.viewport_container.scrollTop(k.viewport_container.scrollTop()-20);break;case 39:k.move_fraction(-0.25);break;case 40:var m=Math.round(k.viewport_container.height()/15);k.viewport_container.scrollTop(k.viewport_container.scrollTop()+20);break}})}});return{object_from_template:j,TracksterUI:g}});
\ No newline at end of file
+define(["base","libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks","viz/visualization"],function(a,f,e,c,d,h){var j=d.object_from_template;var b=function(l,k){if(!k){k={}}var m=new IconButtonCollection(f.map(l,function(n){return new IconButton(f.extend(n,k))}));return new IconButtonMenuView({collection:m})};var g=a.Base.extend({initialize:function(k){this.baseURL=k},createButtonMenu:function(){var k=this,l=b([{icon_class:"plus-button",title:"Add tracks",on_click:function(){h.select_datasets(config.root+"visualization/list_current_history_datasets",config.root+"api/datasets",{"f-dbkey":view.dbkey},function(m){f.each(m,function(n){view.add_drawable(j(n,view,view))})})}},{icon_class:"block--plus",title:"Add group",on_click:function(){view.add_drawable(new d.DrawableGroup(view,view,{name:"New Group"}))}},{icon_class:"bookmarks",title:"Bookmarks",on_click:function(){force_right_panel(($("div#right").css("right")=="0px"?"hide":"show"))}},{icon_class:"globe",title:"Circster",on_click:function(){window.location=k.baseURL+"visualization/circster?id="+view.vis_id}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var m=[];$(".bookmark").each(function(){m.push({position:$(this).children(".position").text(),annotation:$(this).children(".annotation").text()})});var n=(view.overview_drawable?view.overview_drawable.name:null),o={view:view.to_dict(),viewport:{chrom:view.chrom,start:view.low,end:view.high,overview:n},bookmarks:m};$.ajax({url:config.root+"visualization/save",type:"POST",dataType:"json",data:{id:view.vis_id,title:view.name,dbkey:view.dbkey,type:"trackster",vis_json:JSON.stringify(o)}}).success(function(p){hide_modal();view.vis_id=p.vis_id;view.has_changes=false;window.history.pushState({},"",p.url+window.location.hash)}).error(function(){show_modal("Could Not Save","Could not save visualization. Please try again later.",{Close:hide_modal})})}}],{tooltip_config:{placement:"bottom"}});this.buttonMenu=l;return l},add_bookmarks:function(){var k=this,l=this.baseURL;show_modal("Select dataset for new bookmarks","progress");$.ajax({url:this.baseURL+"/visualization/list_histories",data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(m){show_modal("Select dataset for new bookmarks",m,{Cancel:function(){hide_modal()},Insert:function(){$("input[name=id]:checked,input[name=ldda_ids]:checked").first().each(function(){var n,o=$(this).val();if($(this).attr("name")==="id"){n={hda_id:o}}else{n={ldda_id:o}}$.ajax({url:this.baseURL+"/visualization/bookmarks_from_dataset",data:n,dataType:"json"}).then(function(p){for(i=0;i<p.data.length;i++){var q=p.data[i];k.add_bookmark(q[0],q[1])}})});hide_modal()}})}})},add_bookmark:function(o,m,k){var q=$("#right .unified-panel-body"),s=$("<div/>").addClass("bookmark").appendTo(q);var t=$("<div/>").addClass("position").appendTo(s),p=$("<a href=''/>").text(o).appendTo(t).click(function(){view.go_to(o);return false}),n=$("<div/>").text(m).appendTo(s);if(k){var r=$("<div/>").addClass("delete-icon-container").prependTo(s).click(function(){s.slideUp("fast");s.remove();view.has_changes=true;return false}),l=$("<a href=''/>").addClass("icon-button delete").appendTo(r);n.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return s},create_visualization:function(p,k,o,q,n){var m=this,l=new d.TracksterView(p);l.editor=true;$.when(l.load_chroms_deferred).then(function(B){if(k){var z=k.chrom,r=k.start,w=k.end,t=k.overview;if(z&&(r!==undefined)&&w){l.change_chrom(z,r,w)}else{l.change_chrom(B[0].chrom)}}else{l.change_chrom(B[0].chrom)}if(o){var u,s,v;for(var x=0;x<o.length;x++){l.add_drawable(j(o[x],l,l))}}l.update_intro_div();var A;for(var x=0;x<l.drawables.length;x++){if(l.drawables[x].name===t){l.set_overview(l.drawables[x]);break}}if(q){var y;for(var x=0;x<q.length;x++){y=q[x];m.add_bookmark(y.position,y.annotation,n)}}l.has_changes=false});return l},init_keyboard_nav:function(k){$(document).keydown(function(l){if($(l.srcElement).is(":input")){return}switch(l.which){case 37:k.move_fraction(0.25);break;case 38:var m=Math.round(k.viewport_container.height()/15);k.viewport_container.scrollTop(k.viewport_container.scrollTop()-20);break;case 39:k.move_fraction(-0.25);break;case 40:var m=Math.round(k.viewport_container.height()/15);k.viewport_container.scrollTop(k.viewport_container.scrollTop()+20);break}})}});return{object_from_template:j,TracksterUI:g}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Include a file name export_info.xml to repository archives for repositories exported from the tool shed.
by commits-noreply@bitbucket.org 05 Aug '13
by commits-noreply@bitbucket.org 05 Aug '13
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/113fce3ecc3a/
Changeset: 113fce3ecc3a
User: greg
Date: 2013-08-05 22:45:16
Summary: Include a file name export_info.xml to repository archives for repositories exported from the tool shed.
Affected #: 1 file
diff -r 927bea0f9ae7077b5ed821968a772add98466db7 -r 113fce3ecc3a665d18b13d8b9f168c261bbf7594 lib/tool_shed/util/export_util.py
--- a/lib/tool_shed/util/export_util.py
+++ b/lib/tool_shed/util/export_util.py
@@ -4,6 +4,8 @@
import tarfile
import tempfile
import threading
+from time import gmtime
+from time import strftime
import tool_shed.util.shed_util_common as suc
from galaxy import eggs
from galaxy import web
@@ -97,9 +99,14 @@
elem = xml_util.create_element( 'repository', attributes=attributes, sub_elements=sub_elements )
exported_repository_registry.exported_repository_elems.append( elem )
shutil.rmtree( work_dir )
+ # Keep information about the export in a file name export_info.xml in the archive.
+ sub_elements = generate_export_elem( tool_shed_url, repository, changeset_revision, export_repository_dependencies, api )
+ export_elem = xml_util.create_element( 'export_info', attributes=None, sub_elements=sub_elements )
+ tmp_export_info = xml_util.create_and_write_tmp_file( export_elem, use_indent=True )
+ repositories_archive.add( tmp_export_info, arcname='export_info.xml' )
# Write the manifest, which must preserve the order in which the repositories should be imported.
- tmp_xml_file = xml_util.create_and_write_tmp_file( exported_repository_registry.exported_repository_elems, use_indent=True )
- repositories_archive.add( tmp_xml_file, arcname='manifest.xml' )
+ tmp_manifest = xml_util.create_and_write_tmp_file( exported_repository_registry.exported_repository_elems, use_indent=True )
+ repositories_archive.add( tmp_manifest, arcname='manifest.xml' )
except Exception, e:
log.exception( str( e ) )
finally:
@@ -161,6 +168,17 @@
repositories_archive_filename = os.path.join( tmp_archive_dir, repositories_archive_filename )
return repositories_archive_filename
+def generate_export_elem( tool_shed_url, repository, changeset_revision, export_repository_dependencies, api ):
+ sub_elements = odict()
+ sub_elements[ 'export_time' ] = strftime( '%a, %d %b %Y %H:%M:%S +0000', gmtime() )
+ sub_elements[ 'tool_shed' ] = str( tool_shed_url.rstrip( '/' ) )
+ sub_elements[ 'repository_name' ] = str( repository.name )
+ sub_elements[ 'repository_owner' ] = str( repository.user.username )
+ sub_elements[ 'changeset_revision' ] = str( changeset_revision )
+ sub_elements[ 'export_repository_dependencies' ] = str( export_repository_dependencies )
+ sub_elements[ 'exported_via_api' ] = str( api )
+ return sub_elements
+
def get_components_from_repo_info_dict( trans, repo_info_dict ):
"""
Return the repository and the associated latest installable changeset_revision (including updates) for the repository defined by the received
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2acb664c5185/
Changeset: 2acb664c5185
Branch: next-stable
User: natefoo
Date: 2013-08-05 22:06:31
Summary: Don't allow exceptions in set_metadata.py to hang the process when the distributed object store's free space monitor is in use. Also, don't run the monitor unless the object store is started inside the Galaxy application.
Affected #: 2 files
diff -r a2fcb4655e0faa0bebb062a54cad05e448ed6c51 -r 2acb664c5185727bfbf37166dbdcef4cb30eb797 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -54,7 +54,7 @@
from tool_shed.galaxy_install.migrate.check import verify_tools
verify_tools( self, db_url, kwargs.get( 'global_conf', {} ).get( '__file__', None ), self.config.database_engine_options )
# Object store manager
- self.object_store = build_object_store_from_config(self.config)
+ self.object_store = build_object_store_from_config(self.config, fsmon=True)
# Setup the database engine and ORM
from galaxy.model import mapping
self.model = mapping.init( self.config.file_path,
diff -r a2fcb4655e0faa0bebb062a54cad05e448ed6c51 -r 2acb664c5185727bfbf37166dbdcef4cb30eb797 lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -864,7 +864,7 @@
store selected randomly, but with weighting.
"""
- def __init__(self, config):
+ def __init__(self, config, fsmon=False):
super(DistributedObjectStore, self).__init__()
self.distributed_config = config.distributed_object_store_config_file
assert self.distributed_config is not None, "distributed object store ('object_store = distributed') " \
@@ -881,9 +881,10 @@
self.__parse_distributed_config(config)
self.sleeper = None
- if self.global_max_percent_full or filter(lambda x: x != 0.0, self.max_percent_full.values()):
+ if fsmon and ( self.global_max_percent_full or filter( lambda x: x != 0.0, self.max_percent_full.values() ) ):
self.sleeper = Sleeper()
self.filesystem_monitor_thread = threading.Thread(target=self.__filesystem_monitor)
+ self.filesystem_monitor_thread.setDaemon( True )
self.filesystem_monitor_thread.start()
log.info("Filesystem space monitor started")
@@ -1020,7 +1021,7 @@
def __init__(self, backends=[]):
super(HierarchicalObjectStore, self).__init__()
-def build_object_store_from_config(config):
+def build_object_store_from_config(config, fsmon=False):
""" Depending on the configuration setting, invoke the appropriate object store
"""
store = config.object_store
@@ -1029,7 +1030,7 @@
elif store == 's3' or store == 'swift':
return S3ObjectStore(config=config)
elif store == 'distributed':
- return DistributedObjectStore(config=config)
+ return DistributedObjectStore(config=config, fsmon=fsmon)
elif store == 'hierarchical':
return HierarchicalObjectStore()
else:
https://bitbucket.org/galaxy/galaxy-central/commits/6053d0aa63cc/
Changeset: 6053d0aa63cc
Branch: next-stable
User: natefoo
Date: 2013-08-05 22:06:55
Summary: Bug fix for job recovery in the Condor runner.
Affected #: 1 file
diff -r 2acb664c5185727bfbf37166dbdcef4cb30eb797 -r 6053d0aa63cc1e9f295c7a36787d064d754de7ef lib/galaxy/jobs/runners/condor.py
--- a/lib/galaxy/jobs/runners/condor.py
+++ b/lib/galaxy/jobs/runners/condor.py
@@ -246,12 +246,12 @@
if job_id is None:
self.put( job_wrapper )
return
- cjs = CondorJobState()
+ cjs = CondorJobState( job_wrapper=job_wrapper, files_dir=self.app.config.cluster_files_directory )
cjs.job_id = str( job_id )
cjs.command_line = job.get_command_line()
cjs.job_wrapper = job_wrapper
cjs.job_destination = job_wrapper.job_destination
- cjs.user_log = os.path.join( self.app.config.cluster_files_directory, '%s.condor.log' % galaxy_id_tag )
+ cjs.user_log = os.path.join( self.app.config.cluster_files_directory, 'galaxy_%s.condor.log' % galaxy_id_tag )
cjs.register_cleanup_file_attribute( 'user_log' )
self.__old_state_paths( cjs )
if job.state == model.Job.states.RUNNING:
@@ -268,9 +268,9 @@
files in the AsychronousJobState object
"""
if cjs.job_wrapper is not None:
- user_log = "%s/%s.condor.log" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
- if not os.path.exists( cjs.job_file ) and os.path.exists( job_file ):
- cjs.output_file = "%s/%s.o" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
- cjs.error_file = "%s/%s.e" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
- cjs.job_file = "%s/galaxy_%s.sh" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
+ user_log = "%s/%s.condor.log" % (self.app.config.cluster_files_directory, cjs.job_wrapper.job_id)
+ if not os.path.exists( cjs.user_log ) and os.path.exists( user_log ):
+ cjs.output_file = "%s/%s.o" % (self.app.config.cluster_files_directory, cjs.job_wrapper.job_id)
+ cjs.error_file = "%s/%s.e" % (self.app.config.cluster_files_directory, cjs.job_wrapper.job_id)
+ cjs.job_file = "%s/galaxy_%s.sh" % (self.app.config.cluster_files_directory, cjs.job_wrapper.job_id)
cjs.user_log = user_log
https://bitbucket.org/galaxy/galaxy-central/commits/927bea0f9ae7/
Changeset: 927bea0f9ae7
User: natefoo
Date: 2013-08-05 22:08:10
Summary: Merge next-stable.
Affected #: 3 files
diff -r bd469f8d2944f2719fb4fca7078e06e6411c86a3 -r 927bea0f9ae7077b5ed821968a772add98466db7 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -54,7 +54,7 @@
from tool_shed.galaxy_install.migrate.check import verify_tools
verify_tools( self, db_url, kwargs.get( 'global_conf', {} ).get( '__file__', None ), self.config.database_engine_options )
# Object store manager
- self.object_store = build_object_store_from_config(self.config)
+ self.object_store = build_object_store_from_config(self.config, fsmon=True)
# Setup the database engine and ORM
from galaxy.model import mapping
self.model = mapping.init( self.config.file_path,
diff -r bd469f8d2944f2719fb4fca7078e06e6411c86a3 -r 927bea0f9ae7077b5ed821968a772add98466db7 lib/galaxy/jobs/runners/condor.py
--- a/lib/galaxy/jobs/runners/condor.py
+++ b/lib/galaxy/jobs/runners/condor.py
@@ -246,12 +246,12 @@
if job_id is None:
self.put( job_wrapper )
return
- cjs = CondorJobState()
+ cjs = CondorJobState( job_wrapper=job_wrapper, files_dir=self.app.config.cluster_files_directory )
cjs.job_id = str( job_id )
cjs.command_line = job.get_command_line()
cjs.job_wrapper = job_wrapper
cjs.job_destination = job_wrapper.job_destination
- cjs.user_log = os.path.join( self.app.config.cluster_files_directory, '%s.condor.log' % galaxy_id_tag )
+ cjs.user_log = os.path.join( self.app.config.cluster_files_directory, 'galaxy_%s.condor.log' % galaxy_id_tag )
cjs.register_cleanup_file_attribute( 'user_log' )
self.__old_state_paths( cjs )
if job.state == model.Job.states.RUNNING:
@@ -268,9 +268,9 @@
files in the AsychronousJobState object
"""
if cjs.job_wrapper is not None:
- user_log = "%s/%s.condor.log" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
- if not os.path.exists( cjs.job_file ) and os.path.exists( job_file ):
- cjs.output_file = "%s/%s.o" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
- cjs.error_file = "%s/%s.e" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
- cjs.job_file = "%s/galaxy_%s.sh" % (self.app.config.cluster_files_directory, job_wrapper.job_id)
+ user_log = "%s/%s.condor.log" % (self.app.config.cluster_files_directory, cjs.job_wrapper.job_id)
+ if not os.path.exists( cjs.user_log ) and os.path.exists( user_log ):
+ cjs.output_file = "%s/%s.o" % (self.app.config.cluster_files_directory, cjs.job_wrapper.job_id)
+ cjs.error_file = "%s/%s.e" % (self.app.config.cluster_files_directory, cjs.job_wrapper.job_id)
+ cjs.job_file = "%s/galaxy_%s.sh" % (self.app.config.cluster_files_directory, cjs.job_wrapper.job_id)
cjs.user_log = user_log
diff -r bd469f8d2944f2719fb4fca7078e06e6411c86a3 -r 927bea0f9ae7077b5ed821968a772add98466db7 lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -864,7 +864,7 @@
store selected randomly, but with weighting.
"""
- def __init__(self, config):
+ def __init__(self, config, fsmon=False):
super(DistributedObjectStore, self).__init__()
self.distributed_config = config.distributed_object_store_config_file
assert self.distributed_config is not None, "distributed object store ('object_store = distributed') " \
@@ -881,9 +881,10 @@
self.__parse_distributed_config(config)
self.sleeper = None
- if self.global_max_percent_full or filter(lambda x: x != 0.0, self.max_percent_full.values()):
+ if fsmon and ( self.global_max_percent_full or filter( lambda x: x != 0.0, self.max_percent_full.values() ) ):
self.sleeper = Sleeper()
self.filesystem_monitor_thread = threading.Thread(target=self.__filesystem_monitor)
+ self.filesystem_monitor_thread.setDaemon( True )
self.filesystem_monitor_thread.start()
log.info("Filesystem space monitor started")
@@ -1020,7 +1021,7 @@
def __init__(self, backends=[]):
super(HierarchicalObjectStore, self).__init__()
-def build_object_store_from_config(config):
+def build_object_store_from_config(config, fsmon=False):
""" Depending on the configuration setting, invoke the appropriate object store
"""
store = config.object_store
@@ -1029,7 +1030,7 @@
elif store == 's3' or store == 'swift':
return S3ObjectStore(config=config)
elif store == 'distributed':
- return DistributedObjectStore(config=config)
+ return DistributedObjectStore(config=config, fsmon=fsmon)
elif store == 'hierarchical':
return HierarchicalObjectStore()
else:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Enhance the generated name of the archive file created when exporting a tool shed repository.
by commits-noreply@bitbucket.org 05 Aug '13
by commits-noreply@bitbucket.org 05 Aug '13
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bd469f8d2944/
Changeset: bd469f8d2944
User: greg
Date: 2013-08-05 21:59:49
Summary: Enhance the generated name of the archive file created when exporting a tool shed repository.
Affected #: 3 files
diff -r cf08022b68927bebe340c976e6d5eb7a657de7d6 -r bd469f8d2944f2719fb4fca7078e06e6411c86a3 lib/galaxy/webapps/tool_shed/api/repository_revisions.py
--- a/lib/galaxy/webapps/tool_shed/api/repository_revisions.py
+++ b/lib/galaxy/webapps/tool_shed/api/repository_revisions.py
@@ -54,7 +54,6 @@
try:
# We'll currently support only gzip-compressed tar archives.
file_type = 'gz'
- file_type_str = suc.get_file_type_str( changeset_revision, file_type )
export_repository_dependencies = util.string_as_bool( export_repository_dependencies )
# Get the repository information.
repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
diff -r cf08022b68927bebe340c976e6d5eb7a657de7d6 -r bd469f8d2944f2719fb4fca7078e06e6411c86a3 lib/tool_shed/scripts/api/export.py
--- a/lib/tool_shed/scripts/api/export.py
+++ b/lib/tool_shed/scripts/api/export.py
@@ -13,6 +13,7 @@
sys.path.insert( 0, os.path.dirname( __file__ ) )
from common import display
from common import submit
+from tool_shed.util import export_util
CHUNK_SIZE = 2**20 # 1Mb
@@ -54,17 +55,20 @@
if repository_id:
# We'll currently support only gzip-compressed tar archives.
file_type = 'gz'
- file_type_str = get_file_type_str( options.changeset_revision, file_type )
url = '%s%s' % ( base_tool_shed_url, '/api/repository_revisions/%s/export' % str( repository_id ) )
export_dict = submit( url, data, return_formatted=False )
error_messages = export_dict[ 'error_messages' ]
if error_messages:
print "Error attempting to export revision ", options.changeset_revision, " of repository ", options.name, " owned by ", options.owner, ":\n", error_messages
else:
- if string_as_bool( options.export_repository_dependencies ):
- repositories_archive_filename = 'exported-with-dependencies-%s-%s' % ( name, file_type_str )
- else:
- repositories_archive_filename = 'exported-%s-%s' % ( name, file_type_str )
+ repositories_archive_filename = \
+ export_util.generate_repository_archive_filename( base_tool_shed_url,
+ options.name,
+ options.owner,
+ options.changeset_revision,
+ file_type,
+ export_repository_dependencies=string_as_bool( options.export_repository_dependencies ),
+ use_tmp_archive_dir=False )
download_url = export_dict[ 'download_url' ]
download_dir = os.path.abspath( options.download_dir )
file_path = os.path.join( download_dir, repositories_archive_filename )
diff -r cf08022b68927bebe340c976e6d5eb7a657de7d6 -r bd469f8d2944f2719fb4fca7078e06e6411c86a3 lib/tool_shed/util/export_util.py
--- a/lib/tool_shed/util/export_util.py
+++ b/lib/tool_shed/util/export_util.py
@@ -24,6 +24,8 @@
log = logging.getLogger( __name__ )
+CAPSULE_FILENAME = 'capsule'
+CAPSULE_WITH_DEPENDENCIES_FILENAME = 'capsule_with_dependencies'
class ExportedRepositoryRegistry( object ):
@@ -45,11 +47,22 @@
log.exception( error_message )
return return_code, error_message
+def clean_tool_shed_url( base_url ):
+ protocol, base = base_url.split( '://' )
+ base = base.replace( ':', '_colon_' )
+ base = base.rstrip( '/' )
+ return base
+
def export_repository( trans, tool_shed_url, repository_id, repository_name, changeset_revision, file_type, export_repository_dependencies, api=False ):
- file_type_str = suc.get_file_type_str( changeset_revision, file_type )
- tmp_archive_dir = tempfile.mkdtemp( prefix="tmp-toolshed-arcdir" )
+ repository = suc.get_repository_in_tool_shed( trans, repository_id )
+ repositories_archive_filename = generate_repository_archive_filename( tool_shed_url,
+ str( repository.name ),
+ str( repository.user.username ),
+ changeset_revision,
+ file_type,
+ export_repository_dependencies=export_repository_dependencies,
+ use_tmp_archive_dir=True )
if export_repository_dependencies:
- repositories_archive_filename = os.path.join( tmp_archive_dir, 'exported-with-dependencies-%s-%s' % ( repository_name, file_type_str ) )
repo_info_dicts = get_repo_info_dicts( trans, tool_shed_url, repository_id, changeset_revision )
repository_ids = get_repository_ids( trans, repo_info_dicts )
ordered_repository_ids, ordered_repositories, ordered_changeset_revisions = order_components_for_import( trans, repository_ids, repo_info_dicts )
@@ -57,8 +70,6 @@
ordered_repository_ids = []
ordered_repositories = []
ordered_changeset_revisions = []
- repositories_archive_filename = os.path.join( tmp_archive_dir, 'exported-%s-%s' % ( repository_name, file_type_str ) )
- repository = suc.get_repository_in_tool_shed( trans, repository_id )
if repository:
repository_metadata = suc.get_current_repository_metadata_for_changeset_revision( trans, repository, changeset_revision )
if repository_metadata:
@@ -138,6 +149,18 @@
repository_archive.close()
return repository_archive, error_message
+def generate_repository_archive_filename( tool_shed_url, name, owner, changeset_revision, file_type, export_repository_dependencies=False, use_tmp_archive_dir=False ):
+ tool_shed = clean_tool_shed_url( tool_shed_url )
+ file_type_str = suc.get_file_type_str( changeset_revision, file_type )
+ if export_repository_dependencies:
+ repositories_archive_filename = '%s_%s_%s_%s_%s' % ( CAPSULE_WITH_DEPENDENCIES_FILENAME, tool_shed, name, owner, file_type_str )
+ else:
+ repositories_archive_filename = '%s_%s_%s_%s_%s' % ( CAPSULE_FILENAME, tool_shed, name, owner, file_type_str )
+ if use_tmp_archive_dir:
+ tmp_archive_dir = tempfile.mkdtemp( prefix="tmp-toolshed-arcdir" )
+ repositories_archive_filename = os.path.join( tmp_archive_dir, repositories_archive_filename )
+ return repositories_archive_filename
+
def get_components_from_repo_info_dict( trans, repo_info_dict ):
"""
Return the repository and the associated latest installable changeset_revision (including updates) for the repository defined by the received
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Do not display the same repository multiple times on the Monitor installing tool shed repositories page when installing / reinstalling repositories into Galaxy.
by commits-noreply@bitbucket.org 05 Aug '13
by commits-noreply@bitbucket.org 05 Aug '13
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/cf08022b6892/
Changeset: cf08022b6892
User: greg
Date: 2013-08-05 20:05:38
Summary: Do not display the same repository multiple times on the Monitor installing tool shed repositories page when installing / reinstalling repositories into Galaxy.
Affected #: 3 files
diff -r 901808e8e65eed49de6cb42f2cd1ebac0d5eabb8 -r cf08022b68927bebe340c976e6d5eb7a657de7d6 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -1054,18 +1054,19 @@
no_changes_checked=no_changes_checked,
tool_panel_section=tool_panel_section,
new_tool_panel_section=new_tool_panel_section )
- # The repository's status must be updated from 'Uninstall' to 'New' when initiating reinstall so the repository_installation_updater will function.
- tool_shed_repository = suc.create_or_update_tool_shed_repository( trans.app,
- tool_shed_repository.name,
- tool_shed_repository.description,
- tool_shed_repository.installed_changeset_revision,
- tool_shed_repository.ctx_rev,
- repository_clone_url,
- metadata,
- trans.model.ToolShedRepository.installation_status.NEW,
- tool_shed_repository.installed_changeset_revision,
- tool_shed_repository.owner,
- tool_shed_repository.dist_to_shed )
+ if tool_shed_repository.status == trans.model.ToolShedRepository.installation_status.UNINSTALLED:
+ # The repository's status must be updated from 'Uninstalled' to 'New' when initiating reinstall so the repository_installation_updater will function.
+ tool_shed_repository = suc.create_or_update_tool_shed_repository( trans.app,
+ tool_shed_repository.name,
+ tool_shed_repository.description,
+ tool_shed_repository.installed_changeset_revision,
+ tool_shed_repository.ctx_rev,
+ repository_clone_url,
+ metadata,
+ trans.model.ToolShedRepository.installation_status.NEW,
+ tool_shed_repository.installed_changeset_revision,
+ tool_shed_repository.owner,
+ tool_shed_repository.dist_to_shed )
ctx_rev = suc.get_ctx_rev( trans.app,
tool_shed_url,
tool_shed_repository.name,
@@ -1096,7 +1097,8 @@
repository_metadata=None,
tool_dependencies=tool_dependencies,
repository_dependencies=repository_dependencies )
- repo_info_dicts.append( repo_info_dict )
+ if repo_info_dict not in repo_info_dicts:
+ repo_info_dicts.append( repo_info_dict )
# Make sure all tool_shed_repository records exist.
created_or_updated_tool_shed_repositories, tool_panel_section_keys, repo_info_dicts, filtered_repo_info_dicts = \
repository_dependency_util.create_repository_dependency_objects( trans=trans,
@@ -1107,7 +1109,7 @@
install_repository_dependencies=install_repository_dependencies,
no_changes_checked=no_changes_checked,
tool_panel_section=tool_panel_section,
- new_tool_panel_section=new_tool_panel_section )
+ new_tool_panel_section=new_tool_panel_section )
# Default the selected tool panel location for loading tools included in each newly installed required tool shed repository to the location
# selected for the repository selected for reinstallation.
for index, tps_key in enumerate( tool_panel_section_keys ):
diff -r 901808e8e65eed49de6cb42f2cd1ebac0d5eabb8 -r cf08022b68927bebe340c976e6d5eb7a657de7d6 lib/tool_shed/util/repository_dependency_util.py
--- a/lib/tool_shed/util/repository_dependency_util.py
+++ b/lib/tool_shed/util/repository_dependency_util.py
@@ -231,14 +231,16 @@
current_changeset_revision=changeset_revision,
owner=repository_owner,
dist_to_shed=False )
- # Add the processed tool shed repository to the list of all processed repositories maintained within this method.
- all_created_or_updated_tool_shed_repositories.append( tool_shed_repository )
+ if tool_shed_repository not in all_created_or_updated_tool_shed_repositories:
+ # Add the processed tool shed repository to the list of all processed repositories maintained within this method.
+ all_created_or_updated_tool_shed_repositories.append( tool_shed_repository )
# Only append the tool shed repository to the list of created_or_updated_tool_shed_repositories if it is supposed to be installed.
if install_repository_dependencies or is_in_repo_info_dicts( repo_info_dict, repo_info_dicts ):
- # Keep the one-to-one mapping between items in 3 lists.
- created_or_updated_tool_shed_repositories.append( tool_shed_repository )
- tool_panel_section_keys.append( tool_panel_section_key )
- filtered_repo_info_dicts.append( repo_info_dict )
+ if tool_shed_repository not in created_or_updated_tool_shed_repositories:
+ # Keep the one-to-one mapping between items in 3 lists.
+ created_or_updated_tool_shed_repositories.append( tool_shed_repository )
+ tool_panel_section_keys.append( tool_panel_section_key )
+ filtered_repo_info_dicts.append( repo_info_dict )
# Build repository dependency relationships even if the user chose to not install repository dependencies.
build_repository_dependency_relationships( trans, all_repo_info_dicts, all_created_or_updated_tool_shed_repositories )
return created_or_updated_tool_shed_repositories, tool_panel_section_keys, all_repo_info_dicts, filtered_repo_info_dicts
diff -r 901808e8e65eed49de6cb42f2cd1ebac0d5eabb8 -r cf08022b68927bebe340c976e6d5eb7a657de7d6 lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -242,7 +242,7 @@
"""
# The received value for dist_to_shed will be True if the InstallManager is installing a repository that contains tools or datatypes that used
# to be in the Galaxy distribution, but have been moved to the main Galaxy tool shed.
- log.debug( "Adding new row (or updating an existing row) for repository '%s' in the tool_shed_repository table." % name )
+ log.debug( "Adding new row (or updating an existing row) for repository '%s' in the tool_shed_repository table, status set to '%s'." % ( str( name ), str( status ) ) )
if current_changeset_revision is None:
# The current_changeset_revision is not passed if a repository is being installed for the first time. If a previously installed repository
# was later uninstalled, this value should be received as the value of that change set to which the repository had been updated just prior
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Fix issue where a tool shed functional test was failing. Only allow hours between check to be less than 1 when running functional tests.
by commits-noreply@bitbucket.org 05 Aug '13
by commits-noreply@bitbucket.org 05 Aug '13
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/901808e8e65e/
Changeset: 901808e8e65e
User: Dave Bouvier
Date: 2013-08-05 16:17:10
Summary: Fix issue where a tool shed functional test was failing. Only allow hours between check to be less than 1 when running functional tests.
Affected #: 1 file
diff -r 2060df75cb2817fa567853af141c11b53d1ea0da -r 901808e8e65eed49de6cb42f2cd1ebac0d5eabb8 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -76,21 +76,24 @@
self.tool_data_table_config_path = resolve_path( kwargs.get( 'tool_data_table_config_path', 'tool_data_table_conf.xml' ), self.root )
self.shed_tool_data_table_config = resolve_path( kwargs.get( 'shed_tool_data_table_config', 'shed_tool_data_table_conf.xml' ), self.root )
self.enable_tool_shed_check = string_as_bool( kwargs.get( 'enable_tool_shed_check', False ) )
+ self.running_functional_tests = string_as_bool( kwargs.get( 'running_functional_tests', False ) )
self.hours_between_check = kwargs.get( 'hours_between_check', 12 )
try:
- hbc_test = int( self.hours_between_check )
- self.hours_between_check = hbc_test
- if self.hours_between_check < 1 or self.hours_between_check > 24:
+ if isinstance( self.hours_between_check, int ):
+ if self.hours_between_check < 1 or self.hours_between_check > 24:
+ self.hours_between_check = 12
+ elif isinstance( self.hours_between_check, float ):
+ # If we're running functional tests, the minimum hours between check should be reduced to 0.001, or 3.6 seconds.
+ if self.running_functional_tests:
+ if self.hours_between_check < 0.001 or self.hours_between_check > 24.0:
+ self.hours_between_check = 12.0
+ else:
+ if self.hours_between_check < 1.0 or self.hours_between_check > 24.0:
+ self.hours_between_check = 12.0
+ else:
self.hours_between_check = 12
except:
- try:
- # Float values are supported for functional tests.
- hbc_test = float( self.hours_between_check )
- self.hours_between_check = hbc_test
- if self.hours_between_check < 0.001 or self.hours_between_check > 24.0:
- self.hours_between_check = 12.0
- except:
- self.hours_between_check = 12
+ self.hours_between_check = 12
self.update_integrated_tool_panel = kwargs.get( "update_integrated_tool_panel", True )
self.enable_data_manager_user_view = string_as_bool( kwargs.get( "enable_data_manager_user_view", "False" ) )
self.data_manager_config_file = resolve_path( kwargs.get('data_manager_config_file', 'data_manager_conf.xml' ), self.root )
@@ -276,7 +279,6 @@
self.biostar_url = kwargs.get( 'biostar_url', None )
self.biostar_key_name = kwargs.get( 'biostar_key_name', None )
self.biostar_key = kwargs.get( 'biostar_key', None )
- self.running_functional_tests = string_as_bool( kwargs.get( 'running_functional_tests', False ) )
# Experimental: This will not be enabled by default and will hide
# nonproduction code.
# The api_folders refers to whether the API exposes the /folders section.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Andrew Robinson: Fixed a clobbering of 'util' package in the permissions API.
by commits-noreply@bitbucket.org 05 Aug '13
by commits-noreply@bitbucket.org 05 Aug '13
05 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2060df75cb28/
Changeset: 2060df75cb28
User: Andrew Robinson
Date: 2013-08-05 04:17:52
Summary: Fixed a clobbering of 'util' package in the permissions API.
- used a qualified import to avoid a module name clobbering. This addresses the "AttributeError: 'module' object has no attribute 'Params'" exception when updating permissions via the GalaxyAPI.
Affected #: 1 file
diff -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a -r 2060df75cb2817fa567853af141c11b53d1ea0da lib/galaxy/webapps/galaxy/api/permissions.py
--- a/lib/galaxy/webapps/galaxy/api/permissions.py
+++ b/lib/galaxy/webapps/galaxy/api/permissions.py
@@ -3,7 +3,8 @@
"""
import logging, os, string, shutil, urllib, re, socket
from cgi import escape, FieldStorage
-from galaxy import util, datatypes, jobs, web, util
+import galaxy.util
+from galaxy import util, datatypes, jobs, web
from galaxy.web.base.controller import *
from galaxy.util.sanitize_html import sanitize_html
from galaxy.model.orm import *
@@ -23,7 +24,7 @@
trans.response.status = 403
return "You are not authorized to update library permissions."
- params = util.Params( payload )
+ params = galaxy.util.Params( payload )
try:
decoded_library_id = trans.security.decode_id( library_id )
except TypeError:
@@ -38,7 +39,7 @@
permissions = {}
for k, v in trans.app.model.Library.permitted_actions.items():
role_params = params.get( k + '_in', [] )
- in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in util.listify( role_params ) ]
+ in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in galaxy.util.listify( role_params ) ]
permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
trans.app.security_agent.set_all_library_permissions( trans, library, permissions )
trans.sa_session.refresh( library )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
02 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8ca6cfea1909/
Changeset: 8ca6cfea1909
User: greg
Date: 2013-08-03 01:30:03
Summary: Add the ability to export a specified repository revision from the tool shed to a gzip compressed archive saved locally. The ability to import this archive to the same or another tool shed is not yet implemented, but coming soon. All of the repository's repository dependencies can optionally be exported into the same archive. The archive includes a manifest.xml file that contains the order in whcih the repositories in the archive must be imported.
This feature is now available for any installable revision of a repository using the new "Export this revision" option in the Repository actions menu in the browser. It is also available via the Tool Shed API using a command like the following:
export.py --url http://testtoolshed.g2.bx.psu.edu --name chemicaltoolbox --owner bgruening --revision 4133dbf7ff4d --export_repository_dependencies True --download_dir /tmp
Affected #: 20 files
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/galaxy/webapps/tool_shed/api/repository_revisions.py
--- a/lib/galaxy/webapps/tool_shed/api/repository_revisions.py
+++ b/lib/galaxy/webapps/tool_shed/api/repository_revisions.py
@@ -6,6 +6,8 @@
from galaxy import util
from galaxy.model.orm import and_, not_, select
from galaxy.web.base.controller import BaseAPIController
+from tool_shed.util import export_util
+import tool_shed.util.shed_util_common as suc
log = logging.getLogger( __name__ )
@@ -20,6 +22,58 @@
class RepositoryRevisionsController( BaseAPIController ):
"""RESTful controller for interactions with tool shed repository revisions."""
+ @web.expose_api_anonymous
+ def export( self, trans, payload, **kwd ):
+ """
+ POST /api/repository_revisions/export
+ Creates and saves a gzip compressed tar archive of a repository and optionally all of it's repository dependencies.
+
+ The following parameters are included in the payload.
+ :param tool_shed_url (required): the base URL of the Tool Shed from which the Repository was installed
+ :param name (required): the name of the Repository
+ :param owner (required): the owner of the Repository
+ :param changset_revision (required): the changset_revision of the RepositoryMetadata object associated with the Repository
+ :param export_repository_dependencies (optional): whether to export repository dependencies - defaults to False
+ :param download_dir (optional): the local directory to which to download the archive - defaults to /tmp
+ """
+ tool_shed_url = payload.get( 'tool_shed_url', '' )
+ if not tool_shed_url:
+ raise HTTPBadRequest( detail="Missing required parameter 'tool_shed_url'." )
+ tool_shed_url = tool_shed_url.rstrip( '/' )
+ name = payload.get( 'name', '' )
+ if not name:
+ raise HTTPBadRequest( detail="Missing required parameter 'name'." )
+ owner = payload.get( 'owner', '' )
+ if not owner:
+ raise HTTPBadRequest( detail="Missing required parameter 'owner'." )
+ changeset_revision = payload.get( 'changeset_revision', '' )
+ if not changeset_revision:
+ raise HTTPBadRequest( detail="Missing required parameter 'changeset_revision'." )
+ export_repository_dependencies = payload.get( 'export_repository_dependencies', False )
+ download_dir = payload.get( 'download_dir', '/tmp' )
+ try:
+ # We'll currently support only gzip-compressed tar archives.
+ file_type = 'gz'
+ file_type_str = suc.get_file_type_str( changeset_revision, file_type )
+ export_repository_dependencies = util.string_as_bool( export_repository_dependencies )
+ # Get the repository information.
+ repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
+ repository_id = trans.security.encode_id( repository.id )
+ response = export_util.export_repository( trans,
+ tool_shed_url,
+ repository_id,
+ str( repository.name ),
+ changeset_revision,
+ file_type,
+ export_repository_dependencies,
+ api=True )
+ return response
+ except Exception, e:
+ message = "Error in the Tool Shed repository_revisions API in export: %s" % str( e )
+ log.error( message, exc_info=True )
+ trans.response.status = 500
+ return message
+
@web.expose_api
def index( self, trans, **kwd ):
"""
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/galaxy/webapps/tool_shed/buildapp.py
--- a/lib/galaxy/webapps/tool_shed/buildapp.py
+++ b/lib/galaxy/webapps/tool_shed/buildapp.py
@@ -86,6 +86,7 @@
parent_resources=dict( member_name='repository', collection_name='repositories' ) )
webapp.mapper.resource( 'repository_revision',
'repository_revisions',
+ member={ 'export' : 'POST' },
controller='repository_revisions',
name_prefix='repository_revision_',
path_prefix='/api',
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -18,6 +18,7 @@
from galaxy.model.orm import and_
import tool_shed.util.shed_util_common as suc
from tool_shed.util import encoding_util
+from tool_shed.util import export_util
from tool_shed.util import metadata_util
from tool_shed.util import readme_util
from tool_shed.util import repository_dependency_util
@@ -1064,25 +1065,101 @@
@web.expose
def download( self, trans, repository_id, changeset_revision, file_type, **kwd ):
- # Download an archive of the repository files compressed as zip, gz or bz2.
+ """Download an archive of the repository files compressed as zip, gz or bz2."""
+ # FIXME: thgis will currently only download the repository tip, no matter which installable changeset_revision is being viewed.
+ # This should be enhanced to use the export method below, which accounts for the currently viewed changeset_revision.
repository = suc.get_repository_in_tool_shed( trans, repository_id )
# Allow hgweb to handle the download. This requires the tool shed
# server account's .hgrc file to include the following setting:
# [web]
# allow_archive = bz2, gz, zip
- if file_type == 'zip':
- file_type_str = '%s.zip' % changeset_revision
- elif file_type == 'bz2':
- file_type_str = '%s.tar.bz2' % changeset_revision
- elif file_type == 'gz':
- file_type_str = '%s.tar.gz' % changeset_revision
+ file_type_str = suc.get_file_type_str( changeset_revision, file_type )
repository.times_downloaded += 1
trans.sa_session.add( repository )
trans.sa_session.flush()
- download_url = '/repos/%s/%s/archive/%s' % ( repository.user.username, repository.name, file_type_str )
+ download_url = suc.url_join( '/', 'repos', repository.user.username, repository.name, 'archive', file_type_str )
return trans.response.send_redirect( download_url )
@web.expose
+ def export( self, trans, repository_id, changeset_revision, **kwd ):
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ export_repository_dependencies = kwd.get( 'export_repository_dependencies', '' )
+ repository = suc.get_repository_in_tool_shed( trans, repository_id )
+ if kwd.get( 'export_repository_button', False ):
+ # We'll currently support only gzip-compressed tar archives.
+ file_type = 'gz'
+ export_repository_dependencies = CheckboxField.is_checked( export_repository_dependencies )
+ tool_shed_url = web.url_for( '/', qualified=True )
+ repositories_archive, error_message = export_util.export_repository( trans,
+ tool_shed_url,
+ repository_id,
+ str( repository.name ),
+ changeset_revision,
+ file_type,
+ export_repository_dependencies )
+ repositories_archive_filename = os.path.basename( repositories_archive.name )
+ if error_message:
+ message = error_message
+ else:
+ trans.response.set_content_type( 'application/x-gzip' )
+ trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s"' % ( repositories_archive_filename )
+ opened_archive = open( repositories_archive.name )
+ # Make sure the file is removed from disk after the contents have been downloaded.
+ os.unlink( repositories_archive.name )
+ return opened_archive
+ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
+ trans.security.encode_id( repository.id ),
+ changeset_revision )
+ metadata = repository_metadata.metadata
+ # Get a dictionary of all repositories upon which the contents of the current repository_metadata record depend.
+ repository_dependencies = \
+ repository_dependency_util.get_repository_dependencies_for_changeset_revision( trans=trans,
+ repository=repository,
+ repository_metadata=repository_metadata,
+ toolshed_base_url=str( web.url_for( '/', qualified=True ) ).rstrip( '/' ),
+ key_rd_dicts_to_be_processed=None,
+ all_repository_dependencies=None,
+ handled_key_rd_dicts=None )
+ if repository_dependencies:
+ # Only display repository dependencies if they exist.
+ exclude = [ 'datatypes', 'invalid_repository_dependencies', 'invalid_tool_dependencies', 'invalid_tools',
+ 'readme_files', 'tool_dependencies', 'tools', 'tool_test_results', 'workflows', 'data_manager' ]
+ containers_dict = container_util.build_repository_containers_for_tool_shed( trans,
+ repository,
+ changeset_revision,
+ repository_dependencies,
+ repository_metadata,
+ exclude=exclude )
+ export_repository_dependencies_check_box = CheckboxField( 'export_repository_dependencies', checked=True )
+ else:
+ containers_dict = None
+ export_repository_dependencies_check_box = None
+ revision_label = suc.get_revision_label( trans, repository, changeset_revision )
+ return trans.fill_template( "/webapps/tool_shed/repository/export_repository.mako",
+ changeset_revision=changeset_revision,
+ containers_dict=containers_dict,
+ export_repository_dependencies_check_box=export_repository_dependencies_check_box,
+ repository=repository,
+ repository_metadata=repository_metadata,
+ revision_label=revision_label,
+ metadata=metadata,
+ message=message,
+ status=status )
+
+ @web.expose
+ def export_via_api( self, trans, **kwd ):
+ """Return an exported gzip compressed repository archive file opened for reading."""
+ encoded_repositories_archive_name = kwd.get( 'encoded_repositories_archive_name', None )
+ if encoded_repositories_archive_name:
+ repositories_archive_name = encoding_util.tool_shed_decode( encoded_repositories_archive_name )
+ opened_archive = open( repositories_archive_name )
+ # Make sure the file is removed from disk after the contents have been downloaded.
+ os.unlink( repositories_archive_name )
+ return opened_archive
+ return ''
+
+ @web.expose
def find_tools( self, trans, **kwd ):
message = kwd.get( 'message', '' )
status = kwd.get( 'status', 'done' )
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/galaxy/webapps/tool_shed/controllers/upload.py
--- a/lib/galaxy/webapps/tool_shed/controllers/upload.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/upload.py
@@ -135,7 +135,7 @@
# Move some version of the uploaded file to the load_point within the repository hierarchy.
if uploaded_file_filename in [ suc.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME ]:
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
- altered, root_elem = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name )
+ altered, root_elem = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name, unpopulate=False )
if altered:
tmp_filename = xml_util.create_and_write_tmp_file( root_elem )
shutil.move( tmp_filename, full_path )
@@ -277,7 +277,7 @@
uploaded_file_name = os.path.abspath( os.path.join( root, uploaded_file ) )
if os.path.split( uploaded_file_name )[ -1 ] == suc.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME:
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
- altered, root_elem = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name )
+ altered, root_elem = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name, unpopulate=False )
if altered:
tmp_filename = xml_util.create_and_write_tmp_file( root_elem )
shutil.move( tmp_filename, uploaded_file_name )
@@ -338,7 +338,7 @@
uploaded_file_name = os.path.join( full_path, filename )
if os.path.split( uploaded_file_name )[ -1 ] == suc.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME:
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
- altered, root_elem = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name )
+ altered, root_elem = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name, unpopulate=False )
if altered:
tmp_filename = xml_util.create_and_write_tmp_file( root_elem )
shutil.move( tmp_filename, uploaded_file_name )
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/galaxy/webapps/tool_shed/util/container_util.py
--- a/lib/galaxy/webapps/tool_shed/util/container_util.py
+++ b/lib/galaxy/webapps/tool_shed/util/container_util.py
@@ -710,8 +710,10 @@
lock.release()
return containers_dict
-def build_repository_containers_for_tool_shed( trans, repository, changeset_revision, repository_dependencies, repository_metadata ):
+def build_repository_containers_for_tool_shed( trans, repository, changeset_revision, repository_dependencies, repository_metadata, exclude=None ):
"""Return a dictionary of containers for the received repository's dependencies and contents for display in the tool shed."""
+ if exclude is None:
+ exclude = []
containers_dict = dict( datatypes=None,
invalid_tools=None,
readme_files=None,
@@ -734,13 +736,13 @@
folder_id = 0
# Datatypes container.
if metadata:
- if 'datatypes' in metadata:
+ if 'datatypes' not in exclude and 'datatypes' in metadata:
datatypes = metadata[ 'datatypes' ]
folder_id, datatypes_root_folder = build_datatypes_folder( trans, folder_id, datatypes )
containers_dict[ 'datatypes' ] = datatypes_root_folder
# Invalid repository dependencies container.
if metadata:
- if 'invalid_repository_dependencies' in metadata:
+ if 'invalid_repository_dependencies' not in exclude and 'invalid_repository_dependencies' in metadata:
invalid_repository_dependencies = metadata[ 'invalid_repository_dependencies' ]
folder_id, invalid_repository_dependencies_root_folder = \
build_invalid_repository_dependencies_root_folder( trans,
@@ -749,7 +751,7 @@
containers_dict[ 'invalid_repository_dependencies' ] = invalid_repository_dependencies_root_folder
# Invalid tool dependencies container.
if metadata:
- if 'invalid_tool_dependencies' in metadata:
+ if 'invalid_tool_dependencies' not in exclude and 'invalid_tool_dependencies' in metadata:
invalid_tool_dependencies = metadata[ 'invalid_tool_dependencies' ]
folder_id, invalid_tool_dependencies_root_folder = \
build_invalid_tool_dependencies_root_folder( trans,
@@ -758,7 +760,7 @@
containers_dict[ 'invalid_tool_dependencies' ] = invalid_tool_dependencies_root_folder
# Invalid tools container.
if metadata:
- if 'invalid_tools' in metadata:
+ if 'invalid_tools' not in exclude and 'invalid_tools' in metadata:
invalid_tool_configs = metadata[ 'invalid_tools' ]
folder_id, invalid_tools_root_folder = build_invalid_tools_folder( trans,
folder_id,
@@ -769,21 +771,22 @@
containers_dict[ 'invalid_tools' ] = invalid_tools_root_folder
# Readme files container.
if metadata:
- if 'readme_files' in metadata:
+ if 'readme_files' not in exclude and 'readme_files' in metadata:
readme_files_dict = readme_util.build_readme_files_dict( metadata )
folder_id, readme_files_root_folder = build_readme_files_folder( trans, folder_id, readme_files_dict )
containers_dict[ 'readme_files' ] = readme_files_root_folder
- # Repository dependencies container.
- folder_id, repository_dependencies_root_folder = build_repository_dependencies_folder( trans=trans,
- folder_id=folder_id,
- repository_dependencies=repository_dependencies,
- label='Repository dependencies',
- installed=False )
- if repository_dependencies_root_folder:
- containers_dict[ 'repository_dependencies' ] = repository_dependencies_root_folder
+ if 'repository_dependencies' not in exclude:
+ # Repository dependencies container.
+ folder_id, repository_dependencies_root_folder = build_repository_dependencies_folder( trans=trans,
+ folder_id=folder_id,
+ repository_dependencies=repository_dependencies,
+ label='Repository dependencies',
+ installed=False )
+ if repository_dependencies_root_folder:
+ containers_dict[ 'repository_dependencies' ] = repository_dependencies_root_folder
# Tool dependencies container.
if metadata:
- if 'tool_dependencies' in metadata:
+ if 'tool_dependencies' not in exclude and 'tool_dependencies' in metadata:
tool_dependencies = metadata[ 'tool_dependencies' ]
if trans.webapp.name == 'tool_shed':
if 'orphan_tool_dependencies' in metadata:
@@ -797,7 +800,7 @@
containers_dict[ 'tool_dependencies' ] = tool_dependencies_root_folder
# Valid tools container.
if metadata:
- if 'tools' in metadata:
+ if 'tools' not in exclude and 'tools' in metadata:
valid_tools = metadata[ 'tools' ]
folder_id, valid_tools_root_folder = build_tools_folder( trans,
folder_id,
@@ -807,7 +810,7 @@
label='Valid tools' )
containers_dict[ 'valid_tools' ] = valid_tools_root_folder
# Tool test results container.
- if tool_test_results and len( tool_test_results ) > 1:
+ if 'tool_test_results' not in exclude and tool_test_results and len( tool_test_results ) > 1:
# Only create and populate this folder if there are actual tool test results to display, since the display of the 'Test environment'
# folder by itself can be misleading. We check for more than a single entry in the tool_test_results dictionary because it may have
# only the "test_environment" entry, but we want at least 1 of "passed_tests", "failed_tests", "installation_errors", "missing_test_components"
@@ -816,7 +819,7 @@
containers_dict[ 'tool_test_results' ] = tool_test_results_root_folder
# Workflows container.
if metadata:
- if 'workflows' in metadata:
+ if 'workflows' not in exclude and 'workflows' in metadata:
workflows = metadata[ 'workflows' ]
folder_id, workflows_root_folder = build_workflows_folder( trans=trans,
folder_id=folder_id,
@@ -827,7 +830,7 @@
containers_dict[ 'workflows' ] = workflows_root_folder
# Valid Data Managers container
if metadata:
- if 'data_manager' in metadata:
+ if 'data_manager' not in exclude and 'data_manager' in metadata:
data_managers = metadata['data_manager'].get( 'data_managers', None )
folder_id, data_managers_root_folder = build_data_managers_folder( trans, folder_id, data_managers, label="Data Managers" )
containers_dict[ 'valid_data_managers' ] = data_managers_root_folder
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -4,7 +4,6 @@
import tempfile
import threading
from galaxy import tools
-from galaxy.util import asbool
from galaxy.util import json
from galaxy import util
from galaxy import web
@@ -118,34 +117,6 @@
installed_repositories.append( installed_repository )
return installed_repositories
-def get_next_prior_install_required_dict_entry( prior_install_required_dict, processed_tsr_ids ):
- """
- The order in which the prior_install_required_dict is processed is critical in order to ensure that the ultimate repository installation order is correctly
- defined. This method determines the next key / value pair from the received prior_install_required_dict that should be processed.
- """
- # Return the first key / value pair that is not yet processed and whose value is an empty list.
- for key, value in prior_install_required_dict.items():
- if key in processed_tsr_ids:
- continue
- if not value:
- return key
- # Return the first key / value pair that is not yet processed and whose ids in value are all included in processed_tsr_ids.
- for key, value in prior_install_required_dict.items():
- if key in processed_tsr_ids:
- continue
- all_contained = True
- for required_repository_id in value:
- if required_repository_id not in processed_tsr_ids:
- all_contained = False
- break
- if all_contained:
- return key
- # Return the first key / value pair that is not yet processed. Hopefully this is all that is necessary at this point.
- for key, value in prior_install_required_dict.items():
- if key in processed_tsr_ids:
- continue
- return key
-
def get_prior_install_required_dict( trans, tsr_ids, repo_info_dicts ):
"""
Return a dictionary whose keys are the received tsr_ids and whose values are a list of tsr_ids, each of which is contained in the received list of tsr_ids
@@ -155,15 +126,15 @@
prior_install_required_dict = {}
for tsr_id in tsr_ids:
prior_install_required_dict[ tsr_id ] = []
- # inspect the repository dependencies for each repository about to be installed and populate the dictionary.
+ # Inspect the repository dependencies for each repository about to be installed and populate the dictionary.
for repo_info_dict in repo_info_dicts:
- repository, repository_dependencies = get_repository_and_repository_dependencies_from_repo_info_dict( trans, repo_info_dict )
+ repository, repository_dependencies = suc.get_repository_and_repository_dependencies_from_repo_info_dict( trans, repo_info_dict )
if repository:
encoded_repository_id = trans.security.encode_id( repository.id )
if encoded_repository_id in tsr_ids:
# We've located the database table record for one of the repositories we're about to install, so find out if it has any repository
# dependencies that require prior installation.
- prior_install_ids = get_repository_ids_requiring_prior_install( trans, tsr_ids, repository_dependencies )
+ prior_install_ids = suc.get_repository_ids_requiring_prior_import_or_install( trans, tsr_ids, repository_dependencies )
prior_install_required_dict[ encoded_repository_id ] = prior_install_ids
return prior_install_required_dict
@@ -287,38 +258,6 @@
return repo_info_dict, tool_panel_section_key
return None, None
-def get_repository_and_repository_dependencies_from_repo_info_dict( trans, repo_info_dict ):
- """Return a tool_shed_repository record defined by the information in the received repo_info_dict."""
- repository_name = repo_info_dict.keys()[ 0 ]
- repo_info_tuple = repo_info_dict[ repository_name ]
- description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
- suc.get_repo_info_tuple_contents( repo_info_tuple )
- tool_shed = suc.get_tool_shed_from_clone_url( repository_clone_url )
- repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed, repository_name, repository_owner, changeset_revision )
- return repository, repository_dependencies
-
-def get_repository_ids_requiring_prior_install( trans, tsr_ids, repository_dependencies ):
- """
- Inspect the received repository_dependencies and determine if the encoded id of each required repository is in the received tsr_ids. If so,
- then determine whether that required repository should be installed prior to it's dependent repository. Return a list of encoded repository
- ids, each of which is contained in the received list of tsr_ids, and whose associated repositories must be installed prior to the dependent
- repository associated with the received repository_dependencies.
- """
- prior_install_ids = []
- if repository_dependencies:
- for key, rd_tups in repository_dependencies.items():
- if key in [ 'description', 'root_key' ]:
- continue
- for rd_tup in rd_tups:
- tool_shed, name, owner, changeset_revision, prior_installation_required = suc.parse_repository_dependency_tuple( rd_tup )
- if asbool( prior_installation_required ):
- repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed, name, owner, changeset_revision )
- if repository:
- encoded_repository_id = trans.security.encode_id( repository.id )
- if encoded_repository_id in tsr_ids:
- prior_install_ids.append( encoded_repository_id )
- return prior_install_ids
-
def get_tool_shed_repository_ids( as_string=False, **kwd ):
tsrid = kwd.get( 'tool_shed_repository_id', None )
tsridslist = util.listify( kwd.get( 'tool_shed_repository_ids', None ) )
@@ -722,10 +661,10 @@
ordered_tool_panel_section_keys = []
# Create a dictionary whose keys are the received tsr_ids and whose values are a list of tsr_ids, each of which is contained in the received list of tsr_ids
# and whose associated repository must be installed prior to the repository associated with the tsr_id key.
- prior_install_required_dict = get_prior_install_required_dict( trans, tsr_ids, repo_info_dicts )
+ prior_install_required_dict = suc.get_prior_import_or_install_required_dict( trans, tsr_ids, repo_info_dicts )
processed_tsr_ids = []
while len( processed_tsr_ids ) != len( prior_install_required_dict.keys() ):
- tsr_id = get_next_prior_install_required_dict_entry( prior_install_required_dict, processed_tsr_ids )
+ tsr_id = suc.get_next_prior_import_or_install_required_dict_entry( prior_install_required_dict, processed_tsr_ids )
processed_tsr_ids.append( tsr_id )
# Create the ordered_tsr_ids, the ordered_repo_info_dicts and the ordered_tool_panel_section_keys lists.
if tsr_id not in ordered_tsr_ids:
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/tool_shed/scripts/api/common.py
--- a/lib/tool_shed/scripts/api/common.py
+++ b/lib/tool_shed/scripts/api/common.py
@@ -1,6 +1,6 @@
import os, sys, urllib, urllib2
-new_path = [ os.path.join( os.path.dirname( __file__ ), '..', '..', '..', 'lib' ) ]
+new_path = [ os.path.join( os.path.dirname( __file__ ), '..', '..', '..', '..', 'lib' ) ]
new_path.extend( sys.path[ 1: ] )
sys.path = new_path
@@ -45,10 +45,10 @@
print '--------'
print r
-def display( api_key, url, return_formatted=True ):
+def display( url, api_key=None, return_formatted=True ):
# Sends an API GET request and acts as a generic formatter for the JSON response.
try:
- r = get( api_key, url )
+ r = get( url, api_key=api_key )
except urllib2.HTTPError, e:
print e
print e.read( 1024 ) # Only return the first 1K of errors.
@@ -82,43 +82,44 @@
else:
print 'response is unknown type: %s' % type( r )
-def get( api_key, url ):
+def get( url, api_key=None ):
# Do the actual GET.
- url = make_url( api_key, url )
+ url = make_url( url, api_key=api_key )
try:
return simplejson.loads( urllib2.urlopen( url ).read() )
except simplejson.decoder.JSONDecodeError, e:
print "URL did not return JSON data"
sys.exit(1)
-def make_url( api_key, url, args=None ):
+def make_url( url, api_key=None, args=None ):
# Adds the API Key to the URL if it's not already there.
if args is None:
args = []
argsep = '&'
if '?' not in url:
argsep = '?'
- if '?key=' not in url and '&key=' not in url:
- args.insert( 0, ( 'key', api_key ) )
+ if api_key:
+ if '?key=' not in url and '&key=' not in url:
+ args.insert( 0, ( 'key', api_key ) )
return url + argsep + '&'.join( [ '='.join( t ) for t in args ] )
-def post( api_key, url, data ):
+def post( url, data, api_key=None ):
# Do the actual POST.
- url = make_url( api_key, url )
+ url = make_url( url, api_key=api_key )
req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' }, data = simplejson.dumps( data ) )
return simplejson.loads( urllib2.urlopen( req ).read() )
-def put( api_key, url, data ):
+def put( url, data, api_key=None ):
# Do the actual PUT.
- url = make_url( api_key, url )
+ url = make_url( url, api_key=api_key )
req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' }, data = simplejson.dumps( data ))
req.get_method = lambda: 'PUT'
return simplejson.loads( urllib2.urlopen( req ).read() )
-def submit( api_key, url, data, return_formatted=True ):
+def submit( url, data, api_key=None, return_formatted=True ):
# Sends an API POST request and acts as a generic formatter for the JSON response - 'data' will become the JSON payload read by Galaxy.
try:
- r = post( api_key, url, data )
+ r = post( url, data, api_key=api_key )
except urllib2.HTTPError, e:
if return_formatted:
print e
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/tool_shed/scripts/api/export.py
--- /dev/null
+++ b/lib/tool_shed/scripts/api/export.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+"""
+Export a specified repository revision and optionally all of it's defined repository dependencies from the tool shed into a compressed archive.
+
+Here is a working example of how to use this script to export a repository from the tool shed.
+./export.py --url http://testtoolshed.g2.bx.psu.edu --name chemicaltoolbox --owner bgruening --revision 4133dbf7ff4d --export_repository_dependencies True --download_dir /tmp
+"""
+
+import os
+import sys
+import argparse
+import urllib2
+sys.path.insert( 0, os.path.dirname( __file__ ) )
+from common import display
+from common import submit
+
+CHUNK_SIZE = 2**20 # 1Mb
+
+def get_file_type_str( changeset_revision, file_type ):
+ if file_type == 'zip':
+ file_type_str = '%s.zip' % changeset_revision
+ elif file_type == 'bz2':
+ file_type_str = '%s.tar.bz2' % changeset_revision
+ elif file_type == 'gz':
+ file_type_str = '%s.tar.gz' % changeset_revision
+ else:
+ file_type_str = ''
+ return file_type_str
+
+def string_as_bool( string ):
+ if str( string ).lower() in ( 'true', 'yes', 'on' ):
+ return True
+ else:
+ return False
+
+def main( options ):
+ """Collect all user data and export the repository via the Tool Shed API."""
+ base_tool_shed_url = options.tool_shed_url.rstrip( '/' )
+ repositories_url = '%s/api/repositories' % base_tool_shed_url
+ data = {}
+ data[ 'tool_shed_url' ] = base_tool_shed_url
+ data[ 'name' ] = options.name
+ data[ 'owner' ] = options.owner
+ data[ 'changeset_revision' ] = options.changeset_revision
+ data[ 'export_repository_dependencies' ] = options.export_repository_dependencies
+ repository_id = None
+ repositories = display( repositories_url, api_key=None, return_formatted=False )
+ for repository in repositories:
+ name = str( repository[ 'name' ] )
+ owner = str( repository[ 'owner' ] )
+ if name == options.name and owner == options.owner:
+ repository_id = repository[ 'id' ]
+ break
+ if repository_id:
+ # We'll currently support only gzip-compressed tar archives.
+ file_type = 'gz'
+ file_type_str = get_file_type_str( options.changeset_revision, file_type )
+ url = '%s%s' % ( base_tool_shed_url, '/api/repository_revisions/%s/export' % str( repository_id ) )
+ export_dict = submit( url, data, return_formatted=False )
+ error_messages = export_dict[ 'error_messages' ]
+ if error_messages:
+ print "Error attempting to export revision ", options.changeset_revision, " of repository ", options.name, " owned by ", options.owner, ":\n", error_messages
+ else:
+ if string_as_bool( options.export_repository_dependencies ):
+ repositories_archive_filename = 'exported-with-dependencies-%s-%s' % ( name, file_type_str )
+ else:
+ repositories_archive_filename = 'exported-%s-%s' % ( name, file_type_str )
+ download_url = export_dict[ 'download_url' ]
+ download_dir = os.path.abspath( options.download_dir )
+ file_path = os.path.join( download_dir, repositories_archive_filename )
+ src = None
+ dst = None
+ try:
+ src = urllib2.urlopen( download_url )
+ dst = open( file_path, 'wb' )
+ while True:
+ chunk = src.read( CHUNK_SIZE )
+ if chunk:
+ dst.write( chunk )
+ else:
+ break
+ except:
+ raise
+ finally:
+ if src:
+ src.close()
+ if dst:
+ dst.close()
+ print "Successfully exported revision ", options.changeset_revision, " of repository ", options.name, " owned by ", options.owner
+ print "to location ", file_path
+ else:
+ print "Invalid tool_shed / name / owner ."
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser( description='Installation of tool shed repositories via the Galaxy API.' )
+ parser.add_argument( "-u", "--url", dest="tool_shed_url", required=True, help="Tool Shed URL" )
+ parser.add_argument( "-n", "--name", required=True, help="Repository name." )
+ parser.add_argument( "-o", "--owner", required=True, help="Repository owner." )
+ parser.add_argument( "-r", "--revision", dest="changeset_revision", required=True, help="Repository owner." )
+ parser.add_argument( "-e", "--export_repository_dependencies", dest="export_repository_dependencies", required=False, default='False', help="Export repository dependencies." )
+ parser.add_argument( "-d", "--download_dir", dest="download_dir", required=False, default='/tmp', help="Download directory." )
+ options = parser.parse_args()
+ main( options )
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/tool_shed/util/commit_util.py
--- a/lib/tool_shed/util/commit_util.py
+++ b/lib/tool_shed/util/commit_util.py
@@ -9,6 +9,7 @@
from galaxy import util
from galaxy.datatypes import checkers
from galaxy.util import json
+from galaxy.util.odict import odict
from galaxy.web import url_for
import tool_shed.util.shed_util_common as suc
from tool_shed.util import tool_util
@@ -228,7 +229,12 @@
gzipped_file.close()
shutil.move( uncompressed, uploaded_file_name )
-def handle_repository_dependencies_definition( trans, repository_dependencies_config ):
+def handle_repository_dependencies_definition( trans, repository_dependencies_config, unpopulate=False ):
+ """
+ Populate or unpopulate the toolshed and changeset_revision attributes of a <repository> tag. Populating will occur when a
+ dependency definition file is being uploaded to the repository, while depopulating will occur when the repository is being
+ exported.
+ """
altered = False
# Make sure we're looking at a valid repository_dependencies.xml file.
tree, error_message = xml_util.parse_xml( repository_dependencies_config )
@@ -239,33 +245,45 @@
for index, elem in enumerate( root ):
if elem.tag == 'repository':
# <repository name="molecule_datatypes" owner="test" changeset_revision="1a070566e9c6" />
- populated, elem, error_message = handle_repository_dependency_elem( trans, elem )
+ revised, elem, error_message = handle_repository_dependency_elem( trans, elem, unpopulate=unpopulate )
if error_message:
exception_message = 'The repository_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
raise Exception( exception_message )
- if populated:
+ if revised:
root[ index ] = elem
if not altered:
altered = True
return altered, root
return False, None
-def handle_repository_dependency_elem( trans, elem ):
+def handle_repository_dependency_elem( trans, elem, unpopulate=False ):
# <repository name="molecule_datatypes" owner="test" changeset_revision="1a070566e9c6" />
error_message = ''
name = elem.get( 'name' )
owner = elem.get( 'owner' )
+ # The name and owner attributes are always required, so if either are missing, return the error message.
if not name or not owner:
error_message = handle_missing_repository_attribute( elem )
return False, elem, error_message
- populated = False
+ revised = False
toolshed = elem.get( 'toolshed' )
+ changeset_revision = elem.get( 'changeset_revision' )
+ if unpopulate:
+ # We're exporting the repository, so eliminate all toolshed and changeset_revision attributes from the <repository> tag.
+ if toolshed or changeset_revision:
+ attributes = odict()
+ attributes[ 'name' ] = name
+ attributes[ 'owner' ] = owner
+ attributes[ 'prior_installation_required' ] = elem.get( 'prior_installation_required', 'False' )
+ elem = xml_util.create_element( 'repository', attributes=attributes, sub_elements=None )
+ revised = True
+ return revised, elem, error_message
+ # From here on we're populating the toolshed and changeset_revisions if necessary.
if not toolshed:
# Default the setting to the current tool shed.
toolshed = str( url_for( '/', qualified=True ) ).rstrip( '/' )
elem.attrib[ 'toolshed' ] = toolshed
- populated = True
- changeset_revision = elem.get( 'changeset_revision' )
+ revised = True
if not changeset_revision:
# Populate the changeset_revision attribute with the latest installable metadata revision for the defined repository.
# We use the latest installable revision instead of the latest metadata revision to ensure that the contents of the
@@ -277,12 +295,12 @@
lastest_installable_changeset_revision = suc.get_latest_downloadable_changeset_revision( trans, repository, repo )
if lastest_installable_changeset_revision != suc.INITIAL_CHANGELOG_HASH:
elem.attrib[ 'changeset_revision' ] = lastest_installable_changeset_revision
- populated = True
+ revised = True
else:
error_message = 'Unable to locate repository with name %s and owner %s. ' % ( str( name ), str( owner ) )
- return populated, elem, error_message
+ return revised, elem, error_message
-def handle_tool_dependencies_definition( trans, tool_dependencies_config ):
+def handle_tool_dependencies_definition( trans, tool_dependencies_config, unpopulate=False ):
altered = False
# Make sure we're looking at a valid tool_dependencies.xml file.
tree, error_message = xml_util.parse_xml( tool_dependencies_config )
@@ -297,11 +315,11 @@
for package_index, package_elem in enumerate( root_elem ):
if package_elem.tag == 'repository':
# <repository name="package_eigen_2_0" owner="test" changeset_revision="09eb05087cd0" prior_installation_required="True" />
- populated, repository_elem, error_message = handle_repository_dependency_elem( trans, package_elem )
+ revised, repository_elem, error_message = handle_repository_dependency_elem( trans, package_elem, unpopulate=unpopulate )
if error_message:
exception_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
raise Exception( exception_message )
- if populated:
+ if revised:
root_elem[ package_index ] = repository_elem
package_altered = True
if not altered:
@@ -318,11 +336,11 @@
# </repository>
# </action>
for repo_index, repo_elem in enumerate( action_elem ):
- populated, repository_elem, error_message = handle_repository_dependency_elem( trans, repo_elem )
+ revised, repository_elem, error_message = handle_repository_dependency_elem( trans, repo_elem, unpopulate=unpopulate )
if error_message:
exception_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
raise Exception( exception_message )
- if populated:
+ if revised:
action_elem[ repo_index ] = repository_elem
package_altered = True
if not altered:
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/tool_shed/util/export_util.py
--- /dev/null
+++ b/lib/tool_shed/util/export_util.py
@@ -0,0 +1,255 @@
+import logging
+import os
+import shutil
+import tarfile
+import tempfile
+import threading
+import tool_shed.util.shed_util_common as suc
+from galaxy import eggs
+from galaxy import web
+from galaxy.util.odict import odict
+from tool_shed.util import commit_util
+from tool_shed.util import common_install_util
+from tool_shed.util import encoding_util
+from tool_shed.util import repository_dependency_util
+from tool_shed.util import xml_util
+
+eggs.require( 'mercurial' )
+
+import mercurial.util
+from mercurial import commands
+from mercurial import hg
+from mercurial import patch
+from mercurial import ui
+
+log = logging.getLogger( __name__ )
+
+
+class ExportedRepositoryRegistry( object ):
+
+ def __init__( self ):
+ self.exported_repository_elems = []
+
+def archive_repository_revision( trans, ui, repository, archive_dir, changeset_revision ):
+ '''Create an un-versioned archive of a repository.'''
+ repo = hg.repository( suc.get_configured_ui(), repository.repo_path( trans.app ) )
+ options_dict = suc.get_mercurial_default_options_dict( 'archive' )
+ options_dict[ 'rev' ] = changeset_revision
+ error_message = ''
+ return_code = None
+ try:
+ return_code = commands.archive( ui, repo, archive_dir, **options_dict )
+ except Exception, e:
+ error_message = "Error attempting to archive revision <b>%s</b> of repository %s: %s\nReturn code: %s\n" % \
+ ( str( changeset_revision ), str( repository.name ), str( e ), str( return_code ) )
+ log.exception( error_message )
+ return return_code, error_message
+
+def export_repository( trans, tool_shed_url, repository_id, repository_name, changeset_revision, file_type, export_repository_dependencies, api=False ):
+ file_type_str = suc.get_file_type_str( changeset_revision, file_type )
+ tmp_archive_dir = tempfile.mkdtemp( prefix="tmp-toolshed-arcdir" )
+ if export_repository_dependencies:
+ repositories_archive_filename = os.path.join( tmp_archive_dir, 'exported-with-dependencies-%s-%s' % ( repository_name, file_type_str ) )
+ repo_info_dicts = get_repo_info_dicts( trans, tool_shed_url, repository_id, changeset_revision )
+ repository_ids = get_repository_ids( trans, repo_info_dicts )
+ ordered_repository_ids, ordered_repositories, ordered_changeset_revisions = order_components_for_import( trans, repository_ids, repo_info_dicts )
+ else:
+ ordered_repository_ids = []
+ ordered_repositories = []
+ ordered_changeset_revisions = []
+ repositories_archive_filename = os.path.join( tmp_archive_dir, 'exported-%s-%s' % ( repository_name, file_type_str ) )
+ repository = suc.get_repository_in_tool_shed( trans, repository_id )
+ if repository:
+ repository_metadata = suc.get_current_repository_metadata_for_changeset_revision( trans, repository, changeset_revision )
+ if repository_metadata:
+ ordered_repository_ids = [ repository_id ]
+ ordered_repositories = [ repository ]
+ ordered_changeset_revisions = [ repository_metadata.changeset_revision ]
+ repositories_archive = None
+ error_messages = ''
+ lock = threading.Lock()
+ lock.acquire( True )
+ try:
+ repositories_archive = tarfile.open( repositories_archive_filename, "w:%s" % file_type )
+ exported_repository_registry = ExportedRepositoryRegistry()
+ for index, repository_id in enumerate( ordered_repository_ids ):
+ work_dir = tempfile.mkdtemp( prefix="tmp-toolshed-export-er" )
+ ordered_repository = ordered_repositories[ index ]
+ ordered_changeset_revision = ordered_changeset_revisions[ index ]
+ repository_archive, error_message = generate_repository_archive( trans, work_dir, tool_shed_url, ordered_repository, ordered_changeset_revision, file_type )
+ if error_message:
+ error_messages = '%s %s' % ( error_messages, error_message )
+ else:
+ archive_name = str( os.path.basename( repository_archive.name ) )
+ repositories_archive.add( repository_archive.name, arcname=archive_name )
+ attributes, sub_elements = get_repository_attributes_and_sub_elements( ordered_repository, archive_name )
+ elem = xml_util.create_element( 'repository', attributes=attributes, sub_elements=sub_elements )
+ exported_repository_registry.exported_repository_elems.append( elem )
+ shutil.rmtree( work_dir )
+ # Write the manifest, which must preserve the order in which the repositories should be imported.
+ tmp_xml_file = xml_util.create_and_write_tmp_file( exported_repository_registry.exported_repository_elems, use_indent=True )
+ repositories_archive.add( tmp_xml_file, arcname='manifest.xml' )
+ except Exception, e:
+ log.exception( str( e ) )
+ finally:
+ lock.release()
+ repositories_archive.close()
+ if api:
+ encoded_repositories_archive_name = encoding_util.tool_shed_encode( repositories_archive_filename )
+ download_url = suc.url_join( web.url_for( '/', qualified=True ),
+ 'repository/export_via_api?encoded_repositories_archive_name=%s' % encoded_repositories_archive_name )
+ return dict( download_url=download_url, error_messages=error_messages )
+ return repositories_archive, error_messages
+
+def generate_repository_archive( trans, work_dir, tool_shed_url, repository, changeset_revision, file_type ):
+ file_type_str = suc.get_file_type_str( changeset_revision, file_type )
+ file_name = '%s-%s' % ( repository.name, file_type_str )
+ return_code, error_message = archive_repository_revision( trans, ui, repository, work_dir, changeset_revision )
+ if return_code:
+ return None, error_message
+ repository_archive_name = os.path.join( work_dir, file_name )
+ # Create a compressed tar archive that will contain only valid files and possibly altered dependency definition files.
+ repository_archive = tarfile.open( repository_archive_name, "w:%s" % file_type )
+ for root, dirs, files in os.walk( work_dir ):
+ if root.find( '.hg' ) < 0 and root.find( 'hgrc' ) < 0:
+ for dir in dirs:
+ if dir in commit_util.UNDESIRABLE_DIRS:
+ dirs.remove( dir )
+ for name in files:
+ name = str( name )
+ if str( name ) in commit_util.UNDESIRABLE_FILES:
+ continue
+ full_path = os.path.join( root, name )
+ relative_path = full_path.replace( work_dir, '' ).lstrip( '/' )
+ # See if we have a repository dependencies defined.
+ if name == suc.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME:
+ # Eliminate the toolshed, and changeset_revision attributes from all <repository> tags.
+ altered, root_elem = commit_util.handle_repository_dependencies_definition( trans, full_path, unpopulate=True )
+ if altered:
+ tmp_filename = xml_util.create_and_write_tmp_file( root_elem, use_indent=True )
+ shutil.move( tmp_filename, full_path )
+ elif name == suc.TOOL_DEPENDENCY_DEFINITION_FILENAME:
+ # Eliminate the toolshed, and changeset_revision attributes from all <repository> tags.
+ altered, root_elem = commit_util.handle_tool_dependencies_definition( trans, full_path, unpopulate=True )
+ if altered:
+ tmp_filename = xml_util.create_and_write_tmp_file( root_elem, use_indent=True )
+ shutil.move( tmp_filename, full_path )
+ repository_archive.add( full_path, arcname=relative_path )
+ repository_archive.close()
+ return repository_archive, error_message
+
+def get_components_from_repo_info_dict( trans, repo_info_dict ):
+ """
+ Return the repository and the associated latest installable changeset_revision (including updates) for the repository defined by the received
+ repo_info_dict.
+ """
+ for repository_name, repo_info_tup in repo_info_dict.items():
+ # There should only be one entry in the received repo_info_dict.
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
+ suc.get_repo_info_tuple_contents( repo_info_tup )
+ repository = suc.get_repository_by_name_and_owner( trans.app, repository_name, repository_owner )
+ repository_metadata = suc.get_current_repository_metadata_for_changeset_revision( trans, repository, changeset_revision )
+ if repository_metadata:
+ return repository, repository_metadata.changeset_revision
+ return None, None
+
+def get_repo_info_dict_for_import( encoded_repository_id, encoded_repository_ids, repo_info_dicts ):
+ """
+ The received encoded_repository_ids and repo_info_dicts are lists that contain associated elements at each location in the list. This method will return the element
+ from repo_info_dicts associated with the received encoded_repository_id by determining it's location in the received encoded_repository_ids list.
+ """
+ for index, repository_id in enumerate( encoded_repository_ids ):
+ if repository_id == encoded_repository_id:
+ repo_info_dict = repo_info_dicts[ index ]
+ return repo_info_dict
+ return None
+
+def get_repo_info_dicts( trans, tool_shed_url, repository_id, changeset_revision ):
+ repository = suc.get_repository_in_tool_shed( trans, repository_id )
+ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
+ # Get a dictionary of all repositories upon which the contents of the current repository_metadata record depend.
+ repository_dependencies = \
+ repository_dependency_util.get_repository_dependencies_for_changeset_revision( trans=trans,
+ repository=repository,
+ repository_metadata=repository_metadata,
+ toolshed_base_url=str( web.url_for( '/', qualified=True ) ).rstrip( '/' ),
+ key_rd_dicts_to_be_processed=None,
+ all_repository_dependencies=None,
+ handled_key_rd_dicts=None )
+ repo = hg.repository( suc.get_configured_ui(), repository.repo_path( trans.app ) )
+ ctx = suc.get_changectx_for_changeset( repo, changeset_revision )
+ repo_info_dict = {}
+ # Cast unicode to string.
+ repo_info_dict[ str( repository.name ) ] = ( str( repository.description ),
+ suc.generate_clone_url_for_repository_in_tool_shed( trans, repository ),
+ str( changeset_revision ),
+ str( ctx.rev() ),
+ str( repository.user.username ),
+ repository_dependencies,
+ None )
+ all_required_repo_info_dict = common_install_util.get_required_repo_info_dicts( trans, tool_shed_url, [ repo_info_dict ] )
+ all_repo_info_dicts = all_required_repo_info_dict.get( 'all_repo_info_dicts', [] )
+ return all_repo_info_dicts
+
+def get_repository_attributes_and_sub_elements( repository, archive_name ):
+ """
+ Get the information about a repository to create and populate an XML tag set. The generated attributes will be contained within the <repository>
+ tag, while the sub_elements will be tag sets contained within the <repository> tag set.
+ """
+ attributes = odict()
+ sub_elements = odict()
+ attributes[ 'name' ] = str( repository.name )
+ attributes[ 'type' ] = str( repository.type )
+ # We have to associate the public username since the user_id will be different between tool sheds.
+ attributes[ 'username' ] = str( repository.user.username )
+ sub_elements[ 'description' ] = str( repository.description )
+ sub_elements[ 'long_description' ] = str( repository.long_description )
+ sub_elements[ 'archive' ] = archive_name
+ return attributes, sub_elements
+
+def get_repository_ids( trans, repo_info_dicts ):
+ repository_ids = []
+ for repo_info_dict in repo_info_dicts:
+ for repository_name, repo_info_tup in repo_info_dict.items():
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
+ suc.get_repo_info_tuple_contents( repo_info_tup )
+ repository = suc.get_repository_by_name_and_owner( trans.app, repository_name, repository_owner )
+ repository_ids.append( trans.security.encode_id( repository.id ) )
+ return repository_ids
+
+def order_components_for_import( trans, repository_ids, repo_info_dicts ):
+ """
+ Some repositories may have repository dependencies that must be imported and have metadata set on them before the dependent repository is imported. This method
+ will inspect the list of repositories about to be exported and make sure to order them appropriately for proper import. For each repository about to be exported,
+ if required repositories are not contained in the list of repositories about to be exported, then they are not considered. Repository dependency definitions that
+ contain circular dependencies should not result in an infinite loop, but obviously ordering the list will not be handled for one or more of the repositories that
+ require prior import.
+ """
+ ordered_repository_ids = []
+ ordered_repositories = []
+ ordered_changeset_revisions = []
+ # Create a dictionary whose keys are the received repository_ids and whose values are a list of repository_ids, each of which is contained in the received list of
+ # repository_ids and whose associated repository must be imported prior to the repository associated with the repository_id key.
+ prior_import_required_dict = suc.get_prior_import_or_install_required_dict( trans, repository_ids, repo_info_dicts )
+ processed_repository_ids = []
+ while len( processed_repository_ids ) != len( prior_import_required_dict.keys() ):
+ repository_id = suc.get_next_prior_import_or_install_required_dict_entry( prior_import_required_dict, processed_repository_ids )
+ processed_repository_ids.append( repository_id )
+ if repository_id not in ordered_repository_ids:
+ prior_import_required_ids = prior_import_required_dict[ repository_id ]
+ for prior_import_required_id in prior_import_required_ids:
+ if prior_import_required_id not in ordered_repository_ids:
+ # Import the associated repository dependency first.
+ prior_repo_info_dict = get_repo_info_dict_for_import( prior_import_required_id, repository_ids, repo_info_dicts )
+ prior_repository, prior_import_changeset_revision = get_components_from_repo_info_dict( trans, prior_repo_info_dict )
+ if prior_repository and prior_import_changeset_revision:
+ ordered_repository_ids.append( prior_import_required_id )
+ ordered_repositories.append( prior_repository )
+ ordered_changeset_revisions.append( prior_import_changeset_revision )
+ repo_info_dict = get_repo_info_dict_for_import( repository_id, repository_ids, repo_info_dicts )
+ repository, changeset_revision = get_components_from_repo_info_dict( trans, repo_info_dict )
+ if repository and changeset_revision:
+ ordered_repository_ids.append( repository_id )
+ ordered_repositories.append( repository )
+ ordered_changeset_revisions.append( changeset_revision )
+ return ordered_repository_ids, ordered_repositories, ordered_changeset_revisions
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -1614,7 +1614,6 @@
ancestor_changeset_revision = None
ancestor_metadata_dict = None
invalid_file_tups = []
- home_dir = os.getcwd()
for changeset in repository.get_changesets_for_setting_metadata( trans.app ):
work_dir = tempfile.mkdtemp( prefix="tmp-toolshed-ramorits" )
current_changeset_revision = str( repo.changectx( changeset ) )
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -7,6 +7,7 @@
from time import gmtime
from time import strftime
from galaxy import util
+from galaxy.util import asbool
from galaxy.util import json
from galaxy.util import unicodify
from galaxy.web import url_for
@@ -22,7 +23,10 @@
import pkg_resources
pkg_resources.require( 'mercurial' )
-from mercurial import hg, ui, commands
+from mercurial import cmdutil
+from mercurial import commands
+from mercurial import hg
+from mercurial import ui
eggs.require( 'markupsafe' )
import markupsafe
@@ -530,6 +534,20 @@
return manifest_ctx, ctx_file
return None, None
+def get_current_repository_metadata_for_changeset_revision( trans, repository, changeset_revision ):
+ encoded_repository_id = trans.security.encode_id( repository.id )
+ repository_metadata = get_repository_metadata_by_changeset_revision( trans, encoded_repository_id, changeset_revision )
+ if repository_metadata:
+ return repository_metadata
+ # The installable changeset_revision may have been changed because it was "moved ahead" in the repository changelog.
+ repo = hg.repository( get_configured_ui(), repository.repo_path( trans.app ) )
+ updated_changeset_revision = get_next_downloadable_changeset_revision( repository, repo, after_changeset_revision=changeset_revision )
+ if updated_changeset_revision:
+ repository_metadata = get_repository_metadata_by_changeset_revision( trans, encoded_repository_id, updated_changeset_revision )
+ if repository_metadata:
+ return repository_metadata
+ return None
+
def get_file_context_from_ctx( ctx, filename ):
"""Return the mercurial file context for a specified file."""
# We have to be careful in determining if we found the correct file because multiple files with the same name may be in different directories
@@ -552,6 +570,17 @@
return 'DELETED'
return None
+def get_file_type_str( changeset_revision, file_type ):
+ if file_type == 'zip':
+ file_type_str = '%s.zip' % changeset_revision
+ elif file_type == 'bz2':
+ file_type_str = '%s.tar.bz2' % changeset_revision
+ elif file_type == 'gz':
+ file_type_str = '%s.tar.gz' % changeset_revision
+ else:
+ file_type_str = ''
+ return file_type_str
+
def get_ids_of_tool_shed_repositories_being_installed( trans, as_string=False ):
installing_repository_ids = []
new_status = trans.model.ToolShedRepository.installation_status.NEW
@@ -594,6 +623,18 @@
return changeset_revisions[ -1 ]
return INITIAL_CHANGELOG_HASH
+def get_mercurial_default_options_dict( command, command_table=None, **kwd ):
+ '''Borrowed from repoman - get default parameters for a mercurial command.'''
+ if command_table is None:
+ command_table = commands.table
+ possible = cmdutil.findpossible( command, command_table )
+ if len( possible ) != 1:
+ raise Exception, 'unable to find mercurial command "%s"' % command
+ default_options_dict = dict( ( r[ 1 ].replace( '-', '_' ), r[ 2 ] ) for r in possible[ possible.keys()[ 0 ] ][ 1 ][ 1 ] )
+ for option in kwd:
+ default_options_dict[ option ] = kwd[ option ]
+ return default_options_dict
+
def get_named_tmpfile_from_ctx( ctx, filename, dir ):
"""Return a named temporary file created from a specified file with a given name included in a repository changeset revision."""
filename = strip_path( filename )
@@ -638,6 +679,36 @@
found_after_changeset_revision = True
return None
+def get_next_prior_import_or_install_required_dict_entry( prior_required_dict, processed_tsr_ids ):
+ """
+ This method is used in the Tool Shed when exporting a repository and it's dependencies, and in Galaxy when a repository and it's dependencies
+ are being installed. The order in which the prior_required_dict is processed is critical in order to ensure that the ultimate repository import
+ or installation order is correctly defined. This method determines the next key / value pair from the received prior_required_dict that should
+ be processed.
+ """
+ # Return the first key / value pair that is not yet processed and whose value is an empty list.
+ for key, value in prior_required_dict.items():
+ if key in processed_tsr_ids:
+ continue
+ if not value:
+ return key
+ # Return the first key / value pair that is not yet processed and whose ids in value are all included in processed_tsr_ids.
+ for key, value in prior_required_dict.items():
+ if key in processed_tsr_ids:
+ continue
+ all_contained = True
+ for required_repository_id in value:
+ if required_repository_id not in processed_tsr_ids:
+ all_contained = False
+ break
+ if all_contained:
+ return key
+ # Return the first key / value pair that is not yet processed. Hopefully this is all that is necessary at this point.
+ for key, value in prior_required_dict.items():
+ if key in processed_tsr_ids:
+ continue
+ return key
+
def get_or_create_tool_shed_repository( trans, tool_shed, name, owner, changeset_revision ):
"""
Return a tool shed repository database record defined by the combination of tool shed, repository name, repository owner and changeset_revision
@@ -703,6 +774,28 @@
else:
previous_changeset_revision = changeset_revision
+def get_prior_import_or_install_required_dict( trans, tsr_ids, repo_info_dicts ):
+ """
+ This method is used in the Tool Shed when exporting a repository and it's dependencies, and in Galaxy when a repository and it's dependencies
+ are being installed. Return a dictionary whose keys are the received tsr_ids and whose values are a list of tsr_ids, each of which is contained
+ in the received list of tsr_ids and whose associated repository must be imported or installed prior to the repository associated with the tsr_id key.
+ """
+ # Initialize the dictionary.
+ prior_import_or_install_required_dict = {}
+ for tsr_id in tsr_ids:
+ prior_import_or_install_required_dict[ tsr_id ] = []
+ # Inspect the repository dependencies for each repository about to be installed and populate the dictionary.
+ for repo_info_dict in repo_info_dicts:
+ repository, repository_dependencies = get_repository_and_repository_dependencies_from_repo_info_dict( trans, repo_info_dict )
+ if repository:
+ encoded_repository_id = trans.security.encode_id( repository.id )
+ if encoded_repository_id in tsr_ids:
+ # We've located the database table record for one of the repositories we're about to install, so find out if it has any repository
+ # dependencies that require prior installation.
+ prior_import_or_install_ids = get_repository_ids_requiring_prior_import_or_install( trans, tsr_ids, repository_dependencies )
+ prior_import_or_install_required_dict[ encoded_repository_id ] = prior_import_or_install_ids
+ return prior_import_or_install_required_dict
+
def get_repo_info_tuple_contents( repo_info_tuple ):
"""Take care in handling the repo_info_tuple as it evolves over time as new tool shed features are introduced."""
if len( repo_info_tuple ) == 6:
@@ -712,6 +805,20 @@
description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = repo_info_tuple
return description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies
+def get_repository_and_repository_dependencies_from_repo_info_dict( trans, repo_info_dict ):
+ """Return a tool_shed_repository or repository record defined by the information in the received repo_info_dict."""
+ repository_name = repo_info_dict.keys()[ 0 ]
+ repo_info_tuple = repo_info_dict[ repository_name ]
+ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
+ get_repo_info_tuple_contents( repo_info_tuple )
+ if trans.webapp.name == 'galaxy':
+ tool_shed = get_tool_shed_from_clone_url( repository_clone_url )
+ repository = get_repository_for_dependency_relationship( trans.app, tool_shed, repository_name, repository_owner, changeset_revision )
+ else:
+ # We're in the tool shed.
+ repository = get_repository_by_name_and_owner( trans.app, repository_name, repository_owner )
+ return repository, repository_dependencies
+
def get_repository_by_id( trans, id ):
"""Get a repository from the database via id."""
if trans.webapp.name == 'galaxy':
@@ -745,7 +852,7 @@
return None
def get_repository_for_dependency_relationship( app, tool_shed, name, owner, changeset_revision ):
- """Return a tool shed repository database record that is defined by either the current changeset revision or the installed_changeset_revision."""
+ """Return an installed tool_shed_repository database record that is defined by either the current changeset revision or the installed_changeset_revision."""
# This method is used only in Galaxy, not the tool shed.
if tool_shed.endswith( '/' ):
tool_shed = tool_shed.rstrip( '/' )
@@ -821,6 +928,32 @@
# This should never be reached - raise an exception?
return v, None
+def get_repository_ids_requiring_prior_import_or_install( trans, tsr_ids, repository_dependencies ):
+ """
+ This method is used in the Tool Shed when exporting a repository and it's dependencies, and in Galaxy when a repository and it's dependencies
+ are being installed. Inspect the received repository_dependencies and determine if the encoded id of each required repository is in the received
+ tsr_ids. If so, then determine whether that required repository should be imported / installed prior to it's dependent repository. Return a list
+ of encoded repository ids, each of which is contained in the received list of tsr_ids, and whose associated repositories must be impoerted / installed
+ prior to the dependent repository associated with the received repository_dependencies.
+ """
+ prior_tsr_ids = []
+ if repository_dependencies:
+ for key, rd_tups in repository_dependencies.items():
+ if key in [ 'description', 'root_key' ]:
+ continue
+ for rd_tup in rd_tups:
+ tool_shed, name, owner, changeset_revision, prior_installation_required = parse_repository_dependency_tuple( rd_tup )
+ if asbool( prior_installation_required ):
+ if trans.webapp.name == 'galaxy':
+ repository = get_repository_for_dependency_relationship( trans.app, tool_shed, name, owner, changeset_revision )
+ else:
+ repository = get_repository_by_name_and_owner( trans.app, name, owner )
+ if repository:
+ encoded_repository_id = trans.security.encode_id( repository.id )
+ if encoded_repository_id in tsr_ids:
+ prior_tsr_ids.append( encoded_repository_id )
+ return prior_tsr_ids
+
def get_repository_in_tool_shed( trans, id ):
"""Get a repository on the tool shed side from the database via id."""
return trans.sa_session.query( trans.model.Repository ).get( trans.security.decode_id( id ) )
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a lib/tool_shed/util/xml_util.py
--- a/lib/tool_shed/util/xml_util.py
+++ b/lib/tool_shed/util/xml_util.py
@@ -2,6 +2,7 @@
import os
import sys
import tempfile
+from galaxy.util import listify
from xml.etree import ElementTree as XmlET
import xml.etree.ElementTree
@@ -30,8 +31,10 @@
self.data( data )
self.end( XmlET.Comment )
-def create_and_write_tmp_file( elem ):
- tmp_str = xml_to_string( elem )
+def create_and_write_tmp_file( elems, use_indent=False ):
+ tmp_str = ''
+ for elem in listify( elems ):
+ tmp_str += xml_to_string( elem, use_indent=use_indent )
fh = tempfile.NamedTemporaryFile( 'wb', prefix="tmp-toolshed-cawrf" )
tmp_filename = fh.name
fh.close()
@@ -41,6 +44,28 @@
fh.close()
return tmp_filename
+def create_element( tag, attributes=None, sub_elements=None ):
+ """
+ Create a new element whose tag is the value of the received tag, and whose attributes are all key / value pairs in the received the attributes
+ and sub_elements.
+ """
+ if tag:
+ elem = XmlET.Element( tag )
+ if attributes:
+ # The received attributes is an odict to preserve ordering.
+ for k, v in attributes.items():
+ elem.set( k, v )
+ if sub_elements:
+ # The received attributes is an odict as well. These handle information that tends to be long text including paragraphs (e.g.,
+ # description and long_description.
+ for k, v in sub_elements.items():
+ # Don't include fields that are blank.
+ if v:
+ sub_elem = XmlET.SubElement( elem, k )
+ sub_elem.text = v
+ return elem
+ return None
+
def indent( elem, level=0 ):
"""
Prints an XML tree with each node indented according to its depth. This method is used to print the shed tool config (e.g., shed_tool_conf.xml
@@ -86,11 +111,11 @@
fobj.close()
return tree, error_message
-def xml_to_string( elem, encoding='utf-8', use_indent=False ):
- if len( elem ):
+def xml_to_string( elem, encoding='utf-8', use_indent=False, level=0 ):
+ if elem is not None:
if use_indent:
# We were called from suc.config_elems_to_xml_file(), so set the level to 1 since level 0 is the <toolbox> tag set.
- indent( elem, level=1 )
+ indent( elem, level=level )
if using_python_27:
xml_str = '%s\n' % xml.etree.ElementTree.tostring( elem, encoding=encoding, method="xml" )
else:
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a scripts/api/repair_tool_shed_repository.py
--- a/scripts/api/repair_tool_shed_repository.py
+++ b/scripts/api/repair_tool_shed_repository.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python
"""
Repair a specified repository revision previously installed into Galaxy.
-</section>
Here is a working example of how to use this script to repair a repository installed into Galaxy.
./repair_tool_shed_repository.py --api <api key> --local <galaxy base url> --url http://testtoolshed.g2.bx.psu.edu --name gregs_filter --owner greg --revision f28d5018f9cb
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a templates/admin/tool_shed_repository/common.mako
--- a/templates/admin/tool_shed_repository/common.mako
+++ b/templates/admin/tool_shed_repository/common.mako
@@ -69,7 +69,7 @@
</script></%def>
-<%def name="render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict )">
+<%def name="render_dependencies_section( repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict, revision_label=None, export=False )"><style type="text/css">
#dependency_table{ table-layout:fixed;
width:100%;
@@ -89,27 +89,44 @@
def __str__( self ):
return str( self.count )
- repository_dependencies_root_folder = containers_dict[ 'repository_dependencies' ]
- tool_dependencies_root_folder = containers_dict[ 'tool_dependencies' ]
- missing_tool_dependencies_root_folder = containers_dict[ 'missing_tool_dependencies' ]
+ repository_dependencies_root_folder = containers_dict.get( 'repository_dependencies', None )
+ tool_dependencies_root_folder = containers_dict.get( 'tool_dependencies', None )
+ missing_tool_dependencies_root_folder = containers_dict.get( 'missing_tool_dependencies', None )
env_settings_heaader_row_displayed = False
package_header_row_displayed = False
+ if revision_label:
+ revision_label_str = ' revision <b>%s</b> of ' % str( revision_label )
+ else:
+ revision_label_str = ' '
%><div class="form-row"><div class="toolParamHelp" style="clear: both;"><p>
- These dependencies can be automatically handled with the installed repository, providing significant benefits, and
- Galaxy includes various features to manage them.
+ %if export:
+ The following additional repositories are required by${revision_label_str}the <b>${repository.name}</b> repository
+ and they can be exported as well.
+ %else:
+ These dependencies can be automatically handled with${revision_label_str}the installed repository, providing significant
+ benefits, and Galaxy includes various features to manage them.
+ %endif
</p></div></div>
%if repository_dependencies_root_folder:
- %if install_repository_dependencies_check_box is not None:
+ %if repository_dependencies_check_box is not None:
<div class="form-row">
- <label>Handle repository dependencies?</label>
- ${install_repository_dependencies_check_box.get_html()}
+ %if export:
+ <label>Export repository dependencies?</label>
+ %else:
+ <label>Handle repository dependencies?</label>
+ %endif
+ ${repository_dependencies_check_box.get_html()}
<div class="toolParamHelp" style="clear: both;">
- Un-check to skip automatic installation of these additional repositories required by this repository.
+ %if export:
+ Un-check to skip exporting the following additional repositories that are required by this repository.
+ %else:
+ Un-check to skip automatic installation of these additional repositories required by this repository.
+ %endif
</div></div><div style="clear: both"></div>
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a templates/admin/tool_shed_repository/reselect_tool_panel_section.mako
--- a/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako
+++ b/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako
@@ -39,7 +39,7 @@
<th bgcolor="#EBD9B2">Confirm dependency installation</th></table></div>
- ${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict )}
+ ${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict, revision_label=None, export=False )}
%endif
%if shed_tool_conf_select_field:
<div class="form-row">
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a templates/admin/tool_shed_repository/select_shed_tool_panel_config.mako
--- a/templates/admin/tool_shed_repository/select_shed_tool_panel_config.mako
+++ b/templates/admin/tool_shed_repository/select_shed_tool_panel_config.mako
@@ -78,7 +78,7 @@
<th bgcolor="#EBD9B2">Confirm dependency installation</th></table></div>
- ${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict )}
+ ${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict, revision_label=None, export=False )}
<div style="clear: both"></div>
%endif
<div class="form-row">
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a templates/admin/tool_shed_repository/select_tool_panel_section.mako
--- a/templates/admin/tool_shed_repository/select_tool_panel_section.mako
+++ b/templates/admin/tool_shed_repository/select_tool_panel_section.mako
@@ -78,7 +78,7 @@
<th bgcolor="#EBD9B2">Confirm dependency installation</th></table></div>
- ${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict )}
+ ${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict, revision_label=None, export=False )}
<div style="clear: both"></div>
%endif
%if shed_tool_conf_select_field:
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a templates/webapps/tool_shed/common/repository_actions_menu.mako
--- a/templates/webapps/tool_shed/common/repository_actions_menu.mako
+++ b/templates/webapps/tool_shed/common/repository_actions_menu.mako
@@ -174,6 +174,7 @@
<a class="action-button" target="galaxy_main" href="${h.url_for( controller='repository', action='deprecate', id=trans.security.encode_id( repository.id ), mark_deprecated=False )}">Mark repository as not deprecated</a>
%endif
%if can_download:
+ <a class="action-button" href="${h.url_for( controller='repository', action='export', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=changeset_revision )}">Export this revision</a><a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=repository.tip( trans.app ), file_type='gz' )}">Download as a .tar.gz file</a><a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=repository.tip( trans.app ), file_type='bz2' )}">Download as a .tar.bz2 file</a><a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), changeset_revision=repository.tip( trans.app ), file_type='zip' )}">Download as a zip file</a>
diff -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 -r 8ca6cfea19091f0d44be3eec3b3d18794133a39a templates/webapps/tool_shed/repository/export_repository.mako
--- /dev/null
+++ b/templates/webapps/tool_shed/repository/export_repository.mako
@@ -0,0 +1,47 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/webapps/tool_shed/repository/common.mako" import="*" />
+<%namespace file="/admin/tool_shed_repository/common.mako" import="*" />
+<%namespace file="/webapps/tool_shed/common/repository_actions_menu.mako" import="render_tool_shed_repository_actions" />
+
+<%!
+ def inherit(context):
+ if context.get('use_panels'):
+ return '/webapps/tool_shed/base_panels.mako'
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
+
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+ ${h.css( "library" )}
+</%def>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${container_javascripts()}
+</%def>
+
+${render_tool_shed_repository_actions( repository )}
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Repository '${repository.name | h}'</div>
+ <div class="toolFormBody">
+ <form name="export_repository" id="export_repository" action="${h.url_for( controller='repository', action='export', repository_id=trans.security.encode_id( repository.id ), changeset_revision=changeset_revision )}" method="post" >
+ %if containers_dict is not None and export_repository_dependencies_check_box is not None:
+ ${render_dependencies_section( export_repository_dependencies_check_box, None, containers_dict, revision_label=revision_label, export=True )}
+ <div style="clear: both"></div>
+ %else:
+ No repository dependencies are defined for revision <b>${revision_label}</b> of this repository, so click <b>Export</b> to export the selected revision.
+ %endif
+ <div class="form-row">
+ <input type="submit" name="export_repository_button" value="Export"/>
+ </div>
+ </form>
+ </div>
+</div>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a2fcb4655e0f/
Changeset: a2fcb4655e0f
Branch: next-stable
User: natefoo
Date: 2013-08-02 22:39:05
Summary: Merge changes from stable.
Affected #: 3 files
diff -r 96eba6391a06e7e6230e06208347dfb51a64a1e1 -r a2fcb4655e0faa0bebb062a54cad05e448ed6c51 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -264,6 +264,7 @@
self.datatypes_config = kwargs.get( 'datatypes_config_file', 'datatypes_conf.xml' )
# Cloud configuration options
self.enable_cloud_launch = string_as_bool( kwargs.get( 'enable_cloud_launch', False ) )
+ self.cloudlaunch_default_ami = kwargs.get( 'cloudlaunch_default_ami', 'ami-118bfc78' )
# Galaxy messaging (AMQP) configuration options
self.amqp = {}
try:
diff -r 96eba6391a06e7e6230e06208347dfb51a64a1e1 -r a2fcb4655e0faa0bebb062a54cad05e448ed6c51 lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py
--- a/lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py
+++ b/lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py
@@ -26,7 +26,6 @@
PKEY_PREFIX = 'gxy_pkey'
DEFAULT_KEYPAIR = 'cloudman_keypair'
-DEFAULT_AMI = 'ami-da58aab3'
class CloudController(BaseUIController):
@@ -96,7 +95,7 @@
return to_json_string(account_info)
@web.expose
- def launch_instance(self, trans, cluster_name, password, key_id, secret, instance_type, share_string, keypair, ami=DEFAULT_AMI, zone=None, bucket_default=None, **kwargs):
+ def launch_instance(self, trans, cluster_name, password, key_id, secret, instance_type, share_string, keypair, ami=None, zone=None, bucket_default=None, **kwargs):
ec2_error = None
try:
# Create security group & key pair used when starting an instance
@@ -120,6 +119,9 @@
if bucket_default:
user_provided_data['bucket_default'] = bucket_default
+ if not ami:
+ ami = trans.app.config.cloudlaunch_default_ami
+
rs = run_instance(ec2_conn=ec2_conn,
image_id = ami,
user_provided_data=user_provided_data,
diff -r 96eba6391a06e7e6230e06208347dfb51a64a1e1 -r a2fcb4655e0faa0bebb062a54cad05e448ed6c51 universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -324,9 +324,10 @@
# Note that this requires java > 1.4 for executing yuicompressor.jar
#pack_scripts = False
-# Enable Cloud Launch
+# Cloud Launch
#enable_cloud_launch = False
+#cloudlaunch_default_ami = ami-118bfc78
# -- Advanced proxy features
https://bitbucket.org/galaxy/galaxy-central/commits/436ca79f8211/
Changeset: 436ca79f8211
User: natefoo
Date: 2013-08-02 22:39:52
Summary: Merge stable.
Affected #: 3 files
diff -r 57c593cc70a1de89f32e77833cbf1e329cf52c6b -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -264,6 +264,7 @@
self.datatypes_config = kwargs.get( 'datatypes_config_file', 'datatypes_conf.xml' )
# Cloud configuration options
self.enable_cloud_launch = string_as_bool( kwargs.get( 'enable_cloud_launch', False ) )
+ self.cloudlaunch_default_ami = kwargs.get( 'cloudlaunch_default_ami', 'ami-118bfc78' )
# Galaxy messaging (AMQP) configuration options
self.amqp = {}
try:
diff -r 57c593cc70a1de89f32e77833cbf1e329cf52c6b -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py
--- a/lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py
+++ b/lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py
@@ -26,7 +26,6 @@
PKEY_PREFIX = 'gxy_pkey'
DEFAULT_KEYPAIR = 'cloudman_keypair'
-DEFAULT_AMI = 'ami-da58aab3'
class CloudController(BaseUIController):
@@ -96,7 +95,7 @@
return to_json_string(account_info)
@web.expose
- def launch_instance(self, trans, cluster_name, password, key_id, secret, instance_type, share_string, keypair, ami=DEFAULT_AMI, zone=None, bucket_default=None, **kwargs):
+ def launch_instance(self, trans, cluster_name, password, key_id, secret, instance_type, share_string, keypair, ami=None, zone=None, bucket_default=None, **kwargs):
ec2_error = None
try:
# Create security group & key pair used when starting an instance
@@ -120,6 +119,9 @@
if bucket_default:
user_provided_data['bucket_default'] = bucket_default
+ if not ami:
+ ami = trans.app.config.cloudlaunch_default_ami
+
rs = run_instance(ec2_conn=ec2_conn,
image_id = ami,
user_provided_data=user_provided_data,
diff -r 57c593cc70a1de89f32e77833cbf1e329cf52c6b -r 436ca79f821132163526fa9bf1f7d6b7fe3f13c7 universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -324,9 +324,10 @@
# Note that this requires java > 1.4 for executing yuicompressor.jar
#pack_scripts = False
-# Enable Cloud Launch
+# Cloud Launch
#enable_cloud_launch = False
+#cloudlaunch_default_ami = ami-118bfc78
# -- Advanced proxy features
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Explicitly set TEMP dir in Local Runner, when a temp dir value is not already set.
by commits-noreply@bitbucket.org 02 Aug '13
by commits-noreply@bitbucket.org 02 Aug '13
02 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/57c593cc70a1/
Changeset: 57c593cc70a1
User: dan
Date: 2013-08-02 19:28:22
Summary: Explicitly set TEMP dir in Local Runner, when a temp dir value is not already set.
Affected #: 1 file
diff -r 22fb05ea1b47953070570e5622ea4e37ea87ac45 -r 57c593cc70a1de89f32e77833cbf1e329cf52c6b lib/galaxy/jobs/runners/local.py
--- a/lib/galaxy/jobs/runners/local.py
+++ b/lib/galaxy/jobs/runners/local.py
@@ -26,11 +26,18 @@
def __init__( self, app, nworkers ):
"""Start the job runner """
+ #create a local copy of os.environ to use as env for subprocess.Popen
+ self._environ = os.environ.copy()
+
# put lib into the PYTHONPATH for subprocesses
- if 'PYTHONPATH' in os.environ:
- os.environ['PYTHONPATH'] = '%s:%s' % ( os.environ['PYTHONPATH'], os.path.abspath( 'lib' ) )
+ if 'PYTHONPATH' in self._environ:
+ self._environ['PYTHONPATH'] = '%s:%s' % ( self._environ['PYTHONPATH'], os.path.abspath( 'lib' ) )
else:
- os.environ['PYTHONPATH'] = os.path.abspath( 'lib' )
+ self._environ['PYTHONPATH'] = os.path.abspath( 'lib' )
+
+ #Set TEMP if a valid temp value is not already set
+ if not ( 'TMPDIR' in self._environ or 'TEMP' in self._environ or 'TMP' in self._environ ):
+ self._environ[ 'TEMP' ] = tempfile.gettempdir()
super( LocalJobRunner, self ).__init__( app, nworkers )
self._init_worker_threads()
@@ -57,7 +64,7 @@
cwd = job_wrapper.working_directory,
stdout = stdout_file,
stderr = stderr_file,
- env = os.environ,
+ env = self._environ,
preexec_fn = os.setpgrp )
job_wrapper.set_job_destination(job_wrapper.job_destination, proc.pid)
job_wrapper.change_state( model.Job.states.RUNNING )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Explicitly set the test_install_error in the automated testing framework when a repository installs and passes or fails functional tests.
by commits-noreply@bitbucket.org 02 Aug '13
by commits-noreply@bitbucket.org 02 Aug '13
02 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/22fb05ea1b47/
Changeset: 22fb05ea1b47
User: Dave Bouvier
Date: 2013-08-02 19:13:07
Summary: Explicitly set the test_install_error in the automated testing framework when a repository installs and passes or fails functional tests.
Affected #: 1 file
diff -r 59243394031ab93acb5f76b2ea1ed10a6b685533 -r 22fb05ea1b47953070570e5622ea4e37ea87ac45 test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -1057,6 +1057,7 @@
repositories_passed.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
params[ 'tools_functionally_correct' ] = True
params[ 'do_not_test' ] = False
+ params[ 'test_install_error' ] = False
register_test_result( galaxy_tool_shed_url,
metadata_revision_id,
repository_status,
@@ -1108,6 +1109,7 @@
repositories_failed.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
set_do_not_test = not is_latest_downloadable_revision( galaxy_tool_shed_url, repository_info_dict )
params[ 'tools_functionally_correct' ] = False
+ params[ 'test_install_error' ] = False
params[ 'do_not_test' ] = str( set_do_not_test )
register_test_result( galaxy_tool_shed_url,
metadata_revision_id,
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Fix the install and test framework's handling of external metadata.
by commits-noreply@bitbucket.org 02 Aug '13
by commits-noreply@bitbucket.org 02 Aug '13
02 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/59243394031a/
Changeset: 59243394031a
User: Dave Bouvier
Date: 2013-08-02 16:53:41
Summary: Fix the install and test framework's handling of external metadata.
Affected #: 1 file
diff -r 5b9ebcc05ea7f187c2a2f528f643bfda30756e5b -r 59243394031ab93acb5f76b2ea1ed10a6b685533 test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -6,6 +6,7 @@
import os, sys, shutil, tempfile, re, string, urllib, platform
from time import strftime
+from ConfigParser import SafeConfigParser
# Assume we are run from the galaxy root directory, add lib to the python path
cwd = os.getcwd()
@@ -73,6 +74,40 @@
default_galaxy_test_port_max = 10999
default_galaxy_test_host = '127.0.0.1'
+# should this serve static resources (scripts, images, styles, etc.)
+STATIC_ENABLED = True
+
+def get_static_settings():
+ """Returns dictionary of the settings necessary for a galaxy App
+ to be wrapped in the static middleware.
+
+ This mainly consists of the filesystem locations of url-mapped
+ static resources.
+ """
+ cwd = os.getcwd()
+ static_dir = os.path.join( cwd, 'static' )
+ #TODO: these should be copied from universe_wsgi.ini
+ return dict(
+ #TODO: static_enabled needed here?
+ static_enabled = True,
+ static_cache_time = 360,
+ static_dir = static_dir,
+ static_images_dir = os.path.join( static_dir, 'images', '' ),
+ static_favicon_dir = os.path.join( static_dir, 'favicon.ico' ),
+ static_scripts_dir = os.path.join( static_dir, 'scripts', '' ),
+ static_style_dir = os.path.join( static_dir, 'june_2007_style', 'blue' ),
+ static_robots_txt = os.path.join( static_dir, 'robots.txt' ),
+ )
+
+def get_webapp_global_conf():
+ """Get the global_conf dictionary sent as the first argument to app_factory.
+ """
+ # (was originally sent 'dict()') - nothing here for now except static settings
+ global_conf = dict()
+ if STATIC_ENABLED:
+ global_conf.update( get_static_settings() )
+ return global_conf
+
# Optionally, set the environment variable GALAXY_INSTALL_TEST_TOOL_SHEDS_CONF
# to the location of a tool sheds configuration file that includes the tool shed
# that repositories will be installed from.
@@ -219,6 +254,36 @@
success = result.wasSuccessful()
return success
+def generate_config_file( input_filename, output_filename, config_items ):
+ '''
+ Generate a config file with the configuration that has been defined for the embedded web application.
+ This is mostly relevant when setting metadata externally, since the script for doing that does not
+ have access to app.config.
+ '''
+ cp = SafeConfigParser()
+ cp.read( input_filename )
+ config_items_by_section = []
+ for label, value in config_items:
+ found = False
+ # Attempt to determine the correct section for this configuration option.
+ for section in cp.sections():
+ if cp.has_option( section, label ):
+ config_tuple = section, label, value
+ config_items_by_section.append( config_tuple )
+ found = True
+ continue
+ # Default to app:main if no section was found.
+ if not found:
+ config_tuple = 'app:main', label, value
+ config_items_by_section.append( config_tuple )
+ # Replace the default values with the provided configuration.
+ for section, label, value in config_items_by_section:
+ cp.remove_option( section, label )
+ cp.set( section, label, str( value ) )
+ fh = open( output_filename, 'w' )
+ cp.write( fh )
+ fh.close()
+
def get_api_url( base, parts=[], params=None, key=None ):
if 'api' in parts and parts.index( 'api' ) != 0:
parts.pop( parts.index( 'api' ) )
@@ -554,48 +619,64 @@
# Generate the migrated_tool_conf.xml file.
migrated_tool_conf_xml = tool_conf_template_parser.safe_substitute( shed_tool_path=galaxy_migrated_tool_path )
file( galaxy_migrated_tool_conf_file, 'w' ).write( migrated_tool_conf_xml )
-
+ # Write the embedded web application's specific configuration to a temporary file. This is necessary in order for
+ # the external metadata script to find the right datasets.
+ kwargs = dict( admin_users = 'test(a)bx.psu.edu',
+ allow_user_creation = True,
+ allow_user_deletion = True,
+ allow_library_path_paste = True,
+ database_connection = database_connection,
+ datatype_converters_config_file = "datatype_converters_conf.xml.sample",
+ file_path = galaxy_file_path,
+ id_secret = galaxy_encode_secret,
+ job_queue_workers = 5,
+ log_destination = "stdout",
+ migrated_tools_config = galaxy_migrated_tool_conf_file,
+ new_file_path = galaxy_tempfiles,
+ running_functional_tests = True,
+ shed_tool_data_table_config = shed_tool_data_table_conf_file,
+ shed_tool_path = galaxy_shed_tool_path,
+ template_path = "templates",
+ tool_config_file = ','.join( [ galaxy_tool_conf_file, galaxy_shed_tool_conf_file ] ),
+ tool_data_path = tool_data_path,
+ tool_data_table_config_path = galaxy_tool_data_table_conf_file,
+ tool_dependency_dir = tool_dependency_dir,
+ tool_path = tool_path,
+ tool_parse_help = False,
+ tool_sheds_config_file = galaxy_tool_sheds_conf_file,
+ update_integrated_tool_panel = False,
+ use_heartbeat = False )
+ galaxy_config_file = os.environ.get( 'GALAXY_INSTALL_TEST_INI_FILE', None )
+ # If the user has passed in a path for the .ini file, do not overwrite it.
+ if not galaxy_config_file:
+ galaxy_config_file = os.path.join( galaxy_test_tmp_dir, 'install_test_tool_shed_repositories_wsgi.ini' )
+ config_items = []
+ for label in kwargs:
+ config_tuple = label, kwargs[ label ]
+ config_items.append( config_tuple )
+ # Write a temporary file, based on universe_wsgi.ini.sample, using the configuration options defined above.
+ generate_config_file( 'universe_wsgi.ini.sample', galaxy_config_file, config_items )
+ kwargs[ 'tool_config_file' ] = [ galaxy_tool_conf_file, galaxy_shed_tool_conf_file ]
+ # Set the global_conf[ '__file__' ] option to the location of the temporary .ini file, which gets passed to set_metadata.sh.
+ kwargs[ 'global_conf' ] = get_webapp_global_conf()
+ kwargs[ 'global_conf' ][ '__file__' ] = galaxy_config_file
# ---- Build Galaxy Application --------------------------------------------------
- global_conf = { '__file__' : 'universe_wsgi.ini.sample' }
if not database_connection.startswith( 'sqlite://' ):
kwargs[ 'database_engine_option_max_overflow' ] = '20'
kwargs[ 'database_engine_option_pool_size' ] = '10'
- app = UniverseApplication( admin_users = 'test(a)bx.psu.edu',
- allow_user_creation = True,
- allow_user_deletion = True,
- allow_library_path_paste = True,
- database_connection = database_connection,
- datatype_converters_config_file = "datatype_converters_conf.xml.sample",
- file_path = galaxy_file_path,
- global_conf = global_conf,
- id_secret = galaxy_encode_secret,
- job_queue_workers = 5,
- log_destination = "stdout",
- migrated_tools_config = galaxy_migrated_tool_conf_file,
- new_file_path = galaxy_tempfiles,
- running_functional_tests=True,
- shed_tool_data_table_config = shed_tool_data_table_conf_file,
- shed_tool_path = galaxy_shed_tool_path,
- template_path = "templates",
- tool_config_file = [ galaxy_tool_conf_file, galaxy_shed_tool_conf_file ],
- tool_data_path = tool_data_path,
- tool_data_table_config_path = galaxy_tool_data_table_conf_file,
- tool_dependency_dir = tool_dependency_dir,
- tool_path = tool_path,
- tool_parse_help = False,
- tool_sheds_config_file = galaxy_tool_sheds_conf_file,
- update_integrated_tool_panel = False,
- use_heartbeat = False,
- **kwargs )
+ kwargs[ 'config_file' ] = galaxy_config_file
+ app = UniverseApplication( **kwargs )
log.info( "Embedded Galaxy application started" )
# ---- Run galaxy webserver ------------------------------------------------------
server = None
- webapp = buildapp.app_factory( dict( database_file=database_connection ),
- use_translogger=False,
- static_enabled=False,
- app=app )
+ global_conf = get_webapp_global_conf()
+ global_conf[ 'database_file' ] = database_connection
+ webapp = buildapp.app_factory( global_conf,
+ use_translogger=False,
+ static_enabled=STATIC_ENABLED,
+ app=app )
# Serve the app on a specified or random port.
if galaxy_test_port is not None:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/96eba6391a06/
Changeset: 96eba6391a06
Branch: next-stable
User: jgoecks
Date: 2013-08-02 01:38:24
Summary: Fix imports and parentheses spacing.
Affected #: 1 file
diff -r 208f93f6cdc00c6d866b8029b0f53990ce0bfadc -r 96eba6391a06e7e6230e06208347dfb51a64a1e1 lib/galaxy/visualization/data_providers/genome.py
--- a/lib/galaxy/visualization/data_providers/genome.py
+++ b/lib/galaxy/visualization/data_providers/genome.py
@@ -13,6 +13,7 @@
from galaxy.util.json import from_json_string
from bx.interval_index_file import Indexes
from bx.bbi.bigwig_file import BigWigFile
+from bx.bbi.bigbed_file import BigBedFile
from galaxy.util.lrucache import LRUCache
from galaxy.visualization.data_providers.basic import BaseDataProvider
from galaxy.visualization.data_providers.cigar import get_ref_based_read_seq_and_cigar
@@ -861,14 +862,14 @@
"""
Returns an iterator that provides data in the region chrom:start-end
"""
- start, end = int(start), int(end)
+ start, end = int( start ), int( end )
orig_data_filename = self.original_dataset.file_name
index_filename = self.converted_dataset.file_name
# Attempt to open the BAM file with index
bamfile = csamtools.Samfile( filename=orig_data_filename, mode='rb', index_filename=index_filename )
try:
- data = bamfile.fetch(start=start, end=end, reference=chrom)
+ data = bamfile.fetch( start=start, end=end, reference=chrom )
except ValueError, e:
# Try alternative chrom naming.
chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
https://bitbucket.org/galaxy/galaxy-central/commits/5b9ebcc05ea7/
Changeset: 5b9ebcc05ea7
User: jgoecks
Date: 2013-08-02 01:38:49
Summary: Automated merge of next-stable branch
Affected #: 1 file
diff -r 318f84a819ef9d71dbfffa700d93665b596ef440 -r 5b9ebcc05ea7f187c2a2f528f643bfda30756e5b lib/galaxy/visualization/data_providers/genome.py
--- a/lib/galaxy/visualization/data_providers/genome.py
+++ b/lib/galaxy/visualization/data_providers/genome.py
@@ -13,6 +13,7 @@
from galaxy.util.json import from_json_string
from bx.interval_index_file import Indexes
from bx.bbi.bigwig_file import BigWigFile
+from bx.bbi.bigbed_file import BigBedFile
from galaxy.util.lrucache import LRUCache
from galaxy.visualization.data_providers.basic import BaseDataProvider
from galaxy.visualization.data_providers.cigar import get_ref_based_read_seq_and_cigar
@@ -861,14 +862,14 @@
"""
Returns an iterator that provides data in the region chrom:start-end
"""
- start, end = int(start), int(end)
+ start, end = int( start ), int( end )
orig_data_filename = self.original_dataset.file_name
index_filename = self.converted_dataset.file_name
# Attempt to open the BAM file with index
bamfile = csamtools.Samfile( filename=orig_data_filename, mode='rb', index_filename=index_filename )
try:
- data = bamfile.fetch(start=start, end=end, reference=chrom)
+ data = bamfile.fetch( start=start, end=end, reference=chrom )
except ValueError, e:
# Try alternative chrom naming.
chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: API Documentation: small fixes for histories, history_contents
by commits-noreply@bitbucket.org 01 Aug '13
by commits-noreply@bitbucket.org 01 Aug '13
01 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/318f84a819ef/
Changeset: 318f84a819ef
User: carlfeberhard
Date: 2013-08-01 21:35:45
Summary: API Documentation: small fixes for histories, history_contents
Affected #: 2 files
diff -r 8be96f5579e7f228fac8e7b70ac4bbec261b445d -r 318f84a819ef9d71dbfffa700d93665b596ef440 lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -28,9 +28,7 @@
return undeleted histories for the current user
* GET /api/histories/deleted:
return deleted histories for the current user
-
- If the user is logged-in, a full list of all histories is shown.
- If not logged in, only the curernt history (if any) is shown.
+ .. note:: Anonymous users are allowed to get their current history
:type deleted: boolean
:param deleted: if True, show only deleted histories, if False, non-deleted
@@ -76,6 +74,7 @@
return the deleted history with ``id``
* GET /api/histories/most_recently_used:
return the most recently used history
+ .. note:: Anonymous users are allowed to get their current history
:type id: an encoded id string
:param id: the encoded id of the history to query or the string 'most_recently_used'
@@ -127,8 +126,8 @@
create a new history
:type payload: dict
- :param payload: (optional) dictionary structure containing::
- 'name': the new history's name
+ :param payload: (optional) dictionary structure containing:
+ * name: the new history's name
:rtype: dict
:returns: element view of new history
@@ -159,16 +158,16 @@
:type id: str
:param id: the encoded id of the history to delete
:type kwd: dict
- :param kwd: (optional) dictionary structure containing::
- 'payload': a dictionary itself containing::
- 'purge': if True, purge the history and all of it's HDAs
+ :param kwd: (optional) dictionary structure containing:
+
+ * payload: a dictionary itself containing:
+ * purge: if True, purge the history and all of it's HDAs
:rtype: dict
- :returns: an error object if an error occurred or a dictionary containing::
-
- id: the encoded id of the history,
- deleted: if the history was marked as deleted,
- purged: if the history was purged
+ :returns: an error object if an error occurred or a dictionary containing:
+ * id: the encoded id of the history,
+ * deleted: if the history was marked as deleted,
+ * purged: if the history was purged
"""
history_id = id
# a request body is optional here
@@ -255,9 +254,9 @@
:param id: the encoded id of the history to undelete
:type payload: dict
:param payload: a dictionary containing any or all the
- fields in :func:`galaxy.model.History.get_api_value` and/or the following::
+ fields in :func:`galaxy.model.History.get_api_value` and/or the following:
- 'annotation': an annotation for the history
+ * annotation: an annotation for the history
:rtype: dict
:returns: an error object if an error occurred or a dictionary containing
@@ -330,4 +329,3 @@
pass
#log.warn( 'unknown key: %s', str( key ) )
return validated_payload
-
diff -r 8be96f5579e7f228fac8e7b70ac4bbec261b445d -r 318f84a819ef9d71dbfffa700d93665b596ef440 lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -18,28 +18,24 @@
index( self, trans, history_id, ids=None, **kwd )
* GET /api/histories/{history_id}/contents
return a list of HDA data for the history with the given ``id``
+ .. note:: Anonymous users are allowed to get their current history contents
+
+ If Ids is not given, index returns a list of *summary* objects for
+ every HDA associated with the given `history_id`.
+
+ If ids is given, index returns a *more complete* json object for each
+ HDA in the ids list.
:type history_id: str
:param history_id: encoded id string of the HDA's History
:type ids: str
:param ids: (optional) a comma separated list of encoded `HDA` ids
- If Ids is not given, index returns a list of *summary* objects for
- every HDA associated with the given `history_id`.
-
- .. seealso::
- :func:`_summary_hda_dict`
-
- If ids is given, index returns a *more complete* json object for each
- HDA in the ids list.
-
- .. seealso::
- :func:`galaxy.web.base.controller.UsesHistoryDatasetAssociationMixin.get_hda_dict`
-
- .. note:: Anonymous users are allowed to get their current history contents
-
:rtype: list
:returns: dictionaries containing summary or detailed HDA information
+ .. seealso::
+ :func:`_summary_hda_dict` and
+ :func:`galaxy.web.base.controller.UsesHistoryDatasetAssociationMixin.get_hda_dict`
"""
rval = []
try:
@@ -111,18 +107,16 @@
show( self, trans, id, history_id, **kwd )
* GET /api/histories/{history_id}/contents/{id}
return detailed information about an HDA within a history
+ .. note:: Anonymous users are allowed to get their current history contents
:type id: str
:param ids: the encoded id of the HDA to return
:type history_id: str
:param history_id: encoded id string of the HDA's History
- .. seealso:: :func:`galaxy.web.base.controller.UsesHistoryDatasetAssociationMixin.get_hda_dict`
-
- .. note:: Anonymous users are allowed to get their current history contents
-
:rtype: dict
:returns: dictionary containing detailed HDA information
+ .. seealso:: :func:`galaxy.web.base.controller.UsesHistoryDatasetAssociationMixin.get_hda_dict`
"""
hda_dict = {}
try:
@@ -217,9 +211,9 @@
:type payload: dict
:param payload: a dictionary containing any or all the
fields in :func:`galaxy.model.HistoryDatasetAssociation.get_api_value`
- and/or the following::
+ and/or the following:
- 'annotation': an annotation for the history
+ * annotation: an annotation for the HDA
:rtype: dict
:returns: an error object if an error occurred or a dictionary containing
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: API Documentation: libraries, library_contents
by commits-noreply@bitbucket.org 01 Aug '13
by commits-noreply@bitbucket.org 01 Aug '13
01 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8be96f5579e7/
Changeset: 8be96f5579e7
User: carlfeberhard
Date: 2013-08-01 21:21:46
Summary: API Documentation: libraries, library_contents
Affected #: 2 files
diff -r d34d6d1da813bfa6e318b0ceb563186e52d94095 -r 8be96f5579e7f228fac8e7b70ac4bbec261b445d lib/galaxy/webapps/galaxy/api/libraries.py
--- a/lib/galaxy/webapps/galaxy/api/libraries.py
+++ b/lib/galaxy/webapps/galaxy/api/libraries.py
@@ -15,9 +15,18 @@
@web.expose_api
def index( self, trans, deleted='False', **kwd ):
"""
- GET /api/libraries
- GET /api/libraries/deleted
- Displays a collection (list) of libraries.
+ index( self, trans, deleted='False', **kwd )
+ * GET /api/libraries:
+ returns a list of summary data for libraries
+ * GET /api/libraries/deleted:
+ returns a list of summary data for deleted libraries
+
+ :type deleted: boolean
+ :param deleted: if True, show only deleted libraries, if False, non-deleted
+
+ :rtype: list
+ :returns: list of dictionaries containing library information
+ .. seealso:: :attr:`galaxy.model.Library.api_collection_visible_keys`
"""
log.debug( "LibrariesController.index: enter" )
query = trans.sa_session.query( trans.app.model.Library )
@@ -49,9 +58,20 @@
@web.expose_api
def show( self, trans, id, deleted='False', **kwd ):
"""
- GET /api/libraries/{encoded_library_id}
- GET /api/libraries/deleted/{encoded_library_id}
- Displays information about a library.
+ show( self, trans, id, deleted='False', **kwd )
+ * GET /api/libraries/{id}:
+ returns detailed information about a library
+ * GET /api/libraries/deleted/{id}:
+ returns detailed information about a deleted library
+
+ :type id: an encoded id string
+ :param id: the encoded id of the library
+ :type deleted: boolean
+ :param deleted: if True, allow information on a deleted library
+
+ :rtype: dictionary
+ :returns: detailed library information
+ .. seealso:: :attr:`galaxy.model.Library.api_element_visible_keys`
"""
log.debug( "LibraryContentsController.show: enter" )
library_id = id
@@ -75,8 +95,20 @@
@web.expose_api
def create( self, trans, payload, **kwd ):
"""
- POST /api/libraries
- Creates a new library.
+ create( self, trans, payload, **kwd )
+ * POST /api/libraries:
+ create a new library
+ .. note:: Currently, only admin users can create libraries.
+
+ :type payload: dict
+ :param payload: (optional) dictionary structure containing::
+ 'name': the new library's name
+ 'description': the new library's description
+ 'synopsis': the new library's synopsis
+
+ :rtype: dict
+ :returns: a dictionary containing the id, name, and 'show' url
+ of the new library
"""
if not trans.user_is_admin():
raise HTTPForbidden( detail='You are not authorized to create a new library.' )
@@ -102,6 +134,19 @@
@web.expose_api
def delete( self, trans, id, **kwd ):
+ """
+ delete( self, trans, id, **kwd )
+ * DELETE /api/histories/{id}
+ mark the library with the given ``id`` as deleted
+ .. note:: Currently, only admin users can delete libraries.
+
+ :type id: str
+ :param id: the encoded id of the library to delete
+
+ :rtype: dictionary
+ :returns: detailed library information
+ .. seealso:: :attr:`galaxy.model.Library.api_element_visible_keys`
+ """
if not trans.user_is_admin():
raise HTTPForbidden( detail='You are not authorized to delete libraries.' )
try:
diff -r d34d6d1da813bfa6e318b0ceb563186e52d94095 -r 8be96f5579e7f228fac8e7b70ac4bbec261b445d lib/galaxy/webapps/galaxy/api/library_contents.py
--- a/lib/galaxy/webapps/galaxy/api/library_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/library_contents.py
@@ -19,8 +19,21 @@
# TODO: Add parameter to only get top level of datasets/subfolders.
def index( self, trans, library_id, **kwd ):
"""
- GET /api/libraries/{encoded_library_id}/contents
- Displays a collection (list) of library contents (files and folders).
+ index( self, trans, library_id, **kwd )
+ * GET /api/libraries/{library_id}/contents:
+ return a list of library files and folders
+
+ :type library_id: str
+ :param library_id: encoded id string of the library that contains this item
+
+ :rtype: list
+ :returns: list of dictionaries of the form:
+
+ * id: the encoded id of the library item
+ * name: the 'libary path'
+ or relationship of the library item to the root
+ * type: 'file' or 'folder'
+ * url: the url to get detailed information on the library item
"""
rval = []
current_user_roles = trans.get_current_user_roles()
@@ -80,8 +93,20 @@
@web.expose_api
def show( self, trans, id, library_id, **kwd ):
"""
- GET /api/libraries/{encoded_library_id}/contents/{encoded_content_id}
- Displays information about a library content (file or folder).
+ show( self, trans, id, library_id, **kwd )
+ * GET /api/libraries/{library_id}/contents/{id}
+ return information about library file or folder
+
+ :type id: str
+ :param id: the encoded id of the library item to return
+ :type library_id: str
+ :param library_id: encoded id string of the library that contains this item
+
+ :rtype: dict
+ :returns: detailed library item information
+ .. seealso::
+ :func:`galaxy.model.LibraryDataset.get_api_value` and
+ :attr:`galaxy.model.LibraryFolder.api_element_visible_keys`
"""
class_name, content_id = self.__decode_library_content_id( trans, id )
if class_name == 'LibraryFolder':
@@ -93,8 +118,29 @@
@web.expose_api
def create( self, trans, library_id, payload, **kwd ):
"""
- POST /api/libraries/{encoded_library_id}/contents
- Creates a new library content item (file or folder).
+ create( self, trans, library_id, payload, **kwd )
+ * POST /api/libraries/{library_id}/contents:
+ create a new library file or folder
+
+ To copy an HDA into a library send ``create_type`` of 'file' and
+ the HDA's encoded id in ``from_hda_id`` (and optionally ``ldda_message``).
+
+ :type library_id: str
+ :param library_id: encoded id string of the library that contains this item
+ :type payload: dict
+ :param payload: dictionary structure containing:
+
+ * folder_id: the parent folder of the new item
+ * create_type: the type of item to create ('file' or 'folder')
+ * from_hda_id: (optional) the id of an accessible HDA to copy into the
+ library
+ * ldda_message: (optional) the new message attribute of the LDDA created
+ * extended_metadata: (optional) dub-dictionary containing any extended
+ metadata to associate with the item
+
+ :rtype: dict
+ :returns: a dictionary containing the id, name,
+ and 'show' url of the new item
"""
create_type = None
if 'create_type' not in payload:
@@ -195,10 +241,10 @@
def _copy_hda_to_library_folder( self, trans, from_hda_id, library_id, folder_id, ldda_message='' ):
"""
- Copies hda `from_hda_id` to library folder `library_folder_id` optionally
- adding `ldda_message` to the new ldda's `message`.
+ Copies hda ``from_hda_id`` to library folder ``library_folder_id`` optionally
+ adding ``ldda_message`` to the new ldda's ``message``.
- `library_contents.create` will branch to this if called with 'from_hda_id'
+ ``library_contents.create`` will branch to this if called with 'from_hda_id'
in it's payload.
"""
log.debug( '_copy_hda_to_library_folder: %s' %( str(( from_hda_id, library_id, folder_id, ldda_message )) ) )
@@ -236,10 +282,23 @@
return rval
@web.expose_api
- def update( self, trans, id, library_id, payload, **kwd ):
+ def update( self, trans, id, library_id, payload, **kwd ):
"""
- PUT /api/libraries/{encoded_library_id}/contents/{encoded_content_type_and_id}
- Sets relationships among items
+ update( self, trans, id, library_id, payload, **kwd )
+ * PUT /api/libraries/{library_id}/contents/{id}
+ create a ImplicitlyConvertedDatasetAssociation
+ .. seealso:: :class:`galaxy.model.ImplicitlyConvertedDatasetAssociation`
+
+ :type id: str
+ :param id: the encoded id of the library item to return
+ :type library_id: str
+ :param library_id: encoded id string of the library that contains this item
+ :type payload: dict
+ :param payload: dictionary structure containing::
+ 'converted_dataset_id':
+
+ :rtype: None
+ :returns: None
"""
if 'converted_dataset_id' in payload:
converted_id = payload.pop( 'converted_dataset_id' )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Add a sanity check to the twobit sniffer.
by commits-noreply@bitbucket.org 01 Aug '13
by commits-noreply@bitbucket.org 01 Aug '13
01 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d34d6d1da813/
Changeset: d34d6d1da813
User: Dave Bouvier
Date: 2013-08-01 21:03:37
Summary: Add a sanity check to the twobit sniffer.
Affected #: 1 file
diff -r 143f7f55098ae936481e5fcb1be85a3e5b5f159b -r d34d6d1da813bfa6e318b0ceb563186e52d94095 lib/galaxy/datatypes/binary.py
--- a/lib/galaxy/datatypes/binary.py
+++ b/lib/galaxy/datatypes/binary.py
@@ -475,6 +475,9 @@
def sniff(self, filename):
try:
+ # All twobit files start with a 16-byte header. If the file is smaller than 16 bytes, it's obviously not a valid twobit file.
+ if os.path.getsize(filename) < 16:
+ return False
input = file(filename)
magic = struct.unpack(">L", input.read(TWOBIT_MAGIC_SIZE))[0]
if magic == TWOBIT_MAGIC_NUMBER or magic == TWOBIT_MAGIC_NUMBER_SWAP:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Cuffdiff wrapper: add option to output read group datasets.
by commits-noreply@bitbucket.org 01 Aug '13
by commits-noreply@bitbucket.org 01 Aug '13
01 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/143f7f55098a/
Changeset: 143f7f55098a
User: jgoecks
Date: 2013-08-01 20:51:06
Summary: Cuffdiff wrapper: add option to output read group datasets.
Affected #: 1 file
diff -r 6e36021502522213aca87e0b49f0bf0384eddfa1 -r 143f7f55098ae936481e5fcb1be85a3e5b5f159b tools/ngs_rna/cuffdiff_wrapper.xml
--- a/tools/ngs_rna/cuffdiff_wrapper.xml
+++ b/tools/ngs_rna/cuffdiff_wrapper.xml
@@ -96,8 +96,13 @@
<when value="No"></when></conditional>
+ <param name="include_read_group_files" type="select" label="Include Read Group Datasets" help="Read group datasets provide information on replicates.">
+ <option value="No" selected="true">No</option>
+ <option value="Yes">Yes</option>
+ </param>
+
<conditional name="additional">
- <param name="sAdditional" type="select" label="Set Additional Parameters? (not recommended)">
+ <param name="sAdditional" type="select" label="Set Additional Parameters? (not recommended for paired-end reads)"><option value="No">No</option><option value="Yes">Yes</option></param>
@@ -114,6 +119,21 @@
</stdio><outputs>
+ <!-- Optional read group datasets. -->
+ <data format="tabular" name="isoforms_read_group" label="${tool.name} on ${on_string}: isoforms read group tracking" from_work_dir="isoforms.read_group_tracking" >
+ <filter>(params['include_read_group_files'] == 'Yes'</filter>
+ </data>
+ <data format="tabular" name="genes_read_group" label="${tool.name} on ${on_string}: genes read group tracking" from_work_dir="genes.read_group_tracking" >
+ <filter>(params['include_read_group_files'] == 'Yes'</filter>
+ </data>
+ <data format="tabular" name="cds_read_group" label="${tool.name} on ${on_string}: CDs read group tracking" from_work_dir="cds.read_group_tracking" >
+ <filter>(params['include_read_group_files'] == 'Yes'</filter>
+ </data>
+ <data format="tabular" name="tss_groups_read_group" label="${tool.name} on ${on_string}: TSS groups read group tracking" from_work_dir="tss_groups.read_group_tracking" >
+ <filter>(params['include_read_group_files'] == 'Yes'</filter>
+ </data>
+
+ <!-- Standard datasets. --><data format="tabular" name="splicing_diff" label="${tool.name} on ${on_string}: splicing differential expression testing" from_work_dir="splicing.diff" /><data format="tabular" name="promoters_diff" label="${tool.name} on ${on_string}: promoters differential expression testing" from_work_dir="promoters.diff" /><data format="tabular" name="cds_diff" label="${tool.name} on ${on_string}: CDS overloading diffential expression testing" from_work_dir="cds.diff" />
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Implement baseline support for defining a tool dependency that downloads a precompiled binary for the target platform.
by commits-noreply@bitbucket.org 01 Aug '13
by commits-noreply@bitbucket.org 01 Aug '13
01 Aug '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6e3602150252/
Changeset: 6e3602150252
User: Dave Bouvier
Date: 2013-08-01 17:05:34
Summary: Implement baseline support for defining a tool dependency that downloads a precompiled binary for the target platform.
Affected #: 4 files
diff -r fe5867b89ec01bfde18591df8809526d85fb821e -r 6e36021502522213aca87e0b49f0bf0384eddfa1 lib/tool_shed/galaxy_install/tool_dependencies/common_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/common_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/common_util.py
@@ -8,6 +8,7 @@
import zipfile
import tool_shed.util.shed_util_common as suc
from galaxy.datatypes import checkers
+from urllib2 import HTTPError
log = logging.getLogger( __name__ )
@@ -70,6 +71,23 @@
__shellquote(env_shell_file_path))
return cmd
+def download_binary_from_url( url, work_dir, install_dir ):
+ '''
+ Download a pre-compiled binary from the specified URL. If the downloaded file is an archive,
+ extract it into install_dir and delete the archive.
+ '''
+ downloaded_filename = os.path.split( url )[ -1 ]
+ try:
+ dir = url_download( work_dir, downloaded_filename, url, extract=True )
+ downloaded_filepath = os.path.join( work_dir, downloaded_filename )
+ if is_compressed( downloaded_filepath ):
+ os.remove( downloaded_filepath )
+ move_directory_files( current_dir=work_dir,
+ source_dir=dir,
+ destination_dir=install_dir )
+ return True
+ except HTTPError:
+ return False
def extract_tar( file_name, file_path ):
if isgzip( file_name ) or isbz2( file_name ):
@@ -190,6 +208,12 @@
def iszip( file_path ):
return checkers.check_zip( file_path )
+def is_compressed( file_path ):
+ if isjar( file_path ):
+ return False
+ else:
+ return iszip( file_path ) or isgzip( file_path ) or istar( file_path ) or isbz2( file_path )
+
def make_directory( full_path ):
if not os.path.exists( full_path ):
os.makedirs( full_path )
diff -r fe5867b89ec01bfde18591df8809526d85fb821e -r 6e36021502522213aca87e0b49f0bf0384eddfa1 lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -165,12 +165,29 @@
actions = actions_dict.get( 'actions', None )
filtered_actions = []
env_shell_file_paths = []
+ # Default to false so that the install process will default to compiling.
+ binary_found = False
if actions:
with make_tmp_dir() as work_dir:
with lcd( work_dir ):
# The first action in the list of actions will be the one that defines the installation process. There
# are currently only two supported processes; download_by_url and clone via a "shell_command" action type.
action_type, action_dict = actions[ 0 ]
+ if action_type == 'download_binary':
+ # Eliminate the download_binary action so remaining actions can be processed correctly.
+ filtered_actions = actions[ 1: ]
+ url = action_dict[ 'url' ]
+ # Attempt to download a binary from the specified URL.
+ log.debug( 'Attempting to download from %s', url )
+ binary_found = common_util.download_binary_from_url( url, work_dir, install_dir )
+ if binary_found:
+ # If the attempt succeeded, set the action_type to binary_found, in order to skip any download_by_url or shell_command actions.
+ actions = filtered_actions
+ action_type = 'binary_found'
+ else:
+ # No binary exists, or there was an error downloading the binary from the generated URL. Proceed with the remaining actions.
+ del actions[ 0 ]
+ action_type, action_dict = actions[ 0 ]
if action_type == 'download_by_url':
# Eliminate the download_by_url action so remaining actions can be processed correctly.
filtered_actions = actions[ 1: ]
@@ -220,6 +237,9 @@
current_dir = os.path.abspath( os.path.join( work_dir, dir ) )
with lcd( current_dir ):
action_type, action_dict = action_tup
+ # If a binary was found, we only need to process environment variables, file permissions, and any other binary downloads.
+ if binary_found and action_type not in [ 'set_environment', 'chmod', 'download_binary' ]:
+ continue
if action_type == 'make_directory':
common_util.make_directory( full_path=action_dict[ 'full_path' ] )
elif action_type == 'move_directory_files':
@@ -348,6 +368,18 @@
dir = target_directory.replace( os.path.realpath( work_dir ), '' ).lstrip( '/' )
else:
log.error( 'Invalid or nonexistent directory %s specified, ignoring change_directory action.', target_directory )
+ elif action_type == 'chmod':
+ for target_file, mode in action_dict[ 'change_modes' ]:
+ if os.path.exists( target_file ):
+ os.chmod( target_file, mode )
+ elif action_type == 'download_binary':
+ url = action_dict[ 'url' ]
+ binary_found = common_util.download_binary_from_url( url, work_dir, install_dir )
+ if binary_found:
+ log.debug( 'Successfully downloaded binary from %s', url )
+ else:
+ log.error( 'Unable to download binary from %s', url )
+
def log_results( command, fabric_AttributeString, file_path ):
"""
diff -r fe5867b89ec01bfde18591df8809526d85fb821e -r 6e36021502522213aca87e0b49f0bf0384eddfa1 lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -1,6 +1,7 @@
import logging
import os
import sys
+import stat
import subprocess
import tempfile
from string import Template
@@ -379,7 +380,22 @@
for action_elem in actions_elem.findall( 'action' ):
action_dict = {}
action_type = action_elem.get( 'type', 'shell_command' )
- if action_type == 'shell_command':
+ if action_type == 'download_binary':
+ platform_info_dict = tool_dependency_util.get_platform_info_dict()
+ platform_info_dict[ 'name' ] = tool_dependency.name
+ platform_info_dict[ 'version' ] = tool_dependency.version
+ url_template_elems = action_elem.findall( 'url_template' )
+ # Check if there are multiple url_template elements, each with attrib entries for a specific platform.
+ if len( url_template_elems ) > 1:
+ # <base_url os="darwin" extract="false">http://hgdownload.cse.ucsc.edu/admin/exe/macOSX.${architecture}/faToTwoBit</base_url>
+ # This method returns the url_elem that best matches the current platform as received from os.uname().
+ # Currently checked attributes are os and architecture.
+ # These correspond to the values sysname and processor from the Python documentation for os.uname().
+ url_template_elem = tool_dependency_util.get_download_url_for_platform( url_template_elems, platform_info_dict )
+ else:
+ url_template_elem = url_template_elems[ 0 ]
+ action_dict[ 'url' ] = Template( url_template_elem.text ).safe_substitute( platform_info_dict )
+ elif action_type == 'shell_command':
# <action type="shell_command">make</action>
action_elem_text = evaluate_template( action_elem.text )
if action_elem_text:
@@ -492,6 +508,27 @@
# lxml==2.3.0</action>
## Manually specify contents of requirements.txt file to create dynamically.
action_dict[ 'requirements' ] = evaluate_template( action_elem.text or 'requirements.txt' )
+ elif action_type == 'chmod':
+ # Change the read, write, and execute bits on a file.
+ file_elems = action_elem.findall( 'file' )
+ chmod_actions = []
+ # A unix octal mode is the sum of the following values:
+ # Owner:
+ # 400 Read 200 Write 100 Execute
+ # Group:
+ # 040 Read 020 Write 010 Execute
+ # World:
+ # 004 Read 002 Write 001 Execute
+ for file_elem in file_elems:
+ # So by the above table, owner read/write/execute and group read permission would be 740.
+ # Python's os.chmod uses base 10 modes, convert received unix-style octal modes to base 10.
+ received_mode = int( file_elem.get( 'mode', 600 ), base=8 )
+ # For added security, ensure that the setuid and setgid bits are not set.
+ mode = received_mode & ~( stat.S_ISUID | stat.S_ISGID )
+ file = evaluate_template( file_elem.text )
+ chmod_tuple = ( file, mode )
+ chmod_actions.append( chmod_tuple )
+ action_dict[ 'change_modes' ] = chmod_actions
else:
log.debug( "Unsupported action type '%s'. Not proceeding." % str( action_type ) )
raise Exception( "Unsupported action type '%s' in tool dependency definition." % str( action_type ) )
diff -r fe5867b89ec01bfde18591df8809526d85fb821e -r 6e36021502522213aca87e0b49f0bf0384eddfa1 lib/tool_shed/util/tool_dependency_util.py
--- a/lib/tool_shed/util/tool_dependency_util.py
+++ b/lib/tool_shed/util/tool_dependency_util.py
@@ -39,6 +39,37 @@
tool_dependencies[ dependency_key ] = requirements_dict
return tool_dependencies
+def get_download_url_for_platform( url_templates, platform_info_dict ):
+ '''
+ Compare the dict returned by get_platform_info() with the values specified in the base_url element. Return
+ true if and only if all defined attributes match the corresponding dict entries. If an entry is not
+ defined in the base_url element, it is assumed to be irrelevant at this stage. For example,
+ <base_url os="darwin">http://hgdownload.cse.ucsc.edu/admin/exe/macOSX.${architecture}/faToTwoBit</base_url>
+ where the OS must be 'darwin', but the architecture is filled in later using string.Template.
+ '''
+ os_ok = False
+ architecture_ok = False
+ for url_template in url_templates:
+ os_name = url_template.get( 'os', None )
+ architecture = url_template.get( 'architecture', None )
+ if os_name:
+ if os_name.lower() == platform_info_dict[ 'os' ]:
+ os_ok = True
+ else:
+ os_ok = False
+ else:
+ os_ok = True
+ if architecture:
+ if architecture.lower() == platform_info_dict[ 'architecture' ]:
+ architecture_ok = True
+ else:
+ architecture_ok = False
+ else:
+ architecture_ok = True
+ if os_ok and architecture_ok:
+ return url_template
+ return None
+
def create_or_update_tool_dependency( app, tool_shed_repository, name, version, type, status, set_status=True ):
# Called from Galaxy (never the tool shed) when a new repository is being installed or when an uninstalled repository is being reinstalled.
sa_session = app.model.context.current
@@ -204,6 +235,14 @@
missing_tool_dependencies = None
return tool_dependencies, missing_tool_dependencies
+def get_platform_info_dict():
+ '''Return a dict with information about the current platform.'''
+ platform_dict = {}
+ sysname, nodename, release, version, machine = os.uname()
+ platform_dict[ 'os' ] = sysname.lower()
+ platform_dict[ 'architecture' ] = machine.lower()
+ return platform_dict
+
def get_tool_dependency( trans, id ):
"""Get a tool_dependency from the database via id"""
return trans.sa_session.query( trans.model.ToolDependency ).get( trans.security.decode_id( id ) )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: API Documentation: histories, history_contents
by commits-noreply@bitbucket.org 31 Jul '13
by commits-noreply@bitbucket.org 31 Jul '13
31 Jul '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/fe5867b89ec0/
Changeset: fe5867b89ec0
User: carlfeberhard
Date: 2013-07-31 22:55:50
Summary: API Documentation: histories, history_contents
Affected #: 2 files
diff -r edef166c163f30175e98ddb0b98f7993d7d4d5eb -r fe5867b89ec01bfde18591df8809526d85fb821e lib/galaxy/webapps/galaxy/api/histories.py
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -1,5 +1,7 @@
"""
API operations on a history.
+
+.. seealso:: :class:`galaxy.model.History`
"""
import pkg_resources
@@ -21,17 +23,30 @@
@web.expose_api_anonymous
def index( self, trans, deleted='False', **kwd ):
"""
- GET /api/histories
- GET /api/histories/deleted
- Displays a collection (list) of histories.
+ index( trans, deleted='False' )
+ * GET /api/histories:
+ return undeleted histories for the current user
+ * GET /api/histories/deleted:
+ return deleted histories for the current user
+
+ If the user is logged-in, a full list of all histories is shown.
+ If not logged in, only the curernt history (if any) is shown.
+
+ :type deleted: boolean
+ :param deleted: if True, show only deleted histories, if False, non-deleted
+
+ :rtype: list
+ :returns: list of dictionaries containing summary history information
"""
#TODO: query (by name, date, etc.)
rval = []
deleted = string_as_bool( deleted )
try:
if trans.user:
- query = trans.sa_session.query(trans.app.model.History ).filter_by( user=trans.user, deleted=deleted ).order_by(
- desc(trans.app.model.History.table.c.update_time)).all()
+ query = ( trans.sa_session.query( trans.app.model.History )
+ .filter_by( user=trans.user, deleted=deleted )
+ .order_by( desc( trans.app.model.History.table.c.update_time ) )
+ .all() )
for history in query:
item = history.get_api_value(value_mapper={'id':trans.security.encode_id})
item['url'] = url_for( 'history', id=trans.security.encode_id( history.id ) )
@@ -52,11 +67,24 @@
@web.expose_api_anonymous
def show( self, trans, id, deleted='False', **kwd ):
+ # oh, sphinx - you bastard
"""
- GET /api/histories/{encoded_history_id}
- GET /api/histories/deleted/{encoded_history_id}
- GET /api/histories/most_recently_used
- Displays information about a history.
+ show( trans, id, deleted='False' )
+ * GET /api/histories/{id}:
+ return the history with ``id``
+ * GET /api/histories/deleted/{id}:
+ return the deleted history with ``id``
+ * GET /api/histories/most_recently_used:
+ return the most recently used history
+
+ :type id: an encoded id string
+ :param id: the encoded id of the history to query or the string 'most_recently_used'
+ :type deleted: boolean
+ :param deleted: if True, allow information on a deleted history to be shown.
+
+ :rtype: dictionary
+ :returns: detailed history information from
+ :func:`galaxy.web.base.controller.UsesHistoryDatasetAssociationMixin.get_history_dict`
"""
#TODO: GET /api/histories/{encoded_history_id}?as_archive=True
#TODO: GET /api/histories/s/{username}/{slug}
@@ -94,8 +122,16 @@
@web.expose_api
def create( self, trans, payload, **kwd ):
"""
- POST /api/histories
- Creates a new history.
+ create( trans, payload )
+ * POST /api/histories:
+ create a new history
+
+ :type payload: dict
+ :param payload: (optional) dictionary structure containing::
+ 'name': the new history's name
+
+ :rtype: dict
+ :returns: element view of new history
"""
hist_name = None
if payload.get( 'name', None ):
@@ -115,8 +151,24 @@
@web.expose_api
def delete( self, trans, id, **kwd ):
"""
- DELETE /api/histories/{encoded_history_id}
- Deletes a history
+ delete( self, trans, id, **kwd )
+ * DELETE /api/histories/{id}
+ delete the history with the given ``id``
+ .. note:: Currently does not stop any active jobs in the history.
+
+ :type id: str
+ :param id: the encoded id of the history to delete
+ :type kwd: dict
+ :param kwd: (optional) dictionary structure containing::
+ 'payload': a dictionary itself containing::
+ 'purge': if True, purge the history and all of it's HDAs
+
+ :rtype: dict
+ :returns: an error object if an error occurred or a dictionary containing::
+
+ id: the encoded id of the history,
+ deleted: if the history was marked as deleted,
+ purged: if the history was purged
"""
history_id = id
# a request body is optional here
@@ -175,8 +227,15 @@
@web.expose_api
def undelete( self, trans, id, **kwd ):
"""
- POST /api/histories/deleted/{encoded_history_id}/undelete
- Undeletes a history
+ undelete( self, trans, id, **kwd )
+ * POST /api/histories/deleted/{id}/undelete:
+ undelete history (that hasn't been purged) with the given ``id``
+
+ :type id: str
+ :param id: the encoded id of the history to undelete
+
+ :rtype: str
+ :returns: 'OK' if the history was undeleted
"""
history_id = id
history = self.get_history( trans, history_id, check_ownership=True, check_accessible=False, deleted=True )
@@ -188,8 +247,21 @@
@web.expose_api
def update( self, trans, id, payload, **kwd ):
"""
- PUT /api/histories/{encoded_history_id}
- Changes an existing history.
+ update( self, trans, id, payload, **kwd )
+ * PUT /api/histories/{id}
+ updates the values for the history with the given ``id``
+
+ :type id: str
+ :param id: the encoded id of the history to undelete
+ :type payload: dict
+ :param payload: a dictionary containing any or all the
+ fields in :func:`galaxy.model.History.get_api_value` and/or the following::
+
+ 'annotation': an annotation for the history
+
+ :rtype: dict
+ :returns: an error object if an error occurred or a dictionary containing
+ any values that were different from the original and, therefore, updated
"""
#TODO: PUT /api/histories/{encoded_history_id} payload = { rating: rating } (w/ no security checks)
try:
@@ -255,6 +327,7 @@
raise ValueError( 'annotation must be a string or unicode: %s' %( str( type( val ) ) ) )
validated_payload[ 'annotation' ] = sanitize_html( val, 'utf-8' )
elif key not in valid_but_uneditable_keys:
- raise AttributeError( 'unknown key: %s' %( str( key ) ) )
+ pass
+ #log.warn( 'unknown key: %s', str( key ) )
return validated_payload
diff -r edef166c163f30175e98ddb0b98f7993d7d4d5eb -r fe5867b89ec01bfde18591df8809526d85fb821e lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -15,21 +15,31 @@
@web.expose_api_anonymous
def index( self, trans, history_id, ids=None, **kwd ):
"""
- GET /api/histories/{encoded_history_id}/contents
- Displays a collection (list) of history contents (HDAs)
+ index( self, trans, history_id, ids=None, **kwd )
+ * GET /api/histories/{history_id}/contents
+ return a list of HDA data for the history with the given ``id``
- :param history_id: an encoded id string of the `History` to search
- :param ids: (optional) a comma separated list of encoded `HDA` ids
+ :type history_id: str
+ :param history_id: encoded id string of the HDA's History
+ :type ids: str
+ :param ids: (optional) a comma separated list of encoded `HDA` ids
- If Ids is not given, index returns a list of *summary* json objects for
- every `HDA` associated with the given `history_id`.
- See _summary_hda_dict.
+ If Ids is not given, index returns a list of *summary* objects for
+ every HDA associated with the given `history_id`.
+
+ .. seealso::
+ :func:`_summary_hda_dict`
If ids is given, index returns a *more complete* json object for each
HDA in the ids list.
- Note: Anonymous users are allowed to get their current history contents
- (generally useful for browser UI access of the api)
+ .. seealso::
+ :func:`galaxy.web.base.controller.UsesHistoryDatasetAssociationMixin.get_hda_dict`
+
+ .. note:: Anonymous users are allowed to get their current history contents
+
+ :rtype: list
+ :returns: dictionaries containing summary or detailed HDA information
"""
rval = []
try:
@@ -78,13 +88,13 @@
#TODO: move to model or Mixin
def _summary_hda_dict( self, trans, history_id, hda ):
"""
- Returns a dictionary based on the HDA in .. _summary form::
- {
- 'id' : < the encoded dataset id >,
- 'name' : < currently only returns 'file' >,
- 'type' : < name of the dataset >,
- 'url' : < api url to retrieve this datasets full data >,
- }
+ Returns a dictionary based on the HDA in summary form::
+ {
+ 'id' : < the encoded dataset id >,
+ 'name' : < currently only returns 'file' >,
+ 'type' : < name of the dataset >,
+ 'url' : < api url to retrieve this datasets full data >,
+ }
"""
api_type = "file"
encoded_id = trans.security.encode_id( hda.id )
@@ -98,8 +108,21 @@
@web.expose_api_anonymous
def show( self, trans, id, history_id, **kwd ):
"""
- GET /api/histories/{encoded_history_id}/contents/{encoded_content_id}
- Displays information about a history content (dataset).
+ show( self, trans, id, history_id, **kwd )
+ * GET /api/histories/{history_id}/contents/{id}
+ return detailed information about an HDA within a history
+
+ :type id: str
+ :param ids: the encoded id of the HDA to return
+ :type history_id: str
+ :param history_id: encoded id string of the HDA's History
+
+ .. seealso:: :func:`galaxy.web.base.controller.UsesHistoryDatasetAssociationMixin.get_hda_dict`
+
+ .. note:: Anonymous users are allowed to get their current history contents
+
+ :rtype: dict
+ :returns: dictionary containing detailed HDA information
"""
hda_dict = {}
try:
@@ -135,8 +158,18 @@
@web.expose_api
def create( self, trans, history_id, payload, **kwd ):
"""
- POST /api/histories/{encoded_history_id}/contents
- Creates a new history content item (file, aka HistoryDatasetAssociation).
+ create( self, trans, history_id, payload, **kwd )
+ * POST /api/histories/{history_id}/contents
+ create a new HDA by copying an accessible LibraryDataset
+
+ :type history_id: str
+ :param history_id: encoded id string of the new HDA's History
+ :type payload: dict
+ :param payload: dictionary structure containing::
+ 'from_ld_id': the encoded id of the LibraryDataset to copy
+
+ :rtype: dict
+ :returns: dictionary containing detailed information for the new HDA
"""
#TODO: copy existing, accessible hda - dataset controller, copy_datasets
#TODO: convert existing, accessible hda - model.DatasetInstance(or hda.datatype).get_converter_types
@@ -173,8 +206,24 @@
@web.expose_api
def update( self, trans, history_id, id, payload, **kwd ):
"""
- PUT /api/histories/{encoded_history_id}/contents/{encoded_content_id}
- Changes an existing history dataset.
+ update( self, trans, history_id, id, payload, **kwd )
+ * PUT /api/histories/{history_id}/contents/{id}
+ updates the values for the HDA with the given ``id``
+
+ :type history_id: str
+ :param history_id: encoded id string of the HDA's History
+ :type id: str
+ :param id: the encoded id of the history to undelete
+ :type payload: dict
+ :param payload: a dictionary containing any or all the
+ fields in :func:`galaxy.model.HistoryDatasetAssociation.get_api_value`
+ and/or the following::
+
+ 'annotation': an annotation for the history
+
+ :rtype: dict
+ :returns: an error object if an error occurred or a dictionary containing
+ any values that were different from the original and, therefore, updated
"""
#TODO: PUT /api/histories/{encoded_history_id} payload = { rating: rating } (w/ no security checks)
changed = {}
@@ -251,6 +300,7 @@
raise ValueError( 'misc_info must be a string or unicode: %s' %( str( type( val ) ) ) )
validated_payload[ 'info' ] = util.sanitize_html.sanitize_html( val, 'utf-8' )
elif key not in valid_but_uneditable_keys:
- raise AttributeError( 'unknown key: %s' %( str( key ) ) )
+ pass
+ #log.warn( 'unknown key: %s', str( key ) )
return validated_payload
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0