galaxy-commits
Threads by month
- ----- 2025 -----
- 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

commit/galaxy-central: greg: Apply fix from Jim Johnson for rendering tool dependencies defined in a tool shed repository.
by Bitbucket 18 Sep '12
by Bitbucket 18 Sep '12
18 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/ba64c2178fbe/
changeset: ba64c2178fbe
user: greg
date: 2012-09-18 15:03:39
summary: Apply fix from Jim Johnson for rendering tool dependencies defined in a tool shed repository.
affected #: 1 file
diff -r 19345740820fe9fe62fe46e9ae54efbabc1eb019 -r ba64c2178fbee9a83f79580c434ab280d8a0b738 templates/admin/tool_shed_repository/common.mako
--- a/templates/admin/tool_shed_repository/common.mako
+++ b/templates/admin/tool_shed_repository/common.mako
@@ -129,28 +129,30 @@
<% package_header_row_displayed = True %>
%endif
%for dependency_key, requirements_dict in tool_dependencies.items():
- <%
- name = requirements_dict[ 'name' ]
- version = requirements_dict[ 'version' ]
- type = requirements_dict[ 'type' ]
- install_dir = os.path.join( trans.app.config.tool_dependency_dir,
- name,
- version,
- repository_owner,
- repository_name,
- changeset_revision )
- tool_dependency_readme_text = requirements_dict.get( 'readme', None )
- %>
- %if not os.path.exists( install_dir ):
- <tr>
- <td>${name}</td>
- <td>${version}</td>
- <td>${type}</td>
- <td>${install_dir}</td>
- </tr>
- %if tool_dependency_readme_text:
- <tr><td colspan="4" bgcolor="#FFFFCC">${name} ${version} requirements and installation information</td></tr>
- <tr><td colspan="4"><pre>${tool_dependency_readme_text}</pre></td></tr>
+ %if dependency_key not in [ 'set_environment' ]:
+ <%
+ name = requirements_dict[ 'name' ]
+ version = requirements_dict[ 'version' ]
+ type = requirements_dict[ 'type' ]
+ install_dir = os.path.join( trans.app.config.tool_dependency_dir,
+ name,
+ version,
+ repository_owner,
+ repository_name,
+ changeset_revision )
+ tool_dependency_readme_text = requirements_dict.get( 'readme', None )
+ %>
+ %if not os.path.exists( install_dir ):
+ <tr>
+ <td>${name}</td>
+ <td>${version}</td>
+ <td>${type}</td>
+ <td>${install_dir}</td>
+ </tr>
+ %if tool_dependency_readme_text:
+ <tr><td colspan="4" bgcolor="#FFFFCC">${name} ${version} requirements and installation information</td></tr>
+ <tr><td colspan="4"><pre>${tool_dependency_readme_text}</pre></td></tr>
+ %endif
%endif
%endif
%endfor
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: Fix bugs when converting BED to FLI and JS module references.
by Bitbucket 17 Sep '12
by Bitbucket 17 Sep '12
17 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/19345740820f/
changeset: 19345740820f
user: jgoecks
date: 2012-09-17 23:36:40
summary: Fix bugs when converting BED to FLI and JS module references.
affected #: 2 files
diff -r 833f02590bbd11f8ed1bdc024b380c1bb185bfae -r 19345740820fe9fe62fe46e9ae54efbabc1eb019 lib/galaxy/datatypes/converters/interval_to_fli.py
--- a/lib/galaxy/datatypes/converters/interval_to_fli.py
+++ b/lib/galaxy/datatypes/converters/interval_to_fli.py
@@ -53,7 +53,17 @@
else:
# BED format.
for line in open( in_fname, 'r' ):
+ # Ignore track lines.
+ if line.startswith("track"):
+ continue
+
fields = line.split()
+
+ # Ignore lines with no feature name.
+ if len( fields ) < 4:
+ continue
+
+ # Process line
name_loc_dict[ fields[3] ] = {
'contig': fields[0],
'start': int( fields[1] ),
diff -r 833f02590bbd11f8ed1bdc024b380c1bb185bfae -r 19345740820fe9fe62fe46e9ae54efbabc1eb019 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -86,17 +86,17 @@
JSON.parse('${ h.to_json_string( config['bookmarks'] ) }'),
true
);
- ui.init_editor();
+ init_editor();
set_up_router({view: view});
%else:
var continue_fn = function() {
- view = trackster_ui.create_visualization( {
+ view = ui.create_visualization( {
container: $("#browser-container"),
name: $("#new-title").val(),
dbkey: $("#new-dbkey").val()
} );
view.editor = true;
- ui.init_editor();
+ init_editor();
set_up_router({view: view});
hide_modal();
};
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/changeset/5027e0458ef0/
changeset: 5027e0458ef0
user: carlfeberhard
date: 2012-09-17 23:12:42
summary: initial, un-wired prototype for scatterplot visualization
affected #: 6 files
diff -r 65ecf4e0ed28eaa2f3e64495ab800aa7c9779a54 -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 lib/galaxy/visualization/data_providers/basic.py
--- a/lib/galaxy/visualization/data_providers/basic.py
+++ b/lib/galaxy/visualization/data_providers/basic.py
@@ -90,6 +90,11 @@
break
fields = line.split()
+ #pre: column indeces should be avail in fields
+ for col_index in cols:
+ assert col_index < len( fields ), (
+ "column index (%d) must be less than fields length: %d" % ( col_index, len( fields ) ) )
+
data.append( [ cast_val( fields[c], self.original_dataset.metadata.column_types[c] ) for c in cols ] )
f.close()
diff -r 65ecf4e0ed28eaa2f3e64495ab800aa7c9779a54 -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 lib/galaxy/web/api/datasets.py
--- a/lib/galaxy/web/api/datasets.py
+++ b/lib/galaxy/web/api/datasets.py
@@ -215,8 +215,14 @@
# Return data.
data = None
data_provider = trans.app.data_provider_registry.get_data_provider( raw=True, original_dataset=dataset )
+
if data_provider == ColumnDataProvider:
+ #pre: should have column kwargs
+ #print 'kwargs:', kwargs
+ assert 'cols' in kwargs, (
+ "ColumnDataProvider needs a 'cols' parameter in the query string" )
data = data_provider( original_dataset=dataset ).get_data( **kwargs )
+
else:
# Default to genomic data.
# FIXME: need better way to set dataset_type.
diff -r 65ecf4e0ed28eaa2f3e64495ab800aa7c9779a54 -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py
+++ b/lib/galaxy/web/controllers/visualization.py
@@ -6,6 +6,7 @@
from galaxy.web.controllers.library import LibraryListGrid
from galaxy.visualization.genomes import decode_dbkey
from galaxy.visualization.genome.visual_analytics import get_dataset_job
+from galaxy.visualization.data_providers.basic import ColumnDataProvider
#
# -- Grids --
@@ -801,6 +802,28 @@
def get_item( self, trans, id ):
return self.get_visualization( trans, id )
+ @web.expose
+ def scatterplot( self, trans, dataset_id, cols ):
+ # Get HDA.
+ hda = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True )
+
+ # get some metadata for the page
+ hda_dict = hda.get_api_value()
+ #title = "Scatter plot of {name}:".format( **hda_dict )
+ #subtitle = "{misc_info}".format( **hda_dict )
+
+ #TODO: add column data
+ # Read data.
+ data_provider = ColumnDataProvider( original_dataset=hda )
+ data = data_provider.get_data( cols )
+
+ # Return plot.
+ return trans.fill_template_mako( "visualization/scatterplot.mako",
+ title=hda.name, subtitle=hda.info,
+ hda=hda,
+ data=data )
+
+
@web.json
def bookmarks_from_dataset( self, trans, hda_id=None, ldda_id=None ):
if hda_id:
diff -r 65ecf4e0ed28eaa2f3e64495ab800aa7c9779a54 -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 templates/root/history.mako
--- a/templates/root/history.mako
+++ b/templates/root/history.mako
@@ -17,7 +17,16 @@
<meta http-equiv="Pragma" content="no-cache">
${h.css( "base", "history", "autocomplete_tagging" )}
-${h.js( "libs/jquery/jquery", "libs/bootstrap", "galaxy.base", "libs/json2", "libs/jquery/jstorage", "libs/jquery/jquery.autocomplete", "galaxy.autocom_tagging" )}
+${h.js(
+ "libs/jquery/jquery",
+ "libs/bootstrap",
+ "galaxy.base",
+ "libs/json2",
+ "libs/jquery/jstorage",
+ "libs/jquery/jquery.autocomplete",
+ "galaxy.autocom_tagging",
+ "libs/underscore"
+)}
<script type="text/javascript">
@@ -289,8 +298,61 @@
});
}
- init_trackster_links();
+ /**
+ * Create popup menu for visualization icon.
+ */
+ function init_viz_icon(icon) {
+ var icon_link = $(icon);
+ make_popupmenu( icon_link , {
+ "${_("Trackster")}": function() {
+ $.ajax({
+ url: icon_link.attr("data-url"),
+ dataType: "html",
+ error: function() { alert( "Could not add this dataset to browser." ); },
+ success: function(table_html) {
+ var parent = window.parent;
+ parent.show_modal("View Data in a New or Saved Visualization", "", {
+ "Cancel": function() {
+ parent.hide_modal();
+ },
+ "View in saved visualization": function() {
+ // Show new modal with saved visualizations.
+ parent.hide_modal();
+ parent.show_modal("Add Data to Saved Visualization", table_html, {
+ "Cancel": function() {
+ parent.hide_modal();
+ },
+ "Add to visualization": function() {
+ $(parent.document).find('input[name=id]:checked').each(function() {
+ var vis_id = $(this).val();
+ parent.location = icon_link.attr("action-url") + "&id=" + vis_id;
+ });
+ },
+ });
+ },
+ "View in new visualization": function() {
+ parent.location = icon_link.attr("new-url");
+ }
+ });
+ }
+ });
+ },
+ //"${_("Scatterplot")}": function() {
+ // var data_id = icon_link.parents(".historyItemContainer").attr("id").split("-")[1];
+ // parent.galaxy_main.location =
+ // "${h.url_for( controller='visualization', action='scatterplot', col1=9, col2=13 )}"
+ // + "&dataset_id=" + data_id;
+ //}
+ } );
+ return icon;
+ };
+
+ _.each( $(".visualize-icon"), function(icon) {
+ console.debug( 'Init visualization icons, icon:', icon );
+ init_viz_icon(icon);
+ });
+
function init_phyloviz_links() {
// PhyloViz links
// Add to trackster browser functionality
diff -r 65ecf4e0ed28eaa2f3e64495ab800aa7c9779a54 -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -234,9 +234,12 @@
else:
data_url = h.url_for( controller='visualization', action='list_tracks' )
%>
- <a href="javascript:void(0)" data-url="${data_url}" class="icon-button chart_curve tooltip trackster-add"
- action-url="${h.url_for( controller='visualization', action='trackster', dataset_id=dataset_id)}"
- new-url="${h.url_for( controller='visualization', action='trackster', dataset_id=dataset_id, default_dbkey=data.dbkey)}" title="View in Trackster"></a>
+ <!--<a href="javascript:void(0)" data-url="${data_url}" class="icon-button chart_curve tooltip trackster-add"-->
+ <!-- action-url="${h.url_for( controller='visualization', action='trackster', dataset_id=dataset_id)}"-->
+ <!-- new-url="${h.url_for( controller='visualization', action='trackster', dataset_id=dataset_id, default_dbkey=data.dbkey)}" title="View in Trackster"></a>-->
+ <a href="javascript:void(0)" data-url="${data_url}" class="icon-button chart_curve tooltip visualize-icon"
+ action-url="${h.url_for( controller='tracks', action='browser', dataset_id=dataset_id)}"
+ new-url="${h.url_for( controller='tracks', action='index', dataset_id=dataset_id, default_dbkey=data.dbkey)}" title="Visualize"></a>
%endif
<%
isPhylogenyData = isinstance(data.datatype, (Phyloxml, Nexus, Newick))
diff -r 65ecf4e0ed28eaa2f3e64495ab800aa7c9779a54 -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 templates/visualization/scatterplot.mako
--- /dev/null
+++ b/templates/visualization/scatterplot.mako
@@ -0,0 +1,205 @@
+<%inherit file="/base.mako"/>
+
+<%def name="stylesheets()">
+${parent.stylesheets()}
+${h.css( "history", "autocomplete_tagging", "trackster", "overcast/jquery-ui-1.8.5.custom", "library" )}
+
+<style type="text/css">
+* { margin: 0px, padding: 0px; }
+
+.subtitle {
+ margin-left: 1em;
+ margin-top: -1em;
+ color: grey;
+ font-size: small;
+}
+
+.chart {
+ /*shape-rendering: crispEdges;*/
+}
+
+.grid-line {
+ fill: none;
+ stroke: lightgrey;
+ stroke-opacity: 0.5;
+ shape-rendering: crispEdges;
+ stroke-dasharray: 3, 3;
+}
+
+.axis path, .axis line {
+ fill: none;
+ stroke: black;
+ shape-rendering: crispEdges;
+}
+.axis text {
+ font-family: sans-serif;
+ font-size: 12px;
+}
+
+
+circle.bubble {
+ stroke: none;
+ fill: black;
+ fill-opacity: 0.2;
+}
+
+</style>
+
+</%def>
+
+<%def name="javascripts()">
+${parent.javascripts()}
+${h.js( "libs/d3" )}
+
+<script type="text/javascript">
+/* =============================================================================
+todo:
+ validate columns (here or server)
+ send: type, column title/name in JSON
+
+
+ move to obj, possibly view?
+ fetch (new?) data
+ config changes to the graph
+ download svg (png?)
+
+============================================================================= */
+function translateStr( x, y ){
+ return 'translate(' + x + ',' + y + ')';
+}
+function rotateStr( d, x, y ){
+ return 'rotate(' + d + ',' + x + ',' + y + ')';
+}
+
+$(function() {
+ // Constants
+ var data = ${data},
+ MAX_DATA_POINTS = 30000,
+ BUBBLE_RADIUS = 5,
+ ENTRY_ANIM_DURATION = 500,
+ X_TICKS = 10, Y_TICKS = 10,
+ X_AXIS_LABEL_BUMP_Y = 40,
+ Y_AXIS_LABEL_BUMP_X = -35,
+ WIDTH = 300,
+ HEIGHT = 300,
+ MARGIN= 50,
+ xLabel = "Magnitude",
+ yLabel = "Depth";
+
+ // set a cap on the data, limit to first n points
+ data = data.slice( 0, MAX_DATA_POINTS );
+
+ // split the data into columns
+ //TODO: compute min, max on server.
+ var col1_data = data.map( function(e) { return e[0] }),
+ col2_data = data.map( function(e) { return e[1] }),
+ xMin = d3.min( col1_data ),
+ xMax = d3.max( col1_data ),
+ yMin = d3.min( col2_data ),
+ yMax = d3.max( col2_data );
+ console.log( 'col1_data:', col1_data );
+ console.log( 'col2_data:', col2_data );
+ console.log( 'xMin, xMax, yMin, yMax:', xMin, xMax, yMin, yMax );
+
+ // Set up.
+ d3.select( "body" ).append( "svg:svg" )
+ .attr( "width", WIDTH + ( MARGIN * 2 ) )
+ .attr( "height", HEIGHT + ( MARGIN * 2 ) )
+ .attr( "class", "chart" );
+
+ // Scale for x, y based on data domains
+ // origin: bottom, left
+ var x_scale = d3.scale.linear()
+ .domain([ xMin, xMax ])
+ .range([ 0, WIDTH ]),
+ y_scale = d3.scale.linear()
+ .domain([ yMin, yMax ])
+ .range([ HEIGHT, 0 ]);
+
+ // Selection of SVG, append group (will group our entire chart), give attributes
+ // apply a group and transform all coords away from margins
+ var chart = d3.select( ".chart" ).append( "svg:g" )
+ .attr( "class", "content" )
+ .attr( "transform", translateStr( MARGIN, MARGIN ) );
+
+ // axes
+ var xAxisFn = d3.svg.axis()
+ .scale( x_scale )
+ .ticks( X_TICKS )
+ .orient( 'bottom' );
+ var xAxis = chart.append( 'g' ).attr( 'class', 'axis' ).attr( 'id', 'x-axis' )
+ .attr( 'transform', translateStr( 0, HEIGHT ) )
+ .call( xAxisFn )
+ console.debug( 'xAxis:', xAxis ); window.xAxis = xAxis, window.xAxisFn = xAxisFn;
+
+ var xAxisLabel = xAxis.append( 'text' ).attr( 'class', 'axis-label' ).attr( 'id', 'x-axis-label' )
+ .attr( 'x', WIDTH / 2 )
+ .attr( 'y', X_AXIS_LABEL_BUMP_Y )
+ .attr( 'text-anchor', 'middle' )
+ .text( xLabel );
+ console.debug( 'xAxisLabel:', xAxisLabel ); window.xAxisLabel = xAxisLabel;
+
+ var yAxisFn = d3.svg.axis()
+ .scale( y_scale )
+ .ticks( Y_TICKS )
+ .orient( 'left' );
+ var yAxis = chart.append( 'g' ).attr( 'class', 'axis' ).attr( 'id', 'y-axis' )
+ .call( yAxisFn );
+ console.debug( 'yAxis:', yAxis ); window.yAxis = yAxis, window.yAxisFn = yAxisFn;
+
+ var yAxisLabel = yAxis.append( 'text' ).attr( 'class', 'axis-label' ).attr( 'id', 'y-axis-label' )
+ .attr( 'x', Y_AXIS_LABEL_BUMP_X )
+ .attr( 'y', HEIGHT / 2 )
+ .attr( 'text-anchor', 'middle' )
+ .attr( 'transform', rotateStr( -90, Y_AXIS_LABEL_BUMP_X, HEIGHT / 2 ) )
+ .text( yLabel );
+ console.debug( 'yAxisLabel:', yAxisLabel ); window.yAxisLabel = yAxisLabel;
+
+ // grid lines
+ var hGridLines = chart.selectAll( '.h-grid-line' )
+ .data( x_scale.ticks( xAxisFn.ticks()[0] ) )
+ .enter().append( 'svg:line' )
+ .classed( 'grid-line h-grid-line', true )
+ .attr( 'x1', x_scale ).attr( 'y1', 0 )
+ .attr( 'x2', x_scale ).attr( 'y2', HEIGHT )
+ console.debug( 'hGridLines:', hGridLines ); window.hGridLines = hGridLines;
+
+ var vGridLines = chart.selectAll( '.v-grid-line' )
+ .data( y_scale.ticks( yAxisFn.ticks()[0] ) )
+ .enter().append( 'svg:line' )
+ .classed( 'grid-line v-grid-line', true )
+ .attr( 'x1', 0 ) .attr( 'y1', y_scale )
+ .attr( 'x2', WIDTH ).attr( 'y2', y_scale )
+ console.debug( 'vGridLines:', vGridLines ); window.vGridLines = vGridLines;
+
+ // Functions used to render plot.
+ var xPosFn = function( d, i ){
+ return x_scale( col1_data[ i ] );
+ };
+ var yPosFn = function( d, i ){
+ return y_scale( col2_data[ i ] );
+ };
+
+ // Create bubbles for each data point.
+ chart.selectAll( "circle.bubble" )
+ .data(data).enter()
+ .append( "svg:circle" ).attr( "class", "bubble" )
+ // start all bubbles at corner...
+ .attr( "r", 0 )
+ .attr( "fill", "white" )
+ // ...animate to final position
+ .transition().duration( ENTRY_ANIM_DURATION )
+ .attr("cx", xPosFn )
+ .attr("cy", yPosFn )
+ .attr("r", BUBBLE_RADIUS);
+
+ //TODO: on hover red line to axes, display values
+});
+</script>
+</%def>
+
+<%def name="body()">
+ <h1 class="title">Scatterplot of '${title}':</h1>
+ <h2 class="subtitle">${subtitle}</h2>
+
+</%def>
https://bitbucket.org/galaxy/galaxy-central/changeset/833f02590bbd/
changeset: 833f02590bbd
user: carlfeberhard
date: 2012-09-17 23:19:53
summary: scatterplot.mako: some cleanup
affected #: 4 files
diff -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 -r 833f02590bbd11f8ed1bdc024b380c1bb185bfae lib/galaxy/web/api/datasets.py
--- a/lib/galaxy/web/api/datasets.py
+++ b/lib/galaxy/web/api/datasets.py
@@ -219,6 +219,7 @@
if data_provider == ColumnDataProvider:
#pre: should have column kwargs
#print 'kwargs:', kwargs
+ #TODO??: could default to first two here
assert 'cols' in kwargs, (
"ColumnDataProvider needs a 'cols' parameter in the query string" )
data = data_provider( original_dataset=dataset ).get_data( **kwargs )
diff -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 -r 833f02590bbd11f8ed1bdc024b380c1bb185bfae templates/root/history.mako
--- a/templates/root/history.mako
+++ b/templates/root/history.mako
@@ -349,7 +349,6 @@
};
_.each( $(".visualize-icon"), function(icon) {
- console.debug( 'Init visualization icons, icon:', icon );
init_viz_icon(icon);
});
diff -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 -r 833f02590bbd11f8ed1bdc024b380c1bb185bfae templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -234,9 +234,6 @@
else:
data_url = h.url_for( controller='visualization', action='list_tracks' )
%>
- <!--<a href="javascript:void(0)" data-url="${data_url}" class="icon-button chart_curve tooltip trackster-add"-->
- <!-- action-url="${h.url_for( controller='visualization', action='trackster', dataset_id=dataset_id)}"-->
- <!-- new-url="${h.url_for( controller='visualization', action='trackster', dataset_id=dataset_id, default_dbkey=data.dbkey)}" title="View in Trackster"></a>--><a href="javascript:void(0)" data-url="${data_url}" class="icon-button chart_curve tooltip visualize-icon"
action-url="${h.url_for( controller='tracks', action='browser', dataset_id=dataset_id)}"
new-url="${h.url_for( controller='tracks', action='index', dataset_id=dataset_id, default_dbkey=data.dbkey)}" title="Visualize"></a>
diff -r 5027e0458ef06686cbf56770c5e02e9d5d1673c1 -r 833f02590bbd11f8ed1bdc024b380c1bb185bfae templates/visualization/scatterplot.mako
--- a/templates/visualization/scatterplot.mako
+++ b/templates/visualization/scatterplot.mako
@@ -56,7 +56,6 @@
todo:
validate columns (here or server)
send: type, column title/name in JSON
-
move to obj, possibly view?
fetch (new?) data
@@ -97,9 +96,9 @@
xMax = d3.max( col1_data ),
yMin = d3.min( col2_data ),
yMax = d3.max( col2_data );
- console.log( 'col1_data:', col1_data );
- console.log( 'col2_data:', col2_data );
- console.log( 'xMin, xMax, yMin, yMax:', xMin, xMax, yMin, yMax );
+ //console.log( 'col1_data:', col1_data );
+ //console.log( 'col2_data:', col2_data );
+ //console.log( 'xMin, xMax, yMin, yMax:', xMin, xMax, yMin, yMax );
// Set up.
d3.select( "body" ).append( "svg:svg" )
@@ -130,14 +129,14 @@
var xAxis = chart.append( 'g' ).attr( 'class', 'axis' ).attr( 'id', 'x-axis' )
.attr( 'transform', translateStr( 0, HEIGHT ) )
.call( xAxisFn )
- console.debug( 'xAxis:', xAxis ); window.xAxis = xAxis, window.xAxisFn = xAxisFn;
+ //console.debug( 'xAxis:', xAxis ); window.xAxis = xAxis, window.xAxisFn = xAxisFn;
var xAxisLabel = xAxis.append( 'text' ).attr( 'class', 'axis-label' ).attr( 'id', 'x-axis-label' )
.attr( 'x', WIDTH / 2 )
.attr( 'y', X_AXIS_LABEL_BUMP_Y )
.attr( 'text-anchor', 'middle' )
.text( xLabel );
- console.debug( 'xAxisLabel:', xAxisLabel ); window.xAxisLabel = xAxisLabel;
+ //console.debug( 'xAxisLabel:', xAxisLabel ); window.xAxisLabel = xAxisLabel;
var yAxisFn = d3.svg.axis()
.scale( y_scale )
@@ -145,7 +144,7 @@
.orient( 'left' );
var yAxis = chart.append( 'g' ).attr( 'class', 'axis' ).attr( 'id', 'y-axis' )
.call( yAxisFn );
- console.debug( 'yAxis:', yAxis ); window.yAxis = yAxis, window.yAxisFn = yAxisFn;
+ //console.debug( 'yAxis:', yAxis ); window.yAxis = yAxis, window.yAxisFn = yAxisFn;
var yAxisLabel = yAxis.append( 'text' ).attr( 'class', 'axis-label' ).attr( 'id', 'y-axis-label' )
.attr( 'x', Y_AXIS_LABEL_BUMP_X )
@@ -153,7 +152,7 @@
.attr( 'text-anchor', 'middle' )
.attr( 'transform', rotateStr( -90, Y_AXIS_LABEL_BUMP_X, HEIGHT / 2 ) )
.text( yLabel );
- console.debug( 'yAxisLabel:', yAxisLabel ); window.yAxisLabel = yAxisLabel;
+ //console.debug( 'yAxisLabel:', yAxisLabel ); window.yAxisLabel = yAxisLabel;
// grid lines
var hGridLines = chart.selectAll( '.h-grid-line' )
@@ -162,7 +161,7 @@
.classed( 'grid-line h-grid-line', true )
.attr( 'x1', x_scale ).attr( 'y1', 0 )
.attr( 'x2', x_scale ).attr( 'y2', HEIGHT )
- console.debug( 'hGridLines:', hGridLines ); window.hGridLines = hGridLines;
+ //console.debug( 'hGridLines:', hGridLines ); window.hGridLines = hGridLines;
var vGridLines = chart.selectAll( '.v-grid-line' )
.data( y_scale.ticks( yAxisFn.ticks()[0] ) )
@@ -170,7 +169,7 @@
.classed( 'grid-line v-grid-line', true )
.attr( 'x1', 0 ) .attr( 'y1', y_scale )
.attr( 'x2', WIDTH ).attr( 'y2', y_scale )
- console.debug( 'vGridLines:', vGridLines ); window.vGridLines = vGridLines;
+ //console.debug( 'vGridLines:', vGridLines ); window.vGridLines = vGridLines;
// Functions used to render plot.
var xPosFn = function( d, i ){
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/changeset/5a61f5123386/
changeset: 5a61f5123386
user: james_taylor
date: 2012-09-17 22:24:13
summary: trackster: moving more stuff out of mako into javascript
affected #: 2 files
diff -r 6c0bb542d2e0cbda209e473db9d77a7076614f0d -r 5a61f51233861c6f7f4be41c5fd2de94d468ea61 static/scripts/viz/trackster_ui.js
--- a/static/scripts/viz/trackster_ui.js
+++ b/static/scripts/viz/trackster_ui.js
@@ -12,6 +12,90 @@
this.baseURL = baseURL;
},
+
+ /**
+ * Create button menu
+ */
+ createButtonMenu: function() {
+ var menu = create_icon_buttons_menu([
+ { icon_class: 'plus-button', title: 'Add tracks', on_click: function() {
+ add_datasets(add_datasets_url, add_track_async_url, function(tracks) {
+ _.each(tracks, function(track) {
+ view.add_drawable( trackster_ui.object_from_template(track, view, view) );
+ });
+ });
+ } },
+ { icon_class: 'block--plus', title: 'Add group', on_click: function() {
+ view.add_drawable( new tracks.DrawableGroup(view, view, { name: "New Group" }) );
+ } },
+ { icon_class: 'bookmarks', title: 'Bookmarks', on_click: function() {
+ // HACK -- use style to determine if panel is hidden and hide/show accordingly.
+ parent.force_right_panel(($("div#right").css("right") == "0px" ? "hide" : "show"));
+ } },
+ {
+ icon_class: 'globe',
+ title: 'Circster',
+ on_click: function() {
+ // Add viz id dynamically so that newly saved visualizations work as well.
+ window.location = "${h.url_for( controller='visualization', action='circster' )}?id=" + view.vis_id;
+ }
+ },
+ { icon_class: 'disk--arrow', title: 'Save', on_click: function() {
+ // Show saving dialog box
+ show_modal("Saving...", "progress");
+
+ // Save bookmarks.
+ var bookmarks = [];
+ $(".bookmark").each(function() {
+ bookmarks.push({
+ position: $(this).children(".position").text(),
+ annotation: $(this).children(".annotation").text()
+ });
+ });
+
+ // FIXME: give unique IDs to Drawables and save overview as ID.
+ var overview_track_name = (view.overview_drawable ? view.overview_drawable.name : null),
+ viz_config = {
+ 'id': view.vis_id,
+ 'title': view.name,
+ 'dbkey': view.dbkey,
+ 'type': 'trackster',
+ 'datasets': view.to_dict(),
+ 'viewport': { 'chrom': view.chrom, 'start': view.low , 'end': view.high, 'overview': overview_track_name },
+ 'bookmarks': bookmarks
+ };
+
+ $.ajax({
+ url: galaxy_paths.get("visualization_url"),
+ type: "POST",
+ dataType: "json",
+ data: {
+ vis_json: JSON.stringify(viz_config)
+ }
+ }).success(function(vis_info) {
+ hide_modal();
+ view.vis_id = vis_info.vis_id;
+ view.has_changes = false;
+
+ // Needed to set URL when first saving a visualization.
+ window.history.pushState({}, "", vis_info.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 = "${h.url_for( controller='visualization', action='list' )}";
+ } }
+ ],
+ {
+ tooltip_config: { placement: 'bottom' }
+ });
+ this.buttonMenu = menu;
+ return menu;
+ },
+
/**
* Use a popup to select a dataset of create bookmarks from
*/
diff -r 6c0bb542d2e0cbda209e473db9d77a7076614f0d -r 5a61f51233861c6f7f4be41c5fd2de94d468ea61 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -61,85 +61,12 @@
var browser_router;
$(function() {
- // Create and initialize menu.
- var menu = create_icon_buttons_menu([
- { icon_class: 'plus-button', title: 'Add tracks', on_click: function() {
- add_datasets(add_datasets_url, add_track_async_url, function(tracks) {
- _.each(tracks, function(track) {
- view.add_drawable( trackster_ui.object_from_template(track, view, view) );
- });
- });
- } },
- { icon_class: 'block--plus', title: 'Add group', on_click: function() {
- view.add_drawable( new tracks.DrawableGroup(view, view, { name: "New Group" }) );
- } },
- { icon_class: 'bookmarks', title: 'Bookmarks', on_click: function() {
- // HACK -- use style to determine if panel is hidden and hide/show accordingly.
- parent.force_right_panel(($("div#right").css("right") == "0px" ? "hide" : "show"));
- } },
- {
- icon_class: 'globe',
- title: 'Circster',
- on_click: function() {
- // Add viz id dynamically so that newly saved visualizations work as well.
- window.location = "${h.url_for( controller='visualization', action='circster' )}?id=" + view.vis_id;
- }
- },
- { icon_class: 'disk--arrow', title: 'Save', on_click: function() {
- // Show saving dialog box
- show_modal("Saving...", "progress");
-
- // Save bookmarks.
- var bookmarks = [];
- $(".bookmark").each(function() {
- bookmarks.push({
- position: $(this).children(".position").text(),
- annotation: $(this).children(".annotation").text()
- });
- });
- // FIXME: give unique IDs to Drawables and save overview as ID.
- var overview_track_name = (view.overview_drawable ? view.overview_drawable.name : null),
- viz_config = {
- 'id': view.vis_id,
- 'title': view.name,
- 'dbkey': view.dbkey,
- 'type': 'trackster',
- 'datasets': view.to_dict(),
- 'viewport': { 'chrom': view.chrom, 'start': view.low , 'end': view.high, 'overview': overview_track_name },
- 'bookmarks': bookmarks
- };
+ ui.createButtonMenu();
- $.ajax({
- url: galaxy_paths.get("visualization_url"),
- type: "POST",
- dataType: "json",
- data: {
- vis_json: JSON.stringify(viz_config)
- }
- }).success(function(vis_info) {
- hide_modal();
- view.vis_id = vis_info.vis_id;
- view.has_changes = false;
-
- // Needed to set URL when first saving a visualization.
- window.history.pushState({}, "", vis_info.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 = "${h.url_for( controller='visualization', action='list' )}";
- } }
- ],
- {
- tooltip_config: { placement: 'bottom' }
- });
-
- menu.$el.attr("style", "float: right");
- $("#center .unified-panel-header-inner").append(menu.$el);
+ // Attach the button menu to the panel header and float it left
+ ui.buttonMenu.$el.attr("style", "float: right");
+ $("#center .unified-panel-header-inner").append(ui.buttonMenu.$el);
// Hide bookmarks by default right now.
parent.force_right_panel("hide");
@@ -159,7 +86,7 @@
JSON.parse('${ h.to_json_string( config['bookmarks'] ) }'),
true
);
- init_editor();
+ ui.init_editor();
set_up_router({view: view});
%else:
var continue_fn = function() {
@@ -169,7 +96,7 @@
dbkey: $("#new-dbkey").val()
} );
view.editor = true;
- init_editor();
+ ui.init_editor();
set_up_router({view: view});
hide_modal();
};
https://bitbucket.org/galaxy/galaxy-central/changeset/65ecf4e0ed28/
changeset: 65ecf4e0ed28
user: james_taylor
date: 2012-09-17 22:24:27
summary: pack
affected #: 1 file
diff -r 5a61f51233861c6f7f4be41c5fd2de94d468ea61 -r 65ecf4e0ed28eaa2f3e64495ab800aa7c9779a54 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"],function(f,c,g,d,b){var a=b.object_from_template;var e=f.Base.extend({initialize:function(h){this.baseURL=h},add_bookmarks:function(){var h=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(j){show_modal("Select dataset for new bookmarks",j,{Cancel:function(){hide_modal()},Insert:function(){$("input[name=id]:checked,input[name=ldda_ids]:checked").first().each(function(){var k,l=$(this).val();if($(this).attr("name")==="id"){k={hda_id:l}}else{k={ldda_id:l}}$.ajax({url:this.baseURL+"/visualization/bookmarks_from_dataset",data:k,dataType:"json",}).then(function(m){for(i=0;i<m.data.length;i++){var n=m.data[i];add_bookmark(n[0],n[1])}})});hide_modal()}})}})},add_bookmark:function(m,k,h){var o=$("#bookmarks-container"),q=$("<div/>").addClass("bookmark").appendTo(o);var r=$("<div/>").addClass("position").appendTo(q),n=$("<a href=''/>").text(m).appendTo(r).click(function(){view.go_to(m);return false}),l=$("<div/>").text(k).appendTo(q);if(h){var p=$("<div/>").addClass("delete-icon-container").prependTo(q).click(function(){q.slideUp("fast");q.remove();view.has_changes=true;return false}),j=$("<a href=''/>").addClass("icon-button delete").appendTo(p);l.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return q},create_visualization:function(l,h,k,m,j){view=new b.View(l);view.editor=true;$.when(view.load_chroms_deferred).then(function(){if(h){var v=h.chrom,n=h.start,s=h.end,p=h.overview;if(v&&(n!==undefined)&&s){view.change_chrom(v,n,s)}}if(k){var q,o,r;for(var t=0;t<k.length;t++){view.add_drawable(a(k[t],view,view))}}view.update_intro_div();var w;for(var t=0;t<view.drawables.length;t++){if(view.drawables[t].name===p){view.set_overview(view.drawables[t]);break}}if(m){var u;for(var t=0;t<m.length;t++){u=m[t];add_bookmark(u.position,u.annotation,j)}}view.has_changes=false});return view},init_keyboard_nav:function(h){$(document).keydown(function(j){if($(j.srcElement).is(":input")){return}switch(j.which){case 37:h.move_fraction(0.25);break;case 38:var k=Math.round(h.viewport_container.height()/15);h.viewport_container.scrollTop(h.viewport_container.scrollTop()-20);break;case 39:h.move_fraction(-0.25);break;case 40:var k=Math.round(h.viewport_container.height()/15);h.viewport_container.scrollTop(h.viewport_container.scrollTop()+20);break}})}});return{object_from_template:a,TracksterUI:e}});
\ No newline at end of file
+define(["base","libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks"],function(f,c,g,d,b){var a=b.object_from_template;var e=f.Base.extend({initialize:function(h){this.baseURL=h},createButtonMenu:function(){var h=create_icon_buttons_menu([{icon_class:"plus-button",title:"Add tracks",on_click:function(){add_datasets(add_datasets_url,add_track_async_url,function(j){c.each(j,function(k){view.add_drawable(trackster_ui.object_from_template(k,view,view))})})}},{icon_class:"block--plus",title:"Add group",on_click:function(){view.add_drawable(new b.DrawableGroup(view,view,{name:"New Group"}))}},{icon_class:"bookmarks",title:"Bookmarks",on_click:function(){parent.force_right_panel(($("div#right").css("right")=="0px"?"hide":"show"))}},{icon_class:"globe",title:"Circster",on_click:function(){window.location="${h.url_for( controller='visualization', action='circster' )}?id="+view.vis_id}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var j=[];$(".bookmark").each(function(){j.push({position:$(this).children(".position").text(),annotation:$(this).children(".annotation").text()})});var k=(view.overview_drawable?view.overview_drawable.name:null),l={id:view.vis_id,title:view.name,dbkey:view.dbkey,type:"trackster",datasets:view.to_dict(),viewport:{chrom:view.chrom,start:view.low,end:view.high,overview:k},bookmarks:j};$.ajax({url:galaxy_paths.get("visualization_url"),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(l)}}).success(function(m){hide_modal();view.vis_id=m.vis_id;view.has_changes=false;window.history.pushState({},"",m.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="${h.url_for( controller='visualization', action='list' )}"}}],{tooltip_config:{placement:"bottom"}});this.buttonMenu=h;return h},add_bookmarks:function(){var h=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(j){show_modal("Select dataset for new bookmarks",j,{Cancel:function(){hide_modal()},Insert:function(){$("input[name=id]:checked,input[name=ldda_ids]:checked").first().each(function(){var k,l=$(this).val();if($(this).attr("name")==="id"){k={hda_id:l}}else{k={ldda_id:l}}$.ajax({url:this.baseURL+"/visualization/bookmarks_from_dataset",data:k,dataType:"json",}).then(function(m){for(i=0;i<m.data.length;i++){var n=m.data[i];add_bookmark(n[0],n[1])}})});hide_modal()}})}})},add_bookmark:function(m,k,h){var o=$("#bookmarks-container"),q=$("<div/>").addClass("bookmark").appendTo(o);var r=$("<div/>").addClass("position").appendTo(q),n=$("<a href=''/>").text(m).appendTo(r).click(function(){view.go_to(m);return false}),l=$("<div/>").text(k).appendTo(q);if(h){var p=$("<div/>").addClass("delete-icon-container").prependTo(q).click(function(){q.slideUp("fast");q.remove();view.has_changes=true;return false}),j=$("<a href=''/>").addClass("icon-button delete").appendTo(p);l.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return q},create_visualization:function(l,h,k,m,j){view=new b.View(l);view.editor=true;$.when(view.load_chroms_deferred).then(function(){if(h){var v=h.chrom,n=h.start,s=h.end,p=h.overview;if(v&&(n!==undefined)&&s){view.change_chrom(v,n,s)}}if(k){var q,o,r;for(var t=0;t<k.length;t++){view.add_drawable(a(k[t],view,view))}}view.update_intro_div();var w;for(var t=0;t<view.drawables.length;t++){if(view.drawables[t].name===p){view.set_overview(view.drawables[t]);break}}if(m){var u;for(var t=0;t<m.length;t++){u=m[t];add_bookmark(u.position,u.annotation,j)}}view.has_changes=false});return view},init_keyboard_nav:function(h){$(document).keydown(function(j){if($(j.srcElement).is(":input")){return}switch(j.which){case 37:h.move_fraction(0.25);break;case 38:var k=Math.round(h.viewport_container.height()/15);h.viewport_container.scrollTop(h.viewport_container.scrollTop()-20);break;case 39:h.move_fraction(-0.25);break;case 40:var k=Math.round(h.viewport_container.height()/15);h.viewport_container.scrollTop(h.viewport_container.scrollTop()+20);break}})}});return{object_from_template:a,TracksterUI:e}});
\ 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
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/67c3ec05a121/
changeset: 67c3ec05a121
user: james_taylor
date: 2012-09-17 22:14:52
summary: trackster: misc fixes and reorganization
affected #: 3 files
diff -r 9deeb2fec6612253de699cc7207ffba09775c88b -r 67c3ec05a12195d30a3fc0ce5247cbc4545027e3 static/scripts/base.js
--- a/static/scripts/base.js
+++ b/static/scripts/base.js
@@ -1,15 +1,15 @@
-define( "libs/backbone", function( backbone ) {
+define( ["libs/backbone/backbone"], function( Backbone ) {
var Base = function() {
if( this.initialize ) {
this.initialize.apply(this, arguments);
}
};
- Base.extend = backbone.Backbone.Model.extend;
+ Base.extend = Backbone.Model.extend;
return {
Base: Base,
- Backbone: backbone.Backbone
+ Backbone: Backbone
};
});
\ No newline at end of file
diff -r 9deeb2fec6612253de699cc7207ffba09775c88b -r 67c3ec05a12195d30a3fc0ce5247cbc4545027e3 static/scripts/viz/trackster_ui.js
--- a/static/scripts/viz/trackster_ui.js
+++ b/static/scripts/viz/trackster_ui.js
@@ -1,4 +1,4 @@
-define( ["libs/underscore","viz/trackster/slotting", "viz/trackster/painters","viz/trackster/tracks"], function( _, slotting, painters, tracks ) {
+define( ["base","libs/underscore","viz/trackster/slotting", "viz/trackster/painters","viz/trackster/tracks"], function( base, _, slotting, painters, tracks ) {
/************************************************************************
* Functions used for creating and managing the Trackster user interface.
@@ -6,139 +6,191 @@
var object_from_template = tracks.object_from_template;
-/**
- * Add bookmark.
- */
-var add_bookmark = function(position, annotation, editable) {
- // Create HTML.
- var bookmarks_container = $("#bookmarks-container"),
- new_bookmark = $("<div/>").addClass("bookmark").appendTo(bookmarks_container);
+var TracksterUI = base.Base.extend({
- var position_div = $("<div/>").addClass("position").appendTo(new_bookmark),
- position_link = $("<a href=''/>").text(position).appendTo(position_div).click(function() {
- view.go_to(position);
- return false;
- }),
- annotation_div = $("<div/>").text(annotation).appendTo(new_bookmark);
+ initialize: function( baseURL ) {
+ this.baseURL = baseURL;
+ },
- // If editable, enable bookmark deletion and annotation editing.
- if (editable) {
- var delete_icon_container = $("<div/>").addClass("delete-icon-container").prependTo(new_bookmark).click(function (){
- // Remove bookmark.
- new_bookmark.slideUp("fast");
- new_bookmark.remove();
- view.has_changes = true;
+ /**
+ * Use a popup to select a dataset of create bookmarks from
+ */
+ add_bookmarks: function() {
+ var baseURL = 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(table_html) {
+ show_modal(
+ "Select dataset for new bookmarks",
+ table_html, {
+ "Cancel": function() {
+ hide_modal();
+ },
+ "Insert": function() {
+ // Just use the first selected
+ $('input[name=id]:checked,input[name=ldda_ids]:checked').first().each(function(){
+ var data, id = $(this).val();
+ if ($(this).attr("name") === "id") {
+ data = { hda_id: id };
+ } else {
+ data = { ldda_id: id};
+ }
+
+ $.ajax({
+ url: this.baseURL + "/visualization/bookmarks_from_dataset",
+ data: data,
+ dataType: "json",
+ }).then( function(data) {
+ for( i = 0; i < data.data.length; i++ ) {
+ var row = data.data[i];
+ add_bookmark( row[0], row[1] );
+ }
+ });
+ });
+ hide_modal();
+ }
+ }
+ );
+ }
+ });
+ },
+
+ /**
+ * Add bookmark.
+ */
+ add_bookmark: function(position, annotation, editable) {
+ // Create HTML.
+ var bookmarks_container = $("#bookmarks-container"),
+ new_bookmark = $("<div/>").addClass("bookmark").appendTo(bookmarks_container);
+
+ var position_div = $("<div/>").addClass("position").appendTo(new_bookmark),
+ position_link = $("<a href=''/>").text(position).appendTo(position_div).click(function() {
+ view.go_to(position);
return false;
}),
- delete_icon = $("<a href=''/>").addClass("icon-button delete").appendTo(delete_icon_container);
- annotation_div.make_text_editable({
- num_rows: 3,
- use_textarea: true,
- help_text: "Edit bookmark note"
- }).addClass("annotation");
+ annotation_div = $("<div/>").text(annotation).appendTo(new_bookmark);
+
+ // If editable, enable bookmark deletion and annotation editing.
+ if (editable) {
+ var delete_icon_container = $("<div/>").addClass("delete-icon-container").prependTo(new_bookmark).click(function (){
+ // Remove bookmark.
+ new_bookmark.slideUp("fast");
+ new_bookmark.remove();
+ view.has_changes = true;
+ return false;
+ }),
+ delete_icon = $("<a href=''/>").addClass("icon-button delete").appendTo(delete_icon_container);
+ annotation_div.make_text_editable({
+ num_rows: 3,
+ use_textarea: true,
+ help_text: "Edit bookmark note"
+ }).addClass("annotation");
+ }
+
+ view.has_changes = true;
+ return new_bookmark;
+ },
+
+ /**
+ * Create a complete Trackster visualization. Returns view.
+ */
+ create_visualization: function(view_config, viewport_config, drawables_config, bookmarks_config, editable) {
+
+ // Create view.
+ view = new tracks.View(view_config);
+ view.editor = true;
+ $.when( view.load_chroms_deferred ).then(function() {
+ // Viewport config.
+ if (viewport_config) {
+ var
+ chrom = viewport_config.chrom,
+ start = viewport_config.start,
+ end = viewport_config.end,
+ overview_drawable_name = viewport_config.overview;
+
+ if (chrom && (start !== undefined) && end) {
+ view.change_chrom(chrom, start, end);
+ }
+ }
+
+ // Add drawables to view.
+ if (drawables_config) {
+ // FIXME: can from_dict() be used to create view and add drawables?
+ var drawable_config,
+ drawable_type,
+ drawable;
+ for (var i = 0; i < drawables_config.length; i++) {
+ view.add_drawable( object_from_template( drawables_config[i], view, view ) );
+ }
+ }
+
+ // Need to update intro div after drawables have been added.
+ view.update_intro_div();
+
+ // Set overview.
+ var overview_drawable;
+ for (var i = 0; i < view.drawables.length; i++) {
+ if (view.drawables[i].name === overview_drawable_name) {
+ view.set_overview(view.drawables[i]);
+ break;
+ }
+ }
+
+ // Load bookmarks.
+ if (bookmarks_config) {
+ var bookmark;
+ for (var i = 0; i < bookmarks_config.length; i++) {
+ bookmark = bookmarks_config[i];
+ add_bookmark(bookmark['position'], bookmark['annotation'], editable);
+ }
+ }
+
+ // View has no changes as of yet.
+ view.has_changes = false;
+ });
+
+ return view;
+ },
+
+ /**
+ * Set up keyboard navigation for a visualization.
+ */
+ init_keyboard_nav: function(view) {
+ // Keyboard navigation. Scroll ~7% of height when scrolling up/down.
+ $(document).keydown(function(e) {
+ // Do not navigate if arrow keys used in input element.
+ if ($(e.srcElement).is(':input')) {
+ return;
+ }
+
+ // Key codes: left == 37, up == 38, right == 39, down == 40
+ switch(e.which) {
+ case 37:
+ view.move_fraction(0.25);
+ break
+ case 38:
+ var change = Math.round(view.viewport_container.height()/15.0);
+ view.viewport_container.scrollTop( view.viewport_container.scrollTop() - 20);
+ break;
+ case 39:
+ view.move_fraction(-0.25);
+ break;
+ case 40:
+ var change = Math.round(view.viewport_container.height()/15.0);
+ view.viewport_container.scrollTop( view.viewport_container.scrollTop() + 20);
+ break;
+ }
+ });
}
- view.has_changes = true;
- return new_bookmark;
-};
-
-/**
- * Create a complete Trackster visualization. Returns view.
- */
-var create_visualization = function(view_config, viewport_config, drawables_config, bookmarks_config, editable) {
-
- // Create view.
- view = new tracks.View(view_config);
- view.editor = true;
- $.when( view.load_chroms_deferred ).then(function() {
- // Viewport config.
- if (viewport_config) {
- var
- chrom = viewport_config.chrom,
- start = viewport_config.start,
- end = viewport_config.end,
- overview_drawable_name = viewport_config.overview;
-
- if (chrom && (start !== undefined) && end) {
- view.change_chrom(chrom, start, end);
- }
- }
-
- // Add drawables to view.
- if (drawables_config) {
- // FIXME: can from_dict() be used to create view and add drawables?
- var drawable_config,
- drawable_type,
- drawable;
- for (var i = 0; i < drawables_config.length; i++) {
- view.add_drawable( object_from_template( drawables_config[i], view, view ) );
- }
- }
-
- // Need to update intro div after drawables have been added.
- view.update_intro_div();
-
- // Set overview.
- var overview_drawable;
- for (var i = 0; i < view.drawables.length; i++) {
- if (view.drawables[i].name === overview_drawable_name) {
- view.set_overview(view.drawables[i]);
- break;
- }
- }
-
- // Load bookmarks.
- if (bookmarks_config) {
- var bookmark;
- for (var i = 0; i < bookmarks_config.length; i++) {
- bookmark = bookmarks_config[i];
- add_bookmark(bookmark['position'], bookmark['annotation'], editable);
- }
- }
-
- // View has no changes as of yet.
- view.has_changes = false;
- });
-
- return view;
-};
-
-/**
- * Set up keyboard navigation for a visualization.
- */
- var init_keyboard_nav = function(view) {
- // Keyboard navigation. Scroll ~7% of height when scrolling up/down.
- $(document).keydown(function(e) {
- // Do not navigate if arrow keys used in input element.
- if ($(e.srcElement).is(':input')) {
- return;
- }
-
- // Key codes: left == 37, up == 38, right == 39, down == 40
- switch(e.which) {
- case 37:
- view.move_fraction(0.25);
- break
- case 38:
- var change = Math.round(view.viewport_container.height()/15.0);
- view.viewport_container.scrollTop( view.viewport_container.scrollTop() - 20);
- break;
- case 39:
- view.move_fraction(-0.25);
- break;
- case 40:
- var change = Math.round(view.viewport_container.height()/15.0);
- view.viewport_container.scrollTop( view.viewport_container.scrollTop() + 20);
- break;
- }
- });
-};
+});
return {
- add_bookmark: add_bookmark,
object_from_template: object_from_template,
- create_visualization: create_visualization,
- init_keyboard_nav: init_keyboard_nav
+ TracksterUI: TracksterUI
};
});
diff -r 9deeb2fec6612253de699cc7207ffba09775c88b -r 67c3ec05a12195d30a3fc0ce5247cbc4545027e3 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -31,12 +31,11 @@
require.config({
baseUrl: "${h.url_for('/static/scripts') }",
shim: {
- "libs/underscore": { exports: "_" }
+ "libs/underscore": { exports: "_" },
+ "libs/backbone/backbone": { exports: "Backbone" }
}
});
- require( ["viz/trackster_ui","viz/trackster/util","viz/trackster/tracks"], function( trackster_ui, util, tracks ) {
-
- var add_bookmark = trackster_ui.add_bookmark
+ require( ["base", "viz/trackster_ui","viz/trackster/util","viz/trackster/tracks"], function( base, trackster_ui, util, tracks ) {
//
// Place URLs here so that url_for can be used to generate them.
@@ -48,8 +47,9 @@
${render_trackster_js_vars()}
var view,
- browser_router;
-
+ browser_router,
+ ui = new (trackster_ui.TracksterUI)( "${h.url_for('/')}" );
+
/**
* Set up router.
*/
@@ -58,51 +58,7 @@
Backbone.history.start();
};
- /**
- * Use a popup grid to bookmarks from a dataset.
- */
- var add_bookmarks = function() {
- show_modal( "Select dataset for new bookmarks", "progress" );
- $.ajax({
- url: "${h.url_for( controller='visualization', action='list_histories' )}",
- data: { "f-dbkey": view.dbkey },
- error: function() { alert( "Grid failed" ); },
- success: function(table_html) {
- show_modal(
- "Select dataset for new bookmarks",
- table_html, {
- "Cancel": function() {
- hide_modal();
- },
- "Insert": function() {
- // Just use the first selected
- $('input[name=id]:checked,input[name=ldda_ids]:checked').first().each(function(){
- var data, id = $(this).val();
- if ($(this).attr("name") === "id") {
- data = { hda_id: id };
- } else {
- data = { ldda_id: id};
- }
- $.ajax({
- url: "${h.url_for( action='bookmarks_from_dataset' )}",
- data: data,
- dataType: "json",
- }).then( function(data) {
- for( i = 0; i < data.data.length; i++ ) {
- var row = data.data[i];
- add_bookmark( row[0], row[1] );
- }
- });
- });
- hide_modal();
- }
- }
- );
- }
- });
- };
-
var browser_router;
$(function() {
// Create and initialize menu.
@@ -192,7 +148,7 @@
$("#right-border").click(function() { view.resize_window(); });
%if config:
- view = trackster_ui.create_visualization( {
+ view = ui.create_visualization( {
container: $("#browser-container"),
name: "${config.get('title') | h}",
vis_id: "${config.get('vis_id')}",
@@ -262,7 +218,7 @@
// Add new bookmark.
var position = view.chrom + ":" + view.low + "-" + view.high,
annotation = "Bookmark description";
- return add_bookmark(position, annotation, true);
+ return ui.add_bookmark(position, annotation, true);
});
// make_popupmenu( $("#bookmarks-more-button"), {
@@ -271,7 +227,7 @@
// }
// });
- trackster_ui.init_keyboard_nav(view);
+ ui.init_keyboard_nav(view);
};
});
https://bitbucket.org/galaxy/galaxy-central/changeset/6c0bb542d2e0/
changeset: 6c0bb542d2e0
user: james_taylor
date: 2012-09-17 22:15:09
summary: pack scripts
affected #: 2 files
diff -r 67c3ec05a12195d30a3fc0ce5247cbc4545027e3 -r 6c0bb542d2e0cbda209e473db9d77a7076614f0d static/scripts/packed/base.js
--- a/static/scripts/packed/base.js
+++ b/static/scripts/packed/base.js
@@ -1,1 +1,1 @@
-define("libs/backbone",function(b){var a=function(){if(this.initialize){this.initialize.apply(this,arguments)}};a.extend=b.Backbone.Model.extend;return{Base:a,Backbone:b.Backbone}});
\ No newline at end of file
+define(["libs/backbone/backbone"],function(b){var a=function(){if(this.initialize){this.initialize.apply(this,arguments)}};a.extend=b.Model.extend;return{Base:a,Backbone:b}});
\ No newline at end of file
diff -r 67c3ec05a12195d30a3fc0ce5247cbc4545027e3 -r 6c0bb542d2e0cbda209e473db9d77a7076614f0d 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(["libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks"],function(d,h,g,c){var a=c.object_from_template;var f=function(m,k,i){var o=$("#bookmarks-container"),q=$("<div/>").addClass("bookmark").appendTo(o);var r=$("<div/>").addClass("position").appendTo(q),n=$("<a href=''/>").text(m).appendTo(r).click(function(){view.go_to(m);return false}),l=$("<div/>").text(k).appendTo(q);if(i){var p=$("<div/>").addClass("delete-icon-container").prependTo(q).click(function(){q.slideUp("fast");q.remove();view.has_changes=true;return false}),j=$("<a href=''/>").addClass("icon-button delete").appendTo(p);l.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return q};var b=function(l,i,k,m,j){view=new c.View(l);view.editor=true;$.when(view.load_chroms_deferred).then(function(){if(i){var v=i.chrom,n=i.start,s=i.end,p=i.overview;if(v&&(n!==undefined)&&s){view.change_chrom(v,n,s)}}if(k){var q,o,r;for(var t=0;t<k.length;t++){view.add_drawable(a(k[t],view,view))}}view.update_intro_div();var w;for(var t=0;t<view.drawables.length;t++){if(view.drawables[t].name===p){view.set_overview(view.drawables[t]);break}}if(m){var u;for(var t=0;t<m.length;t++){u=m[t];f(u.position,u.annotation,j)}}view.has_changes=false});return view};var e=function(i){$(document).keydown(function(j){if($(j.srcElement).is(":input")){return}switch(j.which){case 37:i.move_fraction(0.25);break;case 38:var k=Math.round(i.viewport_container.height()/15);i.viewport_container.scrollTop(i.viewport_container.scrollTop()-20);break;case 39:i.move_fraction(-0.25);break;case 40:var k=Math.round(i.viewport_container.height()/15);i.viewport_container.scrollTop(i.viewport_container.scrollTop()+20);break}})};return{add_bookmark:f,object_from_template:a,create_visualization:b,init_keyboard_nav:e}});
\ No newline at end of file
+define(["base","libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks"],function(f,c,g,d,b){var a=b.object_from_template;var e=f.Base.extend({initialize:function(h){this.baseURL=h},add_bookmarks:function(){var h=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(j){show_modal("Select dataset for new bookmarks",j,{Cancel:function(){hide_modal()},Insert:function(){$("input[name=id]:checked,input[name=ldda_ids]:checked").first().each(function(){var k,l=$(this).val();if($(this).attr("name")==="id"){k={hda_id:l}}else{k={ldda_id:l}}$.ajax({url:this.baseURL+"/visualization/bookmarks_from_dataset",data:k,dataType:"json",}).then(function(m){for(i=0;i<m.data.length;i++){var n=m.data[i];add_bookmark(n[0],n[1])}})});hide_modal()}})}})},add_bookmark:function(m,k,h){var o=$("#bookmarks-container"),q=$("<div/>").addClass("bookmark").appendTo(o);var r=$("<div/>").addClass("position").appendTo(q),n=$("<a href=''/>").text(m).appendTo(r).click(function(){view.go_to(m);return false}),l=$("<div/>").text(k).appendTo(q);if(h){var p=$("<div/>").addClass("delete-icon-container").prependTo(q).click(function(){q.slideUp("fast");q.remove();view.has_changes=true;return false}),j=$("<a href=''/>").addClass("icon-button delete").appendTo(p);l.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return q},create_visualization:function(l,h,k,m,j){view=new b.View(l);view.editor=true;$.when(view.load_chroms_deferred).then(function(){if(h){var v=h.chrom,n=h.start,s=h.end,p=h.overview;if(v&&(n!==undefined)&&s){view.change_chrom(v,n,s)}}if(k){var q,o,r;for(var t=0;t<k.length;t++){view.add_drawable(a(k[t],view,view))}}view.update_intro_div();var w;for(var t=0;t<view.drawables.length;t++){if(view.drawables[t].name===p){view.set_overview(view.drawables[t]);break}}if(m){var u;for(var t=0;t<m.length;t++){u=m[t];add_bookmark(u.position,u.annotation,j)}}view.has_changes=false});return view},init_keyboard_nav:function(h){$(document).keydown(function(j){if($(j.srcElement).is(":input")){return}switch(j.which){case 37:h.move_fraction(0.25);break;case 38:var k=Math.round(h.viewport_container.height()/15);h.viewport_container.scrollTop(h.viewport_container.scrollTop()-20);break;case 39:h.move_fraction(-0.25);break;case 40:var k=Math.round(h.viewport_container.height()/15);h.viewport_container.scrollTop(h.viewport_container.scrollTop()+20);break}})}});return{object_from_template:a,TracksterUI:e}});
\ 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

17 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/9deeb2fec661/
changeset: 9deeb2fec661
user: james_taylor
date: 2012-09-17 21:41:35
summary: trackster: fix adding bookmarks
affected #: 1 file
diff -r 36f7e3a78eb1c670332916afef78b33b805bcd79 -r 9deeb2fec6612253de699cc7207ffba09775c88b templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -36,6 +36,8 @@
});
require( ["viz/trackster_ui","viz/trackster/util","viz/trackster/tracks"], function( trackster_ui, util, tracks ) {
+ var add_bookmark = trackster_ui.add_bookmark
+
//
// Place URLs here so that url_for can be used to generate them.
//
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
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/36f7e3a78eb1/
changeset: 36f7e3a78eb1
user: james_taylor
date: 2012-09-17 21:38:46
summary: trackster: fix groups
affected #: 1 file
diff -r bba6f86ff735d9cc8e09c56383eeef84b2ac0303 -r 36f7e3a78eb1c670332916afef78b33b805bcd79 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -34,7 +34,7 @@
"libs/underscore": { exports: "_" }
}
});
- require( ["viz/trackster_ui","viz/trackster/util"], function( trackster_ui, util ) {
+ require( ["viz/trackster_ui","viz/trackster/util","viz/trackster/tracks"], function( trackster_ui, util, tracks ) {
//
// Place URLs here so that url_for can be used to generate them.
@@ -113,7 +113,7 @@
});
} },
{ icon_class: 'block--plus', title: 'Add group', on_click: function() {
- view.add_drawable( new DrawableGroup(view, view, { name: "New Group" }) );
+ view.add_drawable( new tracks.DrawableGroup(view, view, { name: "New Group" }) );
} },
{ icon_class: 'bookmarks', title: 'Bookmarks', on_click: function() {
// HACK -- use style to determine if panel is hidden and hide/show accordingly.
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
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/bba6f86ff735/
changeset: bba6f86ff735
user: james_taylor
date: 2012-09-17 21:36:11
summary: trackster fixes
affected #: 4 files
diff -r 0e17b12c190312b7836d69d7852afbed15e81bb9 -r bba6f86ff735d9cc8e09c56383eeef84b2ac0303 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/trackster/util","viz/trackster/slotting","viz/trackster/painters"],function(ab,l,t,J){var p=ab.extend;var O=l.get_random_color;var V=function(ac){return("isResolved" in ac)};var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=n[$(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=n[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=n[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)}n[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);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[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)})};exports.moveable=m;var aa=16,E=9,B=20,y=100,G=12000,R=400,I=5000,v=100,o="There was an error in indexing this dataset. ",H="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",C="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.",w="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",P=10,F=20;function W(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 D({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(){},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 x=function(ad,ac,ae){q.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};p(x.prototype,q.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=object_from_template(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(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw()}},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}});var N=function(ad,ac,af){p(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});x.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new X(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 X(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};p(N.prototype,q.prototype,x.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(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 g){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 d){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 S({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 ag=[];for(var ad=0;ad<this.drawables.length;ad++){ag.push(this.drawables[ad].name)}var ae="Composite Track of "+this.drawables.length+" tracks ("+ag.join(", ")+")";var af=new g(this.view,this.view,{name:ae,drawables:this.drawables});var ac=this.container.replace_drawable(this,af,true);af.request_draw()},add_drawable:function(ac){x.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){x.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=p(x.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,ae){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].request_draw(ac,ae)}}});var Z=function(ac){p(ac,{obj_type:"View"});x.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.init();this.canvas_manager=new CanvasManager(this.container.get(0).ownerDocument);this.reset()};ab.extend(Z.prototype,Backbone.Events);p(Z.prototype,x.prototype,{init: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;k(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(){add_datasets(add_datasets_url,add_track_async_url,function(ag){ab.each(ag,function(ah){ac.add_drawable(object_from_template(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_drawables(),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 Y(this,{content_div:this.top_labeltrack}));this.add_label_track(new Y(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")},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:chrom_url+"/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new z(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)},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();ae.request_redraw(true);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!==undefined&&aj!==undefined){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,"");var ak=this,ac,af,ad=ag.split(":"),ai=ad[0],aj=ad[1];if(aj!==undefined){try{var ah=aj.split("-");ac=parseInt(ah[0],10);af=parseInt(ah[1],10)}catch(ae){return false}}ak.change_chrom(ai,ac,af)},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();var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){x.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){x.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(ak,ac,aj,al){var ai=this,ah=(al?[al]:ai.drawables),ae;var ad;for(var ag=0;ag<ah.length;ag++){ad=ah[ag];ae=-1;for(var af=0;af<ai.tracks_to_be_redrawn.length;af++){if(ai.tracks_to_be_redrawn[af][0]===ad){ae=af;break}}if(ae<0){ai.tracks_to_be_redrawn.push([ad,ac,aj])}else{ai.tracks_to_be_redrawn[ag][1]=ac;ai.tracks_to_be_redrawn[ag][2]=aj}}if(!this.requested_redraw){requestAnimationFrame(function(){ai._redraw(ak)});this.requested_redraw=true}},_redraw:function(am){this.requested_redraw=false;var aj=this.low,af=this.high;if(aj<this.max_low){aj=this.max_low}if(af>this.max_high){af=this.max_high}var al=this.high-this.low;if(this.high!==0&&al<this.min_separation){af=aj+this.min_separation}this.low=Math.floor(aj);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var ac=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ai=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var an=13;this.overview_box.css({left:ac,width:Math.max(an,ai)}).show();if(ai<an){this.overview_box.css("left",ac-(an-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ac,width:ai})}if(!am){var ae,ad,ak;for(var ag=0,ah=this.tracks_to_be_redrawn.length;ag<ah;ag++){ae=this.tracks_to_be_redrawn[ag][0];ad=this.tracks_to_be_redrawn[ag][1];ak=this.tracks_to_be_redrawn[ag][2];if(ae){ae._draw(ad,ak)}}this.tracks_to_be_redrawn=[];for(ag=0,ah=this.label_tracks.length;ag<ah;ag++){this.label_tracks[ag]._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.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 L(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.original_dataset_id,tool_id:ac.name},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 ad={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ad.chrom,ad.low,ad.high),ac;if(ah.container===view){var ag=new N(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 ai=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});ai.init_for_tool_data();ai.change_mode(ah.mode);ai.set_filters_manager(ah.filters_manager.copy(ai));ai.update_icons();ac.add_drawable(ai);ai.tiles_div.text("Starting job.");this.update_params();this.run(ad,ai,function(aj){ai.set_dataset(new Dataset(aj));ai.tiles_div.text("Running job.");ai.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),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(H)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(w+ag.message)}else{af(ag)}}})}});var L=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};p(L.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){L.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};p(e.prototype,L.prototype,{update_value:function(){L.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var f=function(ac){this.manager=null;this.name=ac.name;this.index=ac.index;this.tool_id=ac.tool_id;this.tool_exp_name=ac.tool_exp_name};p(f.prototype,{to_dict:function(){return{name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name}}});var c=function(ae,ad,ac){return $("<a/>").attr("href","javascript:void(0);").attr("title",ae).addClass("icon-button").addClass(ad).tooltip().click(ac)};var S=function(ak){f.call(this,ak);this.low=("low" in ak?ak.low:-Number.MAX_VALUE);this.high=("high" in ak?ak.high:Number.MAX_VALUE);this.min=("min" in ak?ak.min:Number.MAX_VALUE);this.max=("max" in ak?ak.max:-Number.MAX_VALUE);this.container=null;this.slider=null;this.slider_label=null;var ag=function(al,am,an){al.click(function(){var at=am.text(),aq=parseFloat(an.slider("option","max")),ap=(aq<=1?4:aq<=1000000?aq.toString().length:6),ar=false,ao=$(this).parents(".slider-row");ao.addClass("input");if(an.slider("option","values")){ap=2*ap+1;ar=true}am.text("");$("<input type='text'/>").attr("size",ap).attr("maxlength",ap).attr("value",at).appendTo(am).focus().select().click(function(au){au.stopPropagation()}).blur(function(){$(this).remove();am.text(at);ao.removeClass("input")}).keyup(function(ay){if(ay.keyCode===27){$(this).trigger("blur")}else{if(ay.keyCode===13){var aw=an.slider("option","min"),au=an.slider("option","max"),ax=function(az){return(isNaN(az)||az>au||az<aw)},av=$(this).val();if(!ar){av=parseFloat(av);if(ax(av)){alert("Parameter value must be in the range ["+aw+"-"+au+"]");return $(this)}}else{av=av.split("-");av=[parseFloat(av[0]),parseFloat(av[1])];if(ax(av[0])||ax(av[1])){alert("Parameter value must be in the range ["+aw+"-"+au+"]");return $(this)}}an.slider((ar?"values":"value"),av);ao.removeClass("input")}}})})};var ad=this;ad.parent_div=$("<div/>").addClass("filter-row slider-row");var ac=$("<div/>").addClass("elt-label").appendTo(ad.parent_div),ai=$("<span/>").addClass("slider-name").text(ad.name+" ").appendTo(ac),ae=$("<span/>").text(this.low+"-"+this.high),af=$("<span/>").addClass("slider-value").appendTo(ac).append("[").append(ae).append("]");ad.values_span=ae;var ah=$("<div/>").addClass("slider").appendTo(ad.parent_div);ad.control_element=$("<div/>").attr("id",ad.name+"-filter-control").appendTo(ah);ad.control_element.slider({range:true,min:this.min,max:this.max,step:this.get_slider_step(this.min,this.max),values:[this.low,this.high],slide:function(al,am){ad.slide(al,am)},change:function(al,am){ad.control_element.slider("option","slide").call(ad.control_element,al,am)}});ad.slider=ad.control_element;ad.slider_label=ae;ag(af,ae,ad.control_element);var aj=$("<div/>").addClass("display-controls").appendTo(ad.parent_div);this.transparency_icon=c("Use filter for data transparency","layer-transparent",function(){if(ad.manager.alpha_filter!==ad){ad.manager.alpha_filter=ad;ad.manager.parent_div.find(".layer-transparent").removeClass("active").hide();ad.transparency_icon.addClass("active").show()}else{ad.manager.alpha_filter=null;ad.transparency_icon.removeClass("active")}ad.manager.track.request_draw(true,true)}).appendTo(aj).hide();this.height_icon=c("Use filter for data height","arrow-resize-090",function(){if(ad.manager.height_filter!==ad){ad.manager.height_filter=ad;ad.manager.parent_div.find(".arrow-resize-090").removeClass("active").hide();ad.height_icon.addClass("active").show()}else{ad.manager.height_filter=null;ad.height_icon.removeClass("active")}ad.manager.track.request_draw(true,true)}).appendTo(aj).hide();ad.parent_div.hover(function(){ad.transparency_icon.show();ad.height_icon.show()},function(){if(ad.manager.alpha_filter!==ad){ad.transparency_icon.hide()}if(ad.manager.height_filter!==ad){ad.height_icon.hide()}});$("<div style='clear: both;'/>").appendTo(ad.parent_div)};p(S.prototype,{to_dict:function(){var ac=f.prototype.to_dict.call(this);return p(ac,{type:"number",min:this.min,max:this.max,low:this.low,high:this.high})},copy:function(){return new S({name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name})},get_slider_step:function(ae,ac){var ad=ac-ae;return(ad<=2?0.01:1)},slide:function(ae,af){var ad=af.values;this.values_span.text(ad[0]+"-"+ad[1]);this.low=ad[0];this.high=ad[1];var ac=this;setTimeout(function(){if(ad[0]===ac.low&&ad[1]===ac.high){ac.manager.track.request_draw(true,true)}},25)},applies_to:function(ac){if(ac.length>this.index){return true}return false},_keep_val:function(ac){return(isNaN(ac)||(ac>=this.low&&ac<=this.high))},keep:function(ad){if(!this.applies_to(ad)){return true}var af=this;var ag=ad[this.index];if(ag instanceof Array){var ae=true;for(var ac=0;ac<ag.length;ac++){if(!this._keep_val(ag[ac])){ae=false;break}}return ae}else{return this._keep_val(ad[this.index])}},update_attrs:function(af){var ac=false;if(!this.applies_to(af)){return ac}var ad=af[this.index];if(!(ad instanceof Array)){ad=[ad]}for(var ae=0;ae<ad.length;ae++){var ag=ad[ae];if(ag<this.min){this.min=Math.floor(ag);ac=true}if(ag>this.max){this.max=Math.ceil(ag);ac=true}}return ac},update_ui_elt:function(){if(this.min<this.max){this.parent_div.show()}else{this.parent_div.hide()}var ad=this.slider.slider("option","min"),ac=this.slider.slider("option","max");if(this.min<ad||this.max>ac){this.slider.slider("option","min",this.min);this.slider.slider("option","max",this.max);this.slider.slider("option","step",this.get_slider_step(this.min,this.max));this.slider.slider("option","values",[this.min,this.max])}}});var X=function(ae,ak){this.track=ae;this.alpha_filter=null;this.height_filter=null;this.filters=[];this.parent_div=$("<div/>").addClass("filters").hide();this.parent_div.bind("drag",function(am){am.stopPropagation()}).click(function(am){am.stopPropagation()}).bind("dblclick",function(am){am.stopPropagation()}).bind("keydown",function(am){am.stopPropagation()});if(ak&&"filters" in ak){var ac=("alpha_filter" in ak?ak.alpha_filter:null),af=("height_filter" in ak?ak.height_filter:null),ah=ak.filters,ad;for(var ai=0;ai<ah.length;ai++){if(ah[ai].type==="number"){ad=new S(ah[ai]);this.add_filter(ad);if(ad.name===ac){this.alpha_filter=ad;ad.transparency_icon.addClass("active").show()}if(ad.name===af){this.height_filter=ad;ad.height_icon.addClass("active").show()}}else{console.log("ERROR: unsupported filter: ",name,type)}}if("visible" in ak&&ak.visible){this.parent_div.show()}}if(this.filters.length!==0){var al=$("<div/>").addClass("param-row").appendTo(this.parent_div);var aj=$("<input type='submit'/>").attr("value","Run on complete dataset").appendTo(al);var ag=this;aj.click(function(){ag.run_on_dataset()})}};p(X.prototype,{show:function(){this.parent_div.show()},hide:function(){this.parent_div.hide()},toggle:function(){this.parent_div.toggle()},visible:function(){return this.parent_div.is(":visible")},to_dict:function(){var af={},ae=[],ad;for(var ac=0;ac<this.filters.length;ac++){ad=this.filters[ac];ae.push(ad.to_dict())}af.filters=ae;af.alpha_filter=(this.alpha_filter?this.alpha_filter.name:null);af.height_filter=(this.height_filter?this.height_filter.name:null);af.visible=this.parent_div.is(":visible");return af},copy:function(ad){var ae=new X(ad);for(var ac=0;ac<this.filters.length;ac++){ae.add_filter(this.filters[ac].copy())}return ae},add_filter:function(ac){ac.manager=this;this.parent_div.append(ac.parent_div);this.filters.push(ac)},remove_all:function(){this.filters=[];this.parent_div.children().remove()},init_filters:function(){for(var ac=0;ac<this.filters.length;ac++){var ad=this.filters[ac];ad.update_ui_elt()}},clear_filters:function(){for(var ac=0;ac<this.filters.length;ac++){var ad=this.filters[ac];ad.slider.slider("option","values",[ad.min,ad.max])}this.alpha_filter=null;this.height_filter=null;this.parent_div.find(".icon-button").hide()},run_on_dataset:function(){var ai=function(am,ak,al){if(!(ak in am)){am[ak]=al}return am[ak]};var ah={},aj,ac;for(var ag=0;ag<this.filters.length;ag++){aj=this.filters[ag];if(aj.tool_id){if(aj.min!==aj.low){ac=ai(ah,aj.tool_id,[]);ac[ac.length]=aj.tool_exp_name+" >= "+aj.low}if(aj.max!==aj.high){ac=ai(ah,aj.tool_id,[]);ac[ac.length]=aj.tool_exp_name+" <= "+aj.high}}}var ad=[];for(var af in ah){ad[ad.length]=[af,ah[af]]}(function ae(aq,an){var al=an[0],am=al[0],ap=al[1],ao="("+ap.join(") and (")+")",ak={cond:ao,input:aq,target_dataset_id:aq,tool_id:am},an=an.slice(1);$.getJSON(run_tool_url,ak,function(ar){if(ar.error){show_modal("Filter Dataset","Error running tool "+am,{Close:hide_modal})}else{if(an.length===0){show_modal("Filtering Dataset","Filter(s) are running on the complete dataset. Outputs are in dataset's history.",{Close:hide_modal})}else{ae(ar.dataset_id,an)}}})})(this.track.dataset_id,ad)}});var A=function(ac,ad){J.Scaler.call(this,ad);this.filter=ac};A.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 D=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(D.prototype,{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(O())})})(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==="float"){ag=parseFloat(ag)}else{if(ah.type==="int"){ag=parseInt(ag)}else{if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}}}if(ag!==ae.values[ah.key]){ae.values[ah.key]=ag;ad=true}}});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 j=function(ac,ah,ae,ad,af,ag){b.call(this,ac,ah,ae,ad,af);this.max_val=ag};p(j.prototype,b.prototype);var M=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:B-1,width:ae.width}).prependTo(this.html_elt);var al=new 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(true)}).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(true)}).dblclick(function(ar){ar.stopPropagation()})}};p(M.prototype,b.prototype);M.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"?W(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 h=function(ad,ac,ae){p(ae,{drag_handle_class:"draghandle"});q.call(this,ad,ac,ae);this.dataset=new Dataset({id:ae.dataset_id,hda_ldda:ae.hda_ldda});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:I);this.data_manager=("data_manager" in ae?ae.data_manager:new GenomeDataManager({dataset:this.dataset,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(h.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 GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new 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=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ac.dataset_id,hda_ldda:ac.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},on_resize:function(){},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 Y){return"LabelTrack"}else{if(this instanceof z){return"ReferenceTrack"}else{if(this instanceof i){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Q){return"VcfTrack"}else{if(this instanceof g){return"CompositeTrack"}else{if(this instanceof d){return"FeatureTrack"}}}}}}}return""},init:function(){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.content_div.css("height","auto");ad.tiles_div.children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset_id){return}var ac=$.Deferred(),ae={hda_ldda:ad.hda_ldda,data_type:this.dataset_check_type,chrom:ad.view.chrom};$.getJSON(this.dataset.url(),ae,function(af){if(!af||af==="error"||af.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(o);if(af.message){var ag=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+af.message+"</pre>",{Close:hide_modal})});ad.tiles_div.append(ag)}}else{if(af==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(H)}else{if(af==="no data"||(af.data!==undefined&&(af.data===null||af.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(C)}else{if(af==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(u);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(af==="data"||af.status==="data"){if(af.valid_chroms){ad.valid_chroms=af.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(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(){},get_drawables:function(){return this}});var K=function(ae,ad,af){h.call(this,ae,ad,af);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new X(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 Cache(P);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(K.prototype,q.prototype,h.prototype,{action_icons_def:h.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(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,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;ac.tile_cache.clear();ac.request_draw();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,ae,ac){return ad+"_"+ae+"_"+ac},request_draw:function(ad,ac){this.view.request_redraw(false,ad,ac,this)},before_draw:function(){},_draw:function(ad,an){if(!this.can_draw()){return}var al=this.view.low,ah=this.view.high,aj=ah-al,ae=this.view.container.width(),ap=this.view.resolution_px_b,ag=this.view.resolution_b_px;if(this.is_overview){al=this.view.max_low;ah=this.view.max_high;ag=(view.max_high-view.max_low)/ae;ap=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(ag*R)),ak=true,ao=[],ai=function(aq){return(aq&&"track" in aq)};while((ac*R*ag)<ah){var am=this.draw_helper(ad,ae,ac,ag,this.tiles_div,ap);if(ai(am)){ao.push(am)}else{ak=false}ac+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;if(ak){this.tiles_div.children(".remove").remove();af.postdraw_actions(ao,ae,ap,an)}},postdraw_actions:function(ae,af,ah,ac){var ag=false;for(var ad=0;ad<ae.length;ad++){if(ae[ad].has_icons){ag=true;break}}if(ag){for(var ad=0;ad<ae.length;ad++){tile=ae[ad];if(!tile.has_icons){tile.html_elt.css("padding-top",B)}}}},draw_helper:function(ac,ao,au,ar,ah,ai,ap){var an=this,ax=this._gen_tile_cache_key(ao,ai,au),af=this._get_tile_bounds(au,ar);if(!ap){ap={}}var aw=(ac?undefined:an.tile_cache.get_elt(ax));if(aw){an.show_tile(aw,ah,ai);return aw}var al=true;var at=an.data_manager.get_data(af,an.mode,ar,an.data_url_extra_params);if(V(at)){al=false}var aj;if(view.reference_track&&ai>view.canvas_manager.char_width_px){aj=view.reference_track.data_manager.get_data(af,an.mode,ar,view.reference_track.data_url_extra_params);if(V(aj)){al=false}}if(al){p(at,ap.more_tile_data);var ak=an.mode;if(ak==="Auto"){ak=an.get_mode(at);an.update_auto_mode(ak)}var ae=an.view.canvas_manager.new_canvas(),av=af.get("start"),ad=af.get("end"),ao=Math.ceil((ad-av)*ai)+an.left_offset,am=an.get_canvas_height(at,ak,ai,ao);ae.width=ao;ae.height=am;var aq=ae.getContext("2d");aq.translate(this.left_offset,0);var aw=an.draw_tile(at,aq,ak,ar,af,ai,aj);if(aw!==undefined){an.tile_cache.set_elt(ax,aw);an.show_tile(aw,ah,ai)}return aw}var ag=$.Deferred();$.when(at,aj).then(function(){view.request_redraw(false,false,false,an);ag.resolve()});return ag},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ag,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var af=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){af-=this.left_offset}ac.css({position:"absolute",top:0,left:af});if(ac.hasClass("remove")){ac.removeClass("remove")}else{ag.append(ac)}ad.after_show_tile(ae)},after_show_tile:function(ac){this.max_height_px=Math.max(this.max_height_px,ac.html_elt.height());ac.html_elt.parent().children().css("height",this.max_height_px+"px");var ad=this.max_height_px;if(this.visible_height_px!==0){ad=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",ad+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*R*ad),ag=Math.ceil(R*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae,ac,af){var ad=this,ag=(ae!==undefined&&ac!==undefined&&af!==undefined?ae+":"+ac+"-"+af:"all");return" - region=["+ag+"], parameters=["+ad.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){return true},can_subset:function(ac){return false},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=I;var ag=new ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset_id,hda_ldda:ad.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 Y=function(ad,ac){var ae={resize:false};h.call(this,ad,ac,ae);this.container_div.addClass("label-track")};p(Y.prototype,h.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ae=this.view,af=ae.high-ae.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/ai)*ai,ag=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ah=(ac-ae.low)/af*ag;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ah-1}));ac+=ai}this.content_div.children(":first").remove();this.content_div.append(ad)}});var g=function(ad,ac,ag){K.call(this,ad,ac,ag);this.drawables=[];this.left_offset=0;if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=object_from_template(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};p(g.prototype,K.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(K.prototype.action_icons_def),to_dict:x.prototype.to_dict,add_drawable:x.prototype.add_drawable,unpack_drawables:x.prototype.unpack_drawables,change_mode:function(ac){K.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,draw_helper:function(ad,at,az,aw,ak,am,au){var ar=this,aD=this._gen_tile_cache_key(at,am,az),ah=this._get_tile_bounds(az,aw);if(!au){au={}}var aC=(ad?undefined:ar.tile_cache.get_elt(aD));if(aC){ar.show_tile(aC,ak,am);return aC}var al=[],ar,ap=true,ax,an;for(var ay=0;ay<this.drawables.length;ay++){ar=this.drawables[ay];ax=ar.data_manager.get_data(ah,ar.mode,aw,ar.data_url_extra_params);if(V(ax)){ap=false}al.push(ax);an=null;if(view.reference_track&&am>view.canvas_manager.char_width_px){an=view.reference_track.data_manager.get_data(ah,ar.mode,aw,view.reference_track.data_url_extra_params);if(V(an)){ap=false}}al.push(an)}if(ap){p(ax,au.more_tile_data);this.tile_predraw_init();var ag=ar.view.canvas_manager.new_canvas(),ai=ar._get_tile_bounds(az,aw),aA=ah.get("start"),ae=ah.get("end"),aB=0,at=Math.ceil((ae-aA)*am)+this.left_offset,aq=0,af=[],ay;var ac=0;for(ay=0;ay<this.drawables.length;ay++,aB+=2){ar=this.drawables[ay];ax=al[aB];var ao=ar.mode;if(ao==="Auto"){ao=ar.get_mode(ax);ar.update_auto_mode(ao)}af.push(ao);ac=ar.get_canvas_height(ax,ao,am,at);if(ac>aq){aq=ac}}ag.width=at;ag.height=(au.height?au.height:aq);aB=0;var av=ag.getContext("2d");av.translate(this.left_offset,0);av.globalAlpha=0.5;av.globalCompositeOperation="source-over";for(ay=0;ay<this.drawables.length;ay++,aB+=2){ar=this.drawables[ay];ax=al[aB];an=al[aB+1];aC=ar.draw_tile(ax,av,af[ay],aw,ah,am,an)}this.tile_cache.set_elt(aD,aC);this.show_tile(aC,ak,am);return aC}var aj=$.Deferred(),ar=this;$.when.apply($,al).then(function(){view.request_redraw(false,false,false,ar);aj.resolve()});return aj},show_group:function(){var af=new N(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()},tile_predraw_init:function(){var af=Number.MAX_VALUE,ac=-af,ad;for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];if(ad instanceof i){if(ad.prefs.min_value<af){af=ad.prefs.min_value}if(ad.prefs.max_value>ac){ac=ad.prefs.max_value}}}for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];ad.prefs.min_value=af;ad.prefs.max_value=ac}},postdraw_actions:function(ae,ah,aj,ad){K.prototype.postdraw_actions.call(this,ae,ah,aj,ad);var ag=-1;for(var af=0;af<ae.length;af++){var ac=ae[af].html_elt.find("canvas").height();if(ac>ag){ag=ac}}for(var af=0;af<ae.length;af++){var ai=ae[af];if(ai.html_elt.find("canvas").height()!==ag){this.draw_helper(true,ah,ai.index,ai.resolution,ai.html_elt.parent(),aj,{height:ag});ai.html_elt.remove()}}}});var z=function(ac){K.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=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};p(z.prototype,q.prototype,K.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:q.prototype.can_draw,draw_helper:function(ag,ae,ac,ad,ah,ai,af){if(ai>this.view.canvas_manager.char_width_px){return K.prototype.draw_helper.call(this,ag,ae,ac,ad,ah,ai,af)}else{this.hide_contents();return null}},draw_tile:function(ak,al,ag,af,ai,am){var ae=this;if(am>this.view.canvas_manager.char_width_px){if(ak.data===null){this.hide_contents();return}var ad=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";ak=ak.data;for(var ah=0,aj=ak.length;ah<aj;ah++){var ac=Math.floor(ah*am);al.fillText(ak[ah],ac,10)}this.show_contents();return new b(ae,ai,af,ad,ak)}this.hide_contents()}});var i=function(ae,ad,af){var ac=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";K.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new D({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:O()},{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.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};p(i.prototype,q.prototype,K.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ac=this;ac.vertical_range=undefined;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.hda_ldda,dataset_id:ac.dataset_id},function(ad){ac.container_div.addClass("line-track");var ag=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=ag.min,ai=ag.max;ae=Math.floor(Math.min(0,Math.max(ae,ag.mean-2*ag.sd)));ai=Math.ceil(Math.max(0,Math.min(ai,ag.mean+2*ag.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ai;$("#track_"+ac.dataset_id+"_minval").val(ac.prefs.min_value);$("#track_"+ac.dataset_id+"_maxval").val(ac.prefs.max_value)}ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.total_frequency=ag.total_frequency;ac.container_div.find(".yaxislabel").remove();var ah=$("<div/>").text(W(ac.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_min_value(aj)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ac.dataset_id+"_minval").prependTo(ac.container_div),af=$("<div/>").text(W(ac.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_max_value(aj)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ac.dataset_id+"_maxval").prependTo(ac.container_div)})},draw_tile:function(al,aj,ae,ad,ag,ak){var ac=aj.canvas,af=ag.get("start"),ai=ag.get("end"),ah=new J.LinePainter(al.data,af,ai,this.prefs,ae);ah.draw(aj,ac.width,ac.height,ak);return new b(this,ag,ad,ac,al.data)},can_subset:function(ac){return false}});var s=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";K.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new D({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{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);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};p(s.prototype,q.prototype,K.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;this.tile_cache.clear();this.request_draw()},draw_tile:function(am,ak,ah,af,ad,al){var ae=ak.canvas,ac=this._get_tile_bounds(ad,af),ag=ac[0],aj=ac[1],ai=new J.DiagonalHeatmapPainter(am.data,ag,aj,this.prefs,ah);ai.draw(ak,ae.width,ae.height,al);return new b(this,ad,af,ae,am.data)}});var d=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];K.call(this,af,ae,ah);var ag=O(),ac=O([ag,"#ffffff"]);this.config=new D({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:"histogram_max",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.tile_cache.clear();ad.set_painter_from_config();ad.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=ah.dataset_id;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(d.prototype,q.prototype,K.prototype,{set_dataset:function(ac){this.dataset_id=ac.get("id");this.hda_ldda=ac.get("hda_ldda");this.dataset=ac;this.data_manager.set("dataset",ac)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=J.ArcLinkedFeaturePainter}else{this.painter=J.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ar,am,ah,ag){K.prototype.postdraw_actions.call(this,ar,ag);var al=this,ao;if(al.mode==="Coverage"){var ad=-1;for(ao=0;ao<ar.length;ao++){var an=ar[ao].max_val;if(an>ad){ad=an}}for(ao=0;ao<ar.length;ao++){var au=ar[ao];if(au.max_val!==ad){au.html_elt.remove();al.draw_helper(true,am,au.index,au.resolution,au.html_elt.parent(),ah,{more_tile_data:{max:ad}})}}}if(al.filters_manager){var ai=al.filters_manager.filters;for(var aq=0;aq<ai.length;aq++){ai[aq].update_ui_elt()}var at=false,ac,aj;for(ao=0;ao<ar.length;ao++){if(ar[ao].data.length){ac=ar[ao].data[0];for(var aq=0;aq<ai.length;aq++){aj=ai[aq];if(aj.applies_to(ac)&&aj.min!==aj.max){at=true;break}}}}if(al.filters_available!==at){al.filters_available=at;if(!al.filters_available){al.filters_manager.hide()}al.update_icons()}}this.container_div.find(".yaxislabel").remove();var af=ar[0];if(af instanceof j){var ak=(this.prefs.histogram_max?this.prefs.histogram_max:af.max_val),ae=$("<div/>").text(ak).make_text_editable({num_cols:12,on_finish:function(av){$(".bs-tooltip").remove();var av=parseFloat(av);al.prefs.histogram_max=(!isNaN(av)?av:null);al.tile_cache.clear();al.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ae)}if(af instanceof M){var ap=true;for(ao=0;ao<ar.length;ao++){if(!ar[ao].all_slotted){ap=false;break}}if(!ap){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"}else{if(ac==="summary_tree"){ac="coverage histogram"}}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,y,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>G){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="summary_tree"||ag==="Coverage"){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(ao==="summary_tree"||ao==="Coverage"){var aA=new J.SummaryTreePainter(am,ay,ac,this.prefs);aA.draw(aq,ad.width,ad.height,aj);return new j(ap,af,ar,ad,am.data,am.max)}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 A(this.filters_manager.alpha_filter):null);var az=(this.filters_manager.height_filter?new A(this.filters_manager.height_filter):null);var aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae);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 M(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="summary_tree"}else{if(ac.extra_info==="no_detail"||ac.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="summary_tree"||ac.message||ac.extra_info==="no_detail"){return false}return true}});var Q=function(ad,ac,ae){d.call(this,ad,ac,ae);this.config=new D({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:O()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{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.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=J.ReadPainter};p(Q.prototype,q.prototype,K.prototype,d.prototype);var T=function(ae,ad,ag){d.call(this,ae,ad,ag);var af=O(),ac=O([af,"#ffffff"]);this.config=new D({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:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=J.ReadPainter;this.update_icons()};p(T.prototype,q.prototype,K.prototype,d.prototype);return{View:Z,DrawableGroup:N,LineTrack:i,FeatureTrack:d,DiagonalHeatmapTrack:s,ReadTrack:T,VcfTrack:Q,CompositeTrack:g}});
\ No newline at end of file
+define(["libs/underscore","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters"],function(ad,m,v,L){var r=ad.extend;var Q=m.get_random_color;var X=function(ae){return("isResolved" in ae)};var o={};var l=function(ae,af){o[ae.attr("id")]=af};var n=function(ae,ag,ai,ah){ai=".group";var af={};o[ae.attr("id")]=ah;ae.bind("drag",{handle:"."+ag,relative:true},function(aq,ar){var ap=$(this),av=$(this).parent(),am=av.children(),ao=o[$(this).attr("id")],al,ak,at,aj,an;ak=$(this).parents(ai);if(ak.length!==0){at=ak.position().top;aj=at+ak.outerHeight();if(ar.offsetY<at){$(this).insertBefore(ak);var au=o[ak.attr("id")];au.remove_drawable(ao);au.container.add_drawable_before(ao,au);return}else{if(ar.offsetY>aj){$(this).insertAfter(ak);var au=o[ak.attr("id")];au.remove_drawable(ao);au.container.add_drawable(ao);return}}}ak=null;for(an=0;an<am.length;an++){al=$(am.get(an));at=al.position().top;aj=at+al.outerHeight();if(al.is(ai)&&this!==al.get(0)&&ar.offsetY>=at&&ar.offsetY<=aj){if(ar.offsetY-at<aj-ar.offsetY){al.find(".content-div").prepend(this)}else{al.find(".content-div").append(this)}if(ao.container){ao.container.remove_drawable(ao)}o[al.attr("id")].add_drawable(ao);return}}for(an=0;an<am.length;an++){al=$(am.get(an));if(ar.offsetY<al.position().top&&!(al.hasClass("reference-track")||al.hasClass("intro"))){break}}if(an===am.length){if(this!==am.get(an-1)){av.append(this);o[av.attr("id")].move_drawable(ao,an)}}else{if(this!==am.get(an)){$(this).insertBefore(am.get(an));o[av.attr("id")].move_drawable(ao,(ar.deltaY>0?an-1:an))}}}).bind("dragstart",function(){af["border-top"]=ae.css("border-top");af["border-bottom"]=ae.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(af)})};exports.moveable=n;var ac=16,G=9,D=20,A=100,I=12000,T=400,K=5000,x=100,p="There was an error in indexing this dataset. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",w="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",y="Tool cannot be rerun: ",a="Loading data...",W="Ready for display",R=10,H=20;function Y(af,ae){if(!ae){ae=0}var ag=Math.pow(10,ae);return Math.round(af*ag)/ag}var s=function(af,ae,ah){if(!s.id_counter){s.id_counter=0}this.id=s.id_counter++;this.name=ah.name;this.view=af;this.container=ae;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:ah.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=ah.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(ai){ai.stopPropagation()});var ag=this;this.container_div.hover(function(){ag.icons_div.show()},function(){ag.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};s.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ae){if(ae.content_visible){ae.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ae.hide_contents();ae.content_visible=false}else{ae.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ae.content_visible=true;ae.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(af){var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(){af.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ae()}}};$(window).bind("keypress.check_enter_esc",ag);show_modal("Configure",af.config.build_form(),{Cancel:ah,OK:ae})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.remove()}}];r(s.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(){},to_dict:function(){},set_name:function(ae){this.old_name=this.name;this.name=ae;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 ae=this.view;this.container_div.hide(0,function(){$(this).remove();ae.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(af,ak,aj,ai,ae,ah){var ag=this;this.action_icons[af]=$("<a/>").attr("href","javascript:void(0);").attr("title",ak).addClass("icon-button").addClass(aj).tooltip().click(function(){ai(ag)}).appendTo(this.icons_div);if(ah){this.action_icons[af].hide()}},build_action_icons:function(ae){var ag;for(var af=0;af<ae.length;af++){ag=ae[af];this.add_action_icon(ag.name,ag.title,ag.css_class,ag.on_click_fn,ag.prepend,ag.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var z=function(af,ae,ag){s.call(this,af,ae,ag);this.obj_type=ag.obj_type;this.drawables=[]};r(z.prototype,s.prototype,{unpack_drawables:function(ag){this.drawables=[];var af;for(var ae=0;ae<ag.length;ae++){af=q(ag[ae],this.view,this);this.add_drawable(af)}},init:function(){for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae].init()}},_draw:function(){for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae]._draw()}},to_dict:function(){var af=[];for(var ae=0;ae<this.drawables.length;ae++){af.push(this.drawables[ae].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:af}},add_drawable:function(ae){this.drawables.push(ae);ae.container=this;this.changed()},add_drawable_before:function(ag,ae){this.changed();var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables.splice(af,0,ag);return true}return false},replace_drawable:function(ag,ae,af){var ah=this.drawables.indexOf(ag);if(ah!==-1){this.drawables[ah]=ae;if(af){ag.container_div.replaceWith(ae.container_div)}this.changed()}return ah},remove_drawable:function(af){var ae=this.drawables.indexOf(af);if(ae!==-1){this.drawables.splice(ae,1);af.container=null;this.changed();return true}return false},move_drawable:function(af,ag){var ae=this.drawables.indexOf(af);if(ae!==-1){this.drawables.splice(ae,1);this.drawables.splice(ag,0,af);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var P=function(af,ae,ah){r(ah,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});z.call(this,af,ae,ah);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);l(this.container_div,this);l(this.content_div,this);n(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new Z(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ah){this.unpack_drawables(ah.drawables)}if("filters" in ah){var ag=this.filters_manager;this.filters_manager=new Z(this,ah.filters);ag.parent_div.replaceWith(this.filters_manager.parent_div);if(ah.filters.visible){this.setup_multitrack_filtering()}}};r(P.prototype,s.prototype,z.prototype,{action_icons_def:[s.prototype.action_icons_def[0],s.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ae){if(ae.filters_manager.visible()){ae.filters_manager.clear_filters();ae._restore_filter_managers()}else{ae.setup_multitrack_filtering();ae.request_draw(true)}ae.filters_manager.toggle()}},s.prototype.action_icons_def[2]],build_container_div:function(){var ae=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ae)}return ae},build_header_div:function(){var ae=$("<div/>").addClass("track-header");ae.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ae);return ae},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ag=this.drawables.length;if(ag===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ag===1){if(this.drawables[0] instanceof h){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var an,am,ak,aq=true,ai=this.drawables[0].get_type(),ae=0;for(an=0;an<ag;an++){ak=this.drawables[an];if(ak.get_type()!==ai){can_composite=false;break}if(ak instanceof d){ae++}}if(aq||ae===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ae>1&&ae===this.drawables.length){var ar={},af;ak=this.drawables[0];for(am=0;am<ak.filters_manager.filters.length;am++){af=ak.filters_manager.filters[am];ar[af.name]=[af]}for(an=1;an<this.drawables.length;an++){ak=this.drawables[an];for(am=0;am<ak.filters_manager.filters.length;am++){af=ak.filters_manager.filters[am];if(af.name in ar){ar[af.name].push(af)}}}this.filters_manager.remove_all();var ah,aj,al,ao;for(var ap in ar){ah=ar[ap];if(ah.length===ae){aj=new U({name:ah[0].name,index:ah[0].index});this.filters_manager.add_filter(aj)}}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 ae=0;ae<this.drawables.length;ae++){this.drawables[ae].filters_manager=this.saved_filters_managers[ae]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ae=0;ae<this.drawables.length;ae++){drawable=this.drawables[ae];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ai=[];for(var af=0;af<this.drawables.length;af++){ai.push(this.drawables[af].name)}var ag="Composite Track of "+this.drawables.length+" tracks ("+ai.join(", ")+")";var ah=new h(this.view,this.view,{name:ag,drawables:this.drawables});var ae=this.container.replace_drawable(this,ah,true);ah.request_draw()},add_drawable:function(ae){z.prototype.add_drawable.call(this,ae);this.update_icons()},remove_drawable:function(ae){z.prototype.remove_drawable.call(this,ae);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ae=r(z.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ae},request_draw:function(ae,ag){for(var af=0;af<this.drawables.length;af++){this.drawables[af].request_draw(ae,ag)}}});var ab=function(ae){r(ae,{obj_type:"View"});z.call(this,"View",ae.container,ae);this.chrom=null;this.vis_id=ae.vis_id;this.dbkey=ae.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.init();this.canvas_manager=new CanvasManager(this.container.get(0).ownerDocument);this.reset()};ad.extend(ab.prototype,Backbone.Events);r(ab.prototype,z.prototype,{init:function(){this.requested_redraw=false;var ag=this.container,ae=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ag);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ag);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ag);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;l(this.viewport_container,ae);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ah=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){add_datasets(add_datasets_url,add_track_async_url,function(ai){ad.each(ai,function(aj){ae.add_drawable(q(aj,ae,ae))})})});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 af=function(ai){if(ai.type==="focusout"||(ai.keyCode||ai.which)===13||(ai.keyCode||ai.which)===27){if((ai.keyCode||ai.which)!==27){ae.go_to($(this).val())}$(this).hide();$(this).val("");ae.location_span.show();ae.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",af).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(){ae.location_span.hide();ae.chrom_select.hide();ae.nav_input.val(ae.chrom+":"+ae.low+"-"+ae.high);ae.nav_input.css("display","inline-block");ae.nav_input.select();ae.nav_input.focus();ae.nav_input.autocomplete({source:function(ak,ai){var al=[],aj=$.map(ae.get_drawables(),function(am){return am.data_manager.search_features(ak.term).success(function(an){al=al.concat(an)})});$.when.apply($,aj).done(function(){ai($.map(al,function(am){return{label:am[0],value:am[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(){ae.zoom_out();ae.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ae.zoom_in();ae.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ae.change_chrom(ae.chrom_select.val())});this.browser_content_div.click(function(ai){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ai){ae.zoom_in(ai.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ai,aj){this.current_x=aj.offsetX}).bind("drag",function(ai,ak){var al=ak.offsetX-this.current_x;this.current_x=ak.offsetX;var aj=Math.round(al/ae.viewport_container.width()*(ae.max_high-ae.max_low));ae.move_delta(-aj)});this.overview_close.click(function(){ae.reset_overview()});this.viewport_container.bind("draginit",function(ai,aj){if(ai.clientX>ae.viewport_container.width()-16){return false}}).bind("dragstart",function(ai,aj){aj.original_low=ae.low;aj.current_height=ai.clientY;aj.current_x=aj.offsetX}).bind("drag",function(ak,am){var ai=$(this);var an=am.offsetX-am.current_x;var aj=ai.scrollTop()-(ak.clientY-am.current_height);ai.scrollTop(aj);am.current_height=ak.clientY;am.current_x=am.offsetX;var al=Math.round(an/ae.viewport_container.width()*(ae.high-ae.low));ae.move_delta(al)}).bind("mousewheel",function(ak,am,aj,ai){if(aj){aj*=50;var al=Math.round(-aj/ae.viewport_container.width()*(ae.high-ae.low));ae.move_delta(al)}});this.top_labeltrack.bind("dragstart",function(ai,aj){return $("<div />").css({height:ae.browser_content_div.height()+ae.top_labeltrack.height()+ae.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(am,an){$(an.proxy).css({left:Math.min(am.pageX,an.startX)-ae.container.offset().left,width:Math.abs(am.pageX-an.startX)});var aj=Math.min(am.pageX,an.startX)-ae.container.offset().left,ai=Math.max(am.pageX,an.startX)-ae.container.offset().left,al=(ae.high-ae.low),ak=ae.viewport_container.width();ae.update_location(Math.round(aj/ak*al)+ae.low,Math.round(ai/ak*al)+ae.low)}).bind("dragend",function(an,ao){var aj=Math.min(an.pageX,ao.startX),ai=Math.max(an.pageX,ao.startX),al=(ae.high-ae.low),ak=ae.viewport_container.width(),am=ae.low;ae.low=Math.round(aj/ak*al)+am;ae.high=Math.round(ai/ak*al)+am;$(ao.proxy).remove();ae.request_redraw()});this.add_label_track(new aa(this,{content_div:this.top_labeltrack}));this.add_label_track(new aa(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ae.resize_window()},500)});$(document).bind("redraw",function(){ae.redraw()});this.reset();$(window).trigger("resize")},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(af,ah,ae,ai){if(this.timer){clearTimeout(this.timer)}if(ai){var ag=this;this.timer=setTimeout(function(){ag.trigger("navigate",af+":"+ah+"-"+ae)},500)}else{view.trigger("navigate",af+":"+ah+"-"+ae)}},update_location:function(ae,ag){this.location_span.text(commatize(ae)+" - "+commatize(ag));this.nav_input.val(this.chrom+":"+commatize(ae)+"-"+commatize(ag));var af=view.chrom_select.val();if(af!==""){this.trigger_navigate(af,view.low,view.high,true)}},load_chroms:function(ag){ag.num=x;var ae=this,af=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ag,dataType:"json",success:function(ai){if(ai.chrom_info.length===0){return}if(ai.reference){ae.add_label_track(new B(ae))}ae.chrom_data=ai.chrom_info;var al='<option value="">Select Chrom/Contig</option>';for(var ak=0,ah=ae.chrom_data.length;ak<ah;ak++){var aj=ae.chrom_data[ak].chrom;al+='<option value="'+aj+'">'+aj+"</option>"}if(ai.prev_chroms){al+='<option value="previous">Previous '+x+"</option>"}if(ai.next_chroms){al+='<option value="next">Next '+x+"</option>"}ae.chrom_select.html(al);ae.chrom_start_index=ai.start_index;af.resolve(ai)},error:function(){alert("Could not load chroms for this dbkey:",ae.dbkey)}});return af},change_chrom:function(aj,af,al){var ag=this;if(!ag.chrom_data){ag.load_chroms_deferred.then(function(){ag.change_chrom(aj,af,al)});return}if(!aj||aj==="None"){return}if(aj==="previous"){ag.load_chroms({low:this.chrom_start_index-x});return}if(aj==="next"){ag.load_chroms({low:this.chrom_start_index+x});return}var ak=$.grep(ag.chrom_data,function(am,an){return am.chrom===aj})[0];if(ak===undefined){ag.load_chroms({chrom:aj},function(){ag.change_chrom(aj,af,al)});return}else{if(aj!==ag.chrom){ag.chrom=aj;ag.chrom_select.val(ag.chrom);ag.max_high=ak.len-1;ag.reset();ag.request_redraw(true);for(var ai=0,ae=ag.drawables.length;ai<ae;ai++){var ah=ag.drawables[ai];if(ah.init){ah.init()}}if(ag.reference_track){ag.reference_track.init()}}if(af!==undefined&&al!==undefined){ag.low=Math.max(af,0);ag.high=Math.min(al,ag.max_high)}else{ag.low=0;ag.high=ag.max_high}ag.reset_overview();ag.request_redraw()}},go_to:function(ai){ai=ai.replace(/ |,/g,"");var am=this,ae,ah,af=ai.split(":"),ak=af[0],al=af[1];if(al!==undefined){try{var aj=al.split("-");ae=parseInt(aj[0],10);ah=parseInt(aj[1],10)}catch(ag){return false}}am.change_chrom(ak,ae,ah)},move_fraction:function(ag){var ae=this;var af=ae.high-ae.low;this.move_delta(ag*af)},move_delta:function(ah){var ae=this;var ag=ae.high-ae.low;if(ae.low-ah<ae.max_low){ae.low=ae.max_low;ae.high=ae.max_low+ag}else{if(ae.high-ah>ae.max_high){ae.high=ae.max_high;ae.low=ae.max_high-ag}else{ae.high-=ah;ae.low-=ah}}ae.request_redraw();var af=ae.chrom_select.val();this.trigger_navigate(af,ae.low,ae.high,true)},add_drawable:function(ae){z.prototype.add_drawable.call(this,ae);ae.init();this.changed();this.update_intro_div()},add_label_track:function(ae){ae.view=this;ae.init();this.label_tracks.push(ae)},remove_drawable:function(ag,af){z.prototype.remove_drawable.call(this,ag);if(af){var ae=this;ag.container_div.hide(0,function(){$(this).remove();ae.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(am,ae,al,an){var ak=this,aj=(an?[an]:ak.drawables),ag;var af;for(var ai=0;ai<aj.length;ai++){af=aj[ai];ag=-1;for(var ah=0;ah<ak.tracks_to_be_redrawn.length;ah++){if(ak.tracks_to_be_redrawn[ah][0]===af){ag=ah;break}}if(ag<0){ak.tracks_to_be_redrawn.push([af,ae,al])}else{ak.tracks_to_be_redrawn[ai][1]=ae;ak.tracks_to_be_redrawn[ai][2]=al}}if(!this.requested_redraw){requestAnimationFrame(function(){ak._redraw(am)});this.requested_redraw=true}},_redraw:function(ao){this.requested_redraw=false;var al=this.low,ah=this.high;if(al<this.max_low){al=this.max_low}if(ah>this.max_high){ah=this.max_high}var an=this.high-this.low;if(this.high!==0&&an<this.min_separation){ah=al+this.min_separation}this.low=Math.floor(al);this.high=Math.ceil(ah);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var ae=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ak=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ap=13;this.overview_box.css({left:ae,width:Math.max(ap,ak)}).show();if(ak<ap){this.overview_box.css("left",ae-(ap-ak)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ae,width:ak})}if(!ao){var ag,af,am;for(var ai=0,aj=this.tracks_to_be_redrawn.length;ai<aj;ai++){ag=this.tracks_to_be_redrawn[ai][0];af=this.tracks_to_be_redrawn[ai][1];am=this.tracks_to_be_redrawn[ai][2];if(ag){ag._draw(af,am)}}this.tracks_to_be_redrawn=[];for(ai=0,aj=this.label_tracks.length;ai<aj;ai++){this.label_tracks[ai]._draw()}}},zoom_in:function(af,ag){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ah=this.high-this.low,ai=ah/2+this.low,ae=(ah/this.zoom_factor)/2;if(af){ai=af/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ai-ae);this.high=Math.round(ai+ae);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var af=this.high-this.low,ag=af/2+this.low,ae=(af*this.zoom_factor)/2;this.low=Math.round(ag-ae);this.high=Math.round(ag+ae);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(ag){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ag.dataset_id){return}this.overview_viewport.find(".track").remove()}var af=ag.copy({content_div:this.overview_viewport}),ae=this;af.header_div.hide();af.is_overview=true;ae.overview_drawable=af;this.overview_drawable.postdraw_actions=function(){ae.overview_highlight.show().height(ae.overview_drawable.content_div.height());ae.overview_viewport.height(ae.overview_drawable.content_div.height()+ae.overview_box.outerHeight());ae.overview_close.show();ae.resize_window()};ae.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 t=function(ag,al,ah){this.track=ag;this.name=al.name;this.params=[];var at=al.params;for(var ai=0;ai<at.length;ai++){var an=at[ai],af=an.name,ar=an.label,aj=unescape(an.html),au=an.value,ap=an.type;if(ap==="number"){this.params.push(new f(af,ar,aj,(af in ah?ah[af]:au),an.min,an.max))}else{if(ap==="select"){this.params.push(new N(af,ar,aj,(af in ah?ah[af]:au)))}else{console.log("WARNING: unrecognized tool parameter type:",af,ap)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(aw){aw.stopPropagation()}).click(function(aw){aw.stopPropagation()}).bind("dblclick",function(aw){aw.stopPropagation()});var aq=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var ao=this.params;var am=this;$.each(this.params,function(ax,aA){var az=$("<div>").addClass("param-row").appendTo(am.parent_div);var aw=$("<div>").addClass("param-label").text(aA.label).appendTo(az);var ay=$("<div/>").addClass("param-input").html(aA.html).appendTo(az);ay.find(":input").val(aA.value);$("<div style='clear: both;'/>").appendTo(az)});this.parent_div.find("input").click(function(){$(this).select()});var av=$("<div>").addClass("param-row").appendTo(this.parent_div);var ak=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(av);var ae=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(av);ae.click(function(){am.run_on_region()});ak.click(function(){am.run_on_dataset()});if("visible" in ah&&ah.visible){this.parent_div.show()}};r(t.prototype,{update_params:function(){for(var ae=0;ae<this.params.length;ae++){this.params[ae].update_value()}},state_dict:function(){var af={};for(var ae=0;ae<this.params.length;ae++){af[this.params[ae].name]=this.params[ae].value}af.visible=this.parent_div.is(":visible");return af},get_param_values_dict:function(){var ae={};this.parent_div.find(":input").each(function(){var af=$(this).attr("name"),ag=$(this).val();ae[af]=ag});return ae},get_param_values:function(){var ae=[];this.parent_div.find(":input").each(function(){var af=$(this).attr("name"),ag=$(this).val();if(af){ae[ae.length]=ag}});return ae},run_on_dataset:function(){var ae=this;ae.run({target_dataset_id:this.track.original_dataset_id,tool_id:ae.name},null,function(af){show_modal(ae.name+" is Running",ae.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var af={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},aj=this.track,ag=af.tool_id+aj.tool_region_and_parameters_str(af.chrom,af.low,af.high),ae;if(aj.container===view){var ai=new P(view,view,{name:this.name});var ah=aj.container.replace_drawable(aj,ai,false);ai.container_div.insertBefore(aj.view.content_div.children()[ah]);ai.add_drawable(aj);aj.container_div.appendTo(ai.content_div);ae=ai}else{ae=aj.container}var ak=new aj.constructor(view,ae,{name:ag,hda_ldda:"hda"});ak.init_for_tool_data();ak.change_mode(aj.mode);ak.set_filters_manager(aj.filters_manager.copy(ak));ak.update_icons();ae.add_drawable(ak);ak.tiles_div.text("Starting job.");this.update_params();this.run(af,ak,function(al){ak.set_dataset(new Dataset(al));ak.tiles_div.text("Running job.");ak.init()})},run:function(ae,ag,ah){ae.inputs=this.get_param_values_dict();var af=new ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(ae),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ai){return ai!=="pending"}});$.when(af.go()).then(function(ai){if(ai==="no converter"){ag.container_div.addClass("error");ag.content_div.text(J)}else{if(ai.error){ag.container_div.addClass("error");ag.content_div.text(y+ai.message)}else{ah(ai)}}})}});var N=function(af,ae,ag,ah){this.name=af;this.label=ae;this.html=$(ag);this.value=ah};r(N.prototype,{update_value:function(){this.value=$(this.html).val()}});var f=function(ag,af,ai,aj,ah,ae){N.call(this,ag,af,ai,aj);this.min=ah;this.max=ae};r(f.prototype,N.prototype,{update_value:function(){N.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var g=function(ae){this.manager=null;this.name=ae.name;this.index=ae.index;this.tool_id=ae.tool_id;this.tool_exp_name=ae.tool_exp_name};r(g.prototype,{to_dict:function(){return{name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name}}});var c=function(ag,af,ae){return $("<a/>").attr("href","javascript:void(0);").attr("title",ag).addClass("icon-button").addClass(af).tooltip().click(ae)};var U=function(am){g.call(this,am);this.low=("low" in am?am.low:-Number.MAX_VALUE);this.high=("high" in am?am.high:Number.MAX_VALUE);this.min=("min" in am?am.min:Number.MAX_VALUE);this.max=("max" in am?am.max:-Number.MAX_VALUE);this.container=null;this.slider=null;this.slider_label=null;var ai=function(an,ao,ap){an.click(function(){var av=ao.text(),at=parseFloat(ap.slider("option","max")),ar=(at<=1?4:at<=1000000?at.toString().length:6),au=false,aq=$(this).parents(".slider-row");aq.addClass("input");if(ap.slider("option","values")){ar=2*ar+1;au=true}ao.text("");$("<input type='text'/>").attr("size",ar).attr("maxlength",ar).attr("value",av).appendTo(ao).focus().select().click(function(aw){aw.stopPropagation()}).blur(function(){$(this).remove();ao.text(av);aq.removeClass("input")}).keyup(function(aA){if(aA.keyCode===27){$(this).trigger("blur")}else{if(aA.keyCode===13){var ay=ap.slider("option","min"),aw=ap.slider("option","max"),az=function(aB){return(isNaN(aB)||aB>aw||aB<ay)},ax=$(this).val();if(!au){ax=parseFloat(ax);if(az(ax)){alert("Parameter value must be in the range ["+ay+"-"+aw+"]");return $(this)}}else{ax=ax.split("-");ax=[parseFloat(ax[0]),parseFloat(ax[1])];if(az(ax[0])||az(ax[1])){alert("Parameter value must be in the range ["+ay+"-"+aw+"]");return $(this)}}ap.slider((au?"values":"value"),ax);aq.removeClass("input")}}})})};var af=this;af.parent_div=$("<div/>").addClass("filter-row slider-row");var ae=$("<div/>").addClass("elt-label").appendTo(af.parent_div),ak=$("<span/>").addClass("slider-name").text(af.name+" ").appendTo(ae),ag=$("<span/>").text(this.low+"-"+this.high),ah=$("<span/>").addClass("slider-value").appendTo(ae).append("[").append(ag).append("]");af.values_span=ag;var aj=$("<div/>").addClass("slider").appendTo(af.parent_div);af.control_element=$("<div/>").attr("id",af.name+"-filter-control").appendTo(aj);af.control_element.slider({range:true,min:this.min,max:this.max,step:this.get_slider_step(this.min,this.max),values:[this.low,this.high],slide:function(an,ao){af.slide(an,ao)},change:function(an,ao){af.control_element.slider("option","slide").call(af.control_element,an,ao)}});af.slider=af.control_element;af.slider_label=ag;ai(ah,ag,af.control_element);var al=$("<div/>").addClass("display-controls").appendTo(af.parent_div);this.transparency_icon=c("Use filter for data transparency","layer-transparent",function(){if(af.manager.alpha_filter!==af){af.manager.alpha_filter=af;af.manager.parent_div.find(".layer-transparent").removeClass("active").hide();af.transparency_icon.addClass("active").show()}else{af.manager.alpha_filter=null;af.transparency_icon.removeClass("active")}af.manager.track.request_draw(true,true)}).appendTo(al).hide();this.height_icon=c("Use filter for data height","arrow-resize-090",function(){if(af.manager.height_filter!==af){af.manager.height_filter=af;af.manager.parent_div.find(".arrow-resize-090").removeClass("active").hide();af.height_icon.addClass("active").show()}else{af.manager.height_filter=null;af.height_icon.removeClass("active")}af.manager.track.request_draw(true,true)}).appendTo(al).hide();af.parent_div.hover(function(){af.transparency_icon.show();af.height_icon.show()},function(){if(af.manager.alpha_filter!==af){af.transparency_icon.hide()}if(af.manager.height_filter!==af){af.height_icon.hide()}});$("<div style='clear: both;'/>").appendTo(af.parent_div)};r(U.prototype,{to_dict:function(){var ae=g.prototype.to_dict.call(this);return r(ae,{type:"number",min:this.min,max:this.max,low:this.low,high:this.high})},copy:function(){return new U({name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name})},get_slider_step:function(ag,ae){var af=ae-ag;return(af<=2?0.01:1)},slide:function(ag,ah){var af=ah.values;this.values_span.text(af[0]+"-"+af[1]);this.low=af[0];this.high=af[1];var ae=this;setTimeout(function(){if(af[0]===ae.low&&af[1]===ae.high){ae.manager.track.request_draw(true,true)}},25)},applies_to:function(ae){if(ae.length>this.index){return true}return false},_keep_val:function(ae){return(isNaN(ae)||(ae>=this.low&&ae<=this.high))},keep:function(af){if(!this.applies_to(af)){return true}var ah=this;var ai=af[this.index];if(ai instanceof Array){var ag=true;for(var ae=0;ae<ai.length;ae++){if(!this._keep_val(ai[ae])){ag=false;break}}return ag}else{return this._keep_val(af[this.index])}},update_attrs:function(ah){var ae=false;if(!this.applies_to(ah)){return ae}var af=ah[this.index];if(!(af instanceof Array)){af=[af]}for(var ag=0;ag<af.length;ag++){var ai=af[ag];if(ai<this.min){this.min=Math.floor(ai);ae=true}if(ai>this.max){this.max=Math.ceil(ai);ae=true}}return ae},update_ui_elt:function(){if(this.min<this.max){this.parent_div.show()}else{this.parent_div.hide()}var af=this.slider.slider("option","min"),ae=this.slider.slider("option","max");if(this.min<af||this.max>ae){this.slider.slider("option","min",this.min);this.slider.slider("option","max",this.max);this.slider.slider("option","step",this.get_slider_step(this.min,this.max));this.slider.slider("option","values",[this.min,this.max])}}});var Z=function(ag,am){this.track=ag;this.alpha_filter=null;this.height_filter=null;this.filters=[];this.parent_div=$("<div/>").addClass("filters").hide();this.parent_div.bind("drag",function(ao){ao.stopPropagation()}).click(function(ao){ao.stopPropagation()}).bind("dblclick",function(ao){ao.stopPropagation()}).bind("keydown",function(ao){ao.stopPropagation()});if(am&&"filters" in am){var ae=("alpha_filter" in am?am.alpha_filter:null),ah=("height_filter" in am?am.height_filter:null),aj=am.filters,af;for(var ak=0;ak<aj.length;ak++){if(aj[ak].type==="number"){af=new U(aj[ak]);this.add_filter(af);if(af.name===ae){this.alpha_filter=af;af.transparency_icon.addClass("active").show()}if(af.name===ah){this.height_filter=af;af.height_icon.addClass("active").show()}}else{console.log("ERROR: unsupported filter: ",name,type)}}if("visible" in am&&am.visible){this.parent_div.show()}}if(this.filters.length!==0){var an=$("<div/>").addClass("param-row").appendTo(this.parent_div);var al=$("<input type='submit'/>").attr("value","Run on complete dataset").appendTo(an);var ai=this;al.click(function(){ai.run_on_dataset()})}};r(Z.prototype,{show:function(){this.parent_div.show()},hide:function(){this.parent_div.hide()},toggle:function(){this.parent_div.toggle()},visible:function(){return this.parent_div.is(":visible")},to_dict:function(){var ah={},ag=[],af;for(var ae=0;ae<this.filters.length;ae++){af=this.filters[ae];ag.push(af.to_dict())}ah.filters=ag;ah.alpha_filter=(this.alpha_filter?this.alpha_filter.name:null);ah.height_filter=(this.height_filter?this.height_filter.name:null);ah.visible=this.parent_div.is(":visible");return ah},copy:function(af){var ag=new Z(af);for(var ae=0;ae<this.filters.length;ae++){ag.add_filter(this.filters[ae].copy())}return ag},add_filter:function(ae){ae.manager=this;this.parent_div.append(ae.parent_div);this.filters.push(ae)},remove_all:function(){this.filters=[];this.parent_div.children().remove()},init_filters:function(){for(var ae=0;ae<this.filters.length;ae++){var af=this.filters[ae];af.update_ui_elt()}},clear_filters:function(){for(var ae=0;ae<this.filters.length;ae++){var af=this.filters[ae];af.slider.slider("option","values",[af.min,af.max])}this.alpha_filter=null;this.height_filter=null;this.parent_div.find(".icon-button").hide()},run_on_dataset:function(){var ak=function(ao,am,an){if(!(am in ao)){ao[am]=an}return ao[am]};var aj={},al,ae;for(var ai=0;ai<this.filters.length;ai++){al=this.filters[ai];if(al.tool_id){if(al.min!==al.low){ae=ak(aj,al.tool_id,[]);ae[ae.length]=al.tool_exp_name+" >= "+al.low}if(al.max!==al.high){ae=ak(aj,al.tool_id,[]);ae[ae.length]=al.tool_exp_name+" <= "+al.high}}}var af=[];for(var ah in aj){af[af.length]=[ah,aj[ah]]}(function ag(at,ap){var an=ap[0],ao=an[0],ar=an[1],aq="("+ar.join(") and (")+")",am={cond:aq,input:at,target_dataset_id:at,tool_id:ao},ap=ap.slice(1);$.getJSON(run_tool_url,am,function(au){if(au.error){show_modal("Filter Dataset","Error running tool "+ao,{Close:hide_modal})}else{if(ap.length===0){show_modal("Filtering Dataset","Filter(s) are running on the complete dataset. Outputs are in dataset's history.",{Close:hide_modal})}else{ag(au.dataset_id,ap)}}})})(this.track.dataset_id,af)}});var C=function(ae,af){L.Scaler.call(this,af);this.filter=ae};C.prototype.gen_val=function(ae){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(ae[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ae){this.track=ae.track;this.params=ae.params;this.values={};this.restore_values((ae.saved_values?ae.saved_values:{}));this.onchange=ae.onchange};r(F.prototype,{restore_values:function(ae){var af=this;$.each(this.params,function(ag,ah){if(ae[ah.key]!==undefined){af.values[ah.key]=ae[ah.key]}else{af.values[ah.key]=ah.default_value}})},build_form:function(){var ah=this;var ae=$("<div />");var ag;function af(am,ai){for(var aq=0;aq<am.length;aq++){ag=am[aq];if(ag.hidden){continue}var ak="param_"+aq;var av=ah.values[ag.key];var ax=$("<div class='form-row' />").appendTo(ai);ax.append($("<label />").attr("for",ak).text(ag.label+":"));if(ag.type==="bool"){ax.append($('<input type="checkbox" />').attr("id",ak).attr("name",ak).attr("checked",av))}else{if(ag.type==="text"){ax.append($('<input type="text"/>').attr("id",ak).val(av).click(function(){$(this).select()}))}else{if(ag.type==="select"){var at=$("<select />").attr("id",ak);for(var ao=0;ao<ag.options.length;ao++){$("<option/>").text(ag.options[ao].label).attr("value",ag.options[ao].value).appendTo(at)}at.val(av);ax.append(at)}else{if(ag.type==="color"){var aw=$("<div/>").appendTo(ax),ar=$("<input />").attr("id",ak).attr("name",ak).val(av).css("float","left").appendTo(aw).click(function(az){$(".bs-tooltip").removeClass("in");var ay=$(this).siblings(".bs-tooltip").addClass("in");ay.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(ay).height()/2)+($(this).height()/2)}).show();ay.click(function(aA){aA.stopPropagation()});$(document).bind("click.color-picker",function(){ay.hide();$(document).unbind("click.color-picker")});az.stopPropagation()}),ap=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(aw).attr("title","Set new random color").tooltip(),au=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(aw).hide(),al=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(au),aj=$("<div class='tooltip-arrow'></div>").appendTo(au),an=$.farbtastic(al,{width:100,height:100,callback:ar,color:av});aw.append($("<div/>").css("clear","both"));(function(ay){ap.click(function(){ay.setColor(Q())})})(an)}else{ax.append($("<input />").attr("id",ak).attr("name",ak).val(av))}}}}if(ag.help){ax.append($("<div class='help'/>").text(ag.help))}}}af(this.params,ae);return ae},update_from_form:function(ae){var ag=this;var af=false;$.each(this.params,function(ah,aj){if(!aj.hidden){var ak="param_"+ah;var ai=ae.find("#"+ak).val();if(aj.type==="float"){ai=parseFloat(ai)}else{if(aj.type==="int"){ai=parseInt(ai)}else{if(aj.type==="bool"){ai=ae.find("#"+ak).is(":checked")}}}if(ai!==ag.values[aj.key]){ag.values[aj.key]=ai;af=true}}});if(af){this.onchange();this.track.changed()}}});var b=function(ae,ai,ag,af,ah){this.track=ae;this.region=ai;this.low=ai.get("start");this.high=ai.get("end");this.resolution=ag;this.html_elt=$("<div class='track-tile'/>").append(af).height($(af).attr("height"));this.data=ah;this.stale=false};b.prototype.predisplay_actions=function(){};var k=function(ae,aj,ag,af,ah,ai){b.call(this,ae,aj,ag,af,ah);this.max_val=ai};r(k.prototype,b.prototype);var O=function(ah,ap,ai,ag,ak,ar,al,at,af,ao){b.call(this,ah,ap,ai,ag,ak);this.mode=al;this.all_slotted=af;this.feature_mapper=ao;this.has_icons=false;if(at){this.has_icons=true;var am=this;ag=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ag.width}).prependTo(this.html_elt);var an=new GenomeRegion({chrom:ah.view.chrom,start:this.low,end:this.high}),aq=ak.length,aj=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+aq+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ae=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+aq+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);aj.click(function(){am.stale=true;ah.data_manager.get_more_data(an,ah.mode,am.resolution,{},ah.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();ah.request_draw(true)}).dblclick(function(au){au.stopPropagation()});ae.click(function(){am.stale=true;ah.data_manager.get_more_data(an,ah.mode,am.resolution,{},ah.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();ah.request_draw(true)}).dblclick(function(au){au.stopPropagation()})}};r(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var af=this,ae={};if(af.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(aq){if(!this.hovered){return}var al=$(this).offset(),ap=aq.pageX-al.left,ao=aq.pageY-al.top,av=af.feature_mapper.get_feature_data(ap,ao),am=(av?av[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!am||$(this).attr("id")!==am.toString()){$(this).remove()}});if(av){var ah=ae[am];if(!ah){var am=av[0],ar={name:av[3],start:av[1],end:av[2],strand:av[4]},ak=af.track.filters_manager.filters,aj;for(var an=0;an<ak.length;an++){aj=ak[an];ar[aj.name]=av[aj.index]}var ah=$("<div/>").attr("id",am).addClass("feature-popup"),aw=$("<table/>"),au,at,ax;for(au in ar){at=ar[au];ax=$("<tr/>").appendTo(aw);$("<th/>").appendTo(ax).text(au);$("<td/>").attr("align","left").appendTo(ax).text(typeof(at)==="number"?Y(at,2):at)}ah.append($("<div class='feature-popup-inner'>").append(aw));ae[am]=ah}ah.appendTo($(this).parents(".track-content").children(".overlay"));var ai=ap+parseInt(af.html_elt.css("left"))-ah.width()/2,ag=ao+parseInt(af.html_elt.css("top"))+7;ah.css("left",ai+"px").css("top",ag+"px")}else{if(!aq.isPropagationStopped()){aq.stopPropagation();$(this).siblings().each(function(){$(this).trigger(aq)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var i=function(af,ae,ag){r(ag,{drag_handle_class:"draghandle"});s.call(this,af,ae,ag);this.dataset=new Dataset({id:ag.dataset_id,hda_ldda:ag.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ag?ag.data_query_wait:K);this.data_manager=("data_manager" in ag?ag.data_manager:new GenomeDataManager({dataset:this.dataset,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 ag)||ag.resize){this.add_resize_handle()}}};r(i.prototype,s.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},s.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ae){ae.view.set_overview(ae)}},s.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ae){if(ae.filters_manager.visible()){ae.filters_manager.clear_filters()}else{ae.filters_manager.init_filters()}ae.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ae){ae.dynamic_tool_div.toggle();if(ae.dynamic_tool_div.is(":visible")){ae.set_name(ae.name+ae.tool_region_and_parameters_str())}else{ae.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ae){var ah='<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>',ag=ad.template(ah,{track:ae});var aj=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},af=function(){var al=$('select[name="regions"] option:selected').val(),an,ak=new GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),am=ad.map($(".bookmark"),function(ao){return new GenomeRegion({from_str:$(ao).children(".position").text()})});if(al==="cur"){an=[ak]}else{if(al==="bookmarks"){an=am}else{an=[ak].concat(am)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ae.dataset_id,hda_ldda:ae.hda_ldda,regions:JSON.stringify(new Backbone.Collection(an).toJSON())})},ai=function(ak){if((ak.keyCode||ak.which)===27){aj()}else{if((ak.keyCode||ak.which)===13){af()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ag,{No:aj,Yes:af})}},s.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&s.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 ae=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ae)}this.name_div=$("<div/>").addClass("track-name").appendTo(ae).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ae},on_resize:function(){},add_resize_handle:function(){var ae=this;var ah=false;var ag=false;var af=$("<div class='track-resize'>");$(ae.container_div).hover(function(){if(ae.content_visible){ah=true;af.show()}},function(){ah=false;if(!ag){af.hide()}});af.hide().bind("dragstart",function(ai,aj){ag=true;aj.original_height=$(ae.content_div).height()}).bind("drag",function(aj,ak){var ai=Math.min(Math.max(ak.original_height+ak.deltaY,ae.min_height_px),ae.max_height_px);$(ae.tiles_div).css("height",ai);ae.visible_height_px=(ae.max_height_px===ai?0:ai);ae.on_resize()}).bind("dragend",function(ai,aj){ae.tile_cache.clear();ag=false;if(!ah){af.hide()}ae.config.values.height=ae.visible_height_px;ae.changed()}).appendTo(ae.container_div)},set_display_modes:function(ah,ak){this.display_modes=ah;this.mode=(ak?ak:(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 af=this,ai={};for(var ag=0,ae=af.display_modes.length;ag<ae;ag++){var aj=af.display_modes[ag];ai[aj]=function(al){return function(){af.change_mode(al);af.icons_div.show();af.container_div.mouseleave(function(){af.icons_div.hide()})}}(aj)}make_popupmenu(this.action_icons.mode_icon,ai)},build_action_icons:function(){s.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 aa){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof j){return"LineTrack"}else{if(this instanceof V){return"ReadTrack"}else{if(this instanceof S){return"VcfTrack"}else{if(this instanceof h){return"CompositeTrack"}else{if(this instanceof d){return"FeatureTrack"}}}}}}}return""},init:function(){var af=this;af.enabled=false;af.tile_cache.clear();af.data_manager.clear();af.content_div.css("height","auto");af.tiles_div.children().remove();af.container_div.removeClass("nodata error pending");if(!af.dataset_id){return}var ae=$.Deferred(),ag={hda_ldda:af.hda_ldda,data_type:this.dataset_check_type,chrom:af.view.chrom};$.getJSON(this.dataset.url(),ag,function(ah){if(!ah||ah==="error"||ah.kind==="error"){af.container_div.addClass("error");af.tiles_div.text(p);if(ah.message){var ai=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ah.message+"</pre>",{Close:hide_modal})});af.tiles_div.append(ai)}}else{if(ah==="no converter"){af.container_div.addClass("error");af.tiles_div.text(J)}else{if(ah==="no data"||(ah.data!==undefined&&(ah.data===null||ah.data.length===0))){af.container_div.addClass("nodata");af.tiles_div.text(E)}else{if(ah==="pending"){af.container_div.addClass("pending");af.tiles_div.html(w);setTimeout(function(){af.init()},af.data_query_wait)}else{if(ah==="data"||ah.status==="data"){if(ah.valid_chroms){af.valid_chroms=ah.valid_chroms;af.update_icons()}af.tiles_div.text(W);if(af.view.chrom){af.tiles_div.text("");af.tiles_div.css("height",af.visible_height_px+"px");af.enabled=true;$.when(af.predraw_init()).done(function(){ae.resolve();af.container_div.removeClass("nodata error pending");af.request_draw()})}else{ae.resolve()}}}}}}});this.update_icons();return ae},predraw_init:function(){},get_drawables:function(){return this}});var M=function(ag,af,ah){i.call(this,ag,af,ah);var ae=this;n(ae.container_div,ae.drag_handle_class,".group",ae);this.filters_manager=new Z(this,("filters" in ah?ah.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in ah&&ah.tool?new t(this,ah.tool,ah.tool_state):null);this.tile_cache=new Cache(R);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(ah.mode){this.change_mode(ah.mode)}};r(M.prototype,s.prototype,i.prototype,{action_icons_def:i.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(ae){$(".bs-tooltip").remove();ae.slotters[ae.view.resolution_px_b].max_rows*=2;ae.request_draw(true)},hide:true}]),copy:function(ae){var af=this.to_dict();r(af,{data_manager:this.data_manager});var ag=new this.constructor(this.view,ae,af);ag.change_mode(this.mode);ag.enabled=this.enabled;return ag},set_filters_manager:function(ae){this.filters_manager=ae;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(af){var ae=this;ae.mode=af;ae.config.values.mode=af;ae.tile_cache.clear();ae.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+ae.mode+")");return ae},update_icons:function(){var ae=this;if(ae.filters_available){ae.action_icons.filters_icon.show()}else{ae.action_icons.filters_icon.hide()}if(ae.tool){ae.action_icons.tools_icon.show();ae.action_icons.param_space_viz_icon.show()}else{ae.action_icons.tools_icon.hide();ae.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(af,ag,ae){return af+"_"+ag+"_"+ae},request_draw:function(af,ae){this.view.request_redraw(false,af,ae,this)},before_draw:function(){},_draw:function(af,ap){if(!this.can_draw()){return}var an=this.view.low,aj=this.view.high,al=aj-an,ag=this.view.container.width(),ar=this.view.resolution_px_b,ai=this.view.resolution_b_px;if(this.is_overview){an=this.view.max_low;aj=this.view.max_high;ai=(view.max_high-view.max_low)/ag;ar=1/ai}this.before_draw();this.tiles_div.children().addClass("remove");var ae=Math.floor(an/(ai*T)),am=true,aq=[],ak=function(at){return(at&&"track" in at)};while((ae*T*ai)<aj){var ao=this.draw_helper(af,ag,ae,ai,this.tiles_div,ar);if(ak(ao)){aq.push(ao)}else{am=false}ae+=1}if(!ap){this.tiles_div.children(".remove").removeClass("remove").remove()}var ah=this;if(am){this.tiles_div.children(".remove").remove();ah.postdraw_actions(aq,ag,ar,ap)}},postdraw_actions:function(ag,ah,aj,ae){var ai=false;for(var af=0;af<ag.length;af++){if(ag[af].has_icons){ai=true;break}}if(ai){for(var af=0;af<ag.length;af++){tile=ag[af];if(!tile.has_icons){tile.html_elt.css("padding-top",D)}}}},draw_helper:function(ae,aq,aw,au,aj,ak,ar){var ap=this,az=this._gen_tile_cache_key(aq,ak,aw),ah=this._get_tile_bounds(aw,au);if(!ar){ar={}}var ay=(ae?undefined:ap.tile_cache.get_elt(az));if(ay){ap.show_tile(ay,aj,ak);return ay}var an=true;var av=ap.data_manager.get_data(ah,ap.mode,au,ap.data_url_extra_params);if(X(av)){an=false}var al;if(view.reference_track&&ak>view.canvas_manager.char_width_px){al=view.reference_track.data_manager.get_data(ah,ap.mode,au,view.reference_track.data_url_extra_params);if(X(al)){an=false}}if(an){r(av,ar.more_tile_data);var am=ap.mode;if(am==="Auto"){am=ap.get_mode(av);ap.update_auto_mode(am)}var ag=ap.view.canvas_manager.new_canvas(),ax=ah.get("start"),af=ah.get("end"),aq=Math.ceil((af-ax)*ak)+ap.left_offset,ao=ap.get_canvas_height(av,am,ak,aq);ag.width=aq;ag.height=ao;var at=ag.getContext("2d");at.translate(this.left_offset,0);var ay=ap.draw_tile(av,at,am,au,ah,ak,al);if(ay!==undefined){ap.tile_cache.set_elt(az,ay);ap.show_tile(ay,aj,ak)}return ay}var ai=$.Deferred();$.when(av,al).then(function(){view.request_redraw(false,false,false,ap);ai.resolve()});return ai},get_canvas_height:function(ae,ag,ah,af){return this.visible_height_px},draw_tile:function(ae,af,aj,ah,ai,ak,ag){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ag,ai,aj){var af=this,ae=ag.html_elt;ag.predisplay_actions();var ah=(ag.low-(this.is_overview?this.view.max_low:this.view.low))*aj;if(this.left_offset){ah-=this.left_offset}ae.css({position:"absolute",top:0,left:ah});if(ae.hasClass("remove")){ae.removeClass("remove")}else{ai.append(ae)}af.after_show_tile(ag)},after_show_tile:function(ae){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(ae,af){var ah=Math.floor(ae*T*af),ai=Math.ceil(T*af),ag=(ah+ai<=this.view.max_high?ah+ai:this.view.max_high);return new GenomeRegion({chrom:this.view.chrom,start:ah,end:ag})},tool_region_and_parameters_str:function(ag,ae,ah){var af=this,ai=(ag!==undefined&&ae!==undefined&&ah!==undefined?ag+":"+ae+"-"+ah:"all");return" - region=["+ai+"], parameters=["+af.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ae,af){return true},can_subset:function(ae){return false},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(ag,ah,aj,ae){var af=this;af.normal_postdraw_actions(ag,ah,aj,ae);af.dataset_check_type="converted_datasets_state";af.data_query_wait=K;var ai=new ServerStateDeferred({url:af.dataset_state_url,url_params:{dataset_id:af.dataset_id,hda_ldda:af.hda_ldda},interval:af.data_query_wait,success_fn:function(ak){return ak!=="pending"}});$.when(ai.go()).then(function(){af.data_manager.set("data_type","data")});af.postdraw_actions=af.normal_postdraw_actions}}});var aa=function(af,ae){var ag={resize:false};i.call(this,af,ae,ag);this.container_div.addClass("label-track")};r(aa.prototype,i.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ag=this.view,ah=ag.high-ag.low,ak=Math.floor(Math.pow(10,Math.floor(Math.log(ah)/Math.log(10)))),ae=Math.floor(ag.low/ak)*ak,ai=this.view.container.width(),af=$("<div style='position: relative; height: 1.3em;'></div>");while(ae<ag.high){var aj=(ae-ag.low)/ah*ai;af.append($("<div class='label'>"+commatize(ae)+"</div>").css({position:"absolute",left:aj-1}));ae+=ak}this.content_div.children(":first").remove();this.content_div.append(af)}});var h=function(af,ae,ai){M.call(this,af,ae,ai);this.drawables=[];this.left_offset=0;if("drawables" in ai){var ah;for(var ag=0;ag<ai.drawables.length;ag++){ah=ai.drawables[ag];this.drawables[ag]=q(ah,af,null);if(ah.left_offset>this.left_offset){this.left_offset=ah.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};r(h.prototype,M.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ae){$(".bs-tooltip").remove();ae.show_group()}}].concat(M.prototype.action_icons_def),to_dict:z.prototype.to_dict,add_drawable:z.prototype.add_drawable,unpack_drawables:z.prototype.unpack_drawables,change_mode:function(ae){M.prototype.change_mode.call(this,ae);for(var af=0;af<this.drawables.length;af++){this.drawables[af].change_mode(ae)}},init:function(){var ag=[];for(var af=0;af<this.drawables.length;af++){ag.push(this.drawables[af].init())}var ae=this;$.when.apply($,ag).then(function(){ae.enabled=true;ae.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:s.prototype.can_draw,draw_helper:function(af,av,aB,ay,am,ao,aw){var au=this,aF=this._gen_tile_cache_key(av,ao,aB),aj=this._get_tile_bounds(aB,ay);if(!aw){aw={}}var aE=(af?undefined:au.tile_cache.get_elt(aF));if(aE){au.show_tile(aE,am,ao);return aE}var an=[],au,ar=true,az,ap;for(var aA=0;aA<this.drawables.length;aA++){au=this.drawables[aA];az=au.data_manager.get_data(aj,au.mode,ay,au.data_url_extra_params);if(X(az)){ar=false}an.push(az);ap=null;if(view.reference_track&&ao>view.canvas_manager.char_width_px){ap=view.reference_track.data_manager.get_data(aj,au.mode,ay,view.reference_track.data_url_extra_params);if(X(ap)){ar=false}}an.push(ap)}if(ar){r(az,aw.more_tile_data);this.tile_predraw_init();var ai=au.view.canvas_manager.new_canvas(),ak=au._get_tile_bounds(aB,ay),aC=aj.get("start"),ag=aj.get("end"),aD=0,av=Math.ceil((ag-aC)*ao)+this.left_offset,at=0,ah=[],aA;var ae=0;for(aA=0;aA<this.drawables.length;aA++,aD+=2){au=this.drawables[aA];az=an[aD];var aq=au.mode;if(aq==="Auto"){aq=au.get_mode(az);au.update_auto_mode(aq)}ah.push(aq);ae=au.get_canvas_height(az,aq,ao,av);if(ae>at){at=ae}}ai.width=av;ai.height=(aw.height?aw.height:at);aD=0;var ax=ai.getContext("2d");ax.translate(this.left_offset,0);ax.globalAlpha=0.5;ax.globalCompositeOperation="source-over";for(aA=0;aA<this.drawables.length;aA++,aD+=2){au=this.drawables[aA];az=an[aD];ap=an[aD+1];aE=au.draw_tile(az,ax,ah[aA],ay,aj,ao,ap)}this.tile_cache.set_elt(aF,aE);this.show_tile(aE,am,ao);return aE}var al=$.Deferred(),au=this;$.when.apply($,an).then(function(){view.request_redraw(false,false,false,au);al.resolve()});return al},show_group:function(){var ah=new P(this.view,this.container,{name:this.name}),ae;for(var ag=0;ag<this.drawables.length;ag++){ae=this.drawables[ag];ae.update_icons();ah.add_drawable(ae);ae.container=ah;ah.content_div.append(ae.container_div)}var af=this.container.replace_drawable(this,ah,true);ah.request_draw()},tile_predraw_init:function(){var ah=Number.MAX_VALUE,ae=-ah,af;for(var ag=0;ag<this.drawables.length;ag++){af=this.drawables[ag];if(af instanceof j){if(af.prefs.min_value<ah){ah=af.prefs.min_value}if(af.prefs.max_value>ae){ae=af.prefs.max_value}}}for(var ag=0;ag<this.drawables.length;ag++){af=this.drawables[ag];af.prefs.min_value=ah;af.prefs.max_value=ae}},postdraw_actions:function(ag,aj,al,af){M.prototype.postdraw_actions.call(this,ag,aj,al,af);var ai=-1;for(var ah=0;ah<ag.length;ah++){var ae=ag[ah].html_elt.find("canvas").height();if(ae>ai){ai=ae}}for(var ah=0;ah<ag.length;ah++){var ak=ag[ah];if(ak.html_elt.find("canvas").height()!==ai){this.draw_helper(true,aj,ak.index,ak.resolution,ak.html_elt.parent(),al,{height:ai});ak.html_elt.remove()}}}});var B=function(ae){M.call(this,ae,{content_div:ae.top_labeltrack},{resize:false});ae.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=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};r(B.prototype,s.prototype,M.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:s.prototype.can_draw,draw_helper:function(ai,ag,ae,af,aj,ak,ah){if(ak>this.view.canvas_manager.char_width_px){return M.prototype.draw_helper.call(this,ai,ag,ae,af,aj,ak,ah)}else{this.hide_contents();return null}},draw_tile:function(am,an,ai,ah,ak,ao){var ag=this;if(ao>this.view.canvas_manager.char_width_px){if(am.data===null){this.hide_contents();return}var af=an.canvas;an.font=an.canvas.manager.default_font;an.textAlign="center";am=am.data;for(var aj=0,al=am.length;aj<al;aj++){var ae=Math.floor(aj*ao);an.fillText(am[aj],ae,10)}this.show_contents();return new b(ag,ak,ah,af,am)}this.hide_contents()}});var j=function(ag,af,ah){var ae=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";M.call(this,ag,af,ah);this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;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:Q()},{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:ah.prefs,onchange:function(){ae.set_name(ae.prefs.name);ae.vertical_range=ae.prefs.max_value-ae.prefs.min_value;ae.set_min_value(ae.prefs.min_value);ae.set_max_value(ae.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};r(j.prototype,s.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ae){this.prefs.min_value=ae;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ae){this.prefs.max_value=ae;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ae=this;ae.vertical_range=undefined;return $.getJSON(ae.dataset.url(),{data_type:"data",stats:true,chrom:ae.view.chrom,low:0,high:ae.view.max_high,hda_ldda:ae.hda_ldda,dataset_id:ae.dataset_id},function(af){ae.container_div.addClass("line-track");var ai=af.data;if(isNaN(parseFloat(ae.prefs.min_value))||isNaN(parseFloat(ae.prefs.max_value))){var ag=ai.min,ak=ai.max;ag=Math.floor(Math.min(0,Math.max(ag,ai.mean-2*ai.sd)));ak=Math.ceil(Math.max(0,Math.min(ak,ai.mean+2*ai.sd)));ae.prefs.min_value=ag;ae.prefs.max_value=ak;$("#track_"+ae.dataset_id+"_minval").val(ae.prefs.min_value);$("#track_"+ae.dataset_id+"_maxval").val(ae.prefs.max_value)}ae.vertical_range=ae.prefs.max_value-ae.prefs.min_value;ae.total_frequency=ai.total_frequency;ae.container_div.find(".yaxislabel").remove();var aj=$("<div/>").text(Y(ae.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(al){$(".bs-tooltip").remove();var al=parseFloat(al);if(!isNaN(al)){ae.set_min_value(al)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ae.dataset_id+"_minval").prependTo(ae.container_div),ah=$("<div/>").text(Y(ae.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(al){$(".bs-tooltip").remove();var al=parseFloat(al);if(!isNaN(al)){ae.set_max_value(al)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ae.dataset_id+"_maxval").prependTo(ae.container_div)})},draw_tile:function(an,al,ag,af,ai,am){var ae=al.canvas,ah=ai.get("start"),ak=ai.get("end"),aj=new L.LinePainter(an.data,ah,ak,this.prefs,ag);aj.draw(al,ae.width,ae.height,am);return new b(this,ai,af,ae,an.data)},can_subset:function(ae){return false}});var u=function(ag,af,ah){var ae=this;this.display_modes=["Heatmap"];this.mode="Heatmap";M.call(this,ag,af,ah);this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;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:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{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:ah.prefs,onchange:function(){ae.set_name(ae.prefs.name);ae.vertical_range=ae.prefs.max_value-ae.prefs.min_value;ae.set_min_value(ae.prefs.min_value);ae.set_max_value(ae.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};r(u.prototype,s.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ae){this.prefs.min_value=ae;this.tile_cache.clear();this.request_draw()},set_max_value:function(ae){this.prefs.max_value=ae;this.tile_cache.clear();this.request_draw()},draw_tile:function(ao,am,aj,ah,af,an){var ag=am.canvas,ae=this._get_tile_bounds(af,ah),ai=ae[0],al=ae[1],ak=new L.DiagonalHeatmapPainter(ao.data,ai,al,this.prefs,aj);ak.draw(am,ag.width,ag.height,an);return new b(this,af,ah,ag,ao.data)}});var d=function(ah,ag,aj){var af=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];M.call(this,ah,ag,aj);var ai=Q(),ae=Q([ai,"#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:ai},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ae},{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:"histogram_max",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:aj.prefs,onchange:function(){af.set_name(af.prefs.name);af.tile_cache.clear();af.set_painter_from_config();af.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=aj.hda_ldda;this.dataset_id=aj.dataset_id;this.original_dataset_id=aj.dataset_id;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()};r(d.prototype,s.prototype,M.prototype,{set_dataset:function(ae){this.dataset_id=ae.get("id");this.hda_ldda=ae.get("hda_ldda");this.dataset=ae;this.data_manager.set("dataset",ae)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(au,ao,aj,ai){M.prototype.postdraw_actions.call(this,au,ai);var an=this,aq;if(an.mode==="Coverage"){var af=-1;for(aq=0;aq<au.length;aq++){var ap=au[aq].max_val;if(ap>af){af=ap}}for(aq=0;aq<au.length;aq++){var aw=au[aq];if(aw.max_val!==af){aw.html_elt.remove();an.draw_helper(true,ao,aw.index,aw.resolution,aw.html_elt.parent(),aj,{more_tile_data:{max:af}})}}}if(an.filters_manager){var ak=an.filters_manager.filters;for(var at=0;at<ak.length;at++){ak[at].update_ui_elt()}var av=false,ae,al;for(aq=0;aq<au.length;aq++){if(au[aq].data.length){ae=au[aq].data[0];for(var at=0;at<ak.length;at++){al=ak[at];if(al.applies_to(ae)&&al.min!==al.max){av=true;break}}}}if(an.filters_available!==av){an.filters_available=av;if(!an.filters_available){an.filters_manager.hide()}an.update_icons()}}this.container_div.find(".yaxislabel").remove();var ah=au[0];if(ah instanceof k){var am=(this.prefs.histogram_max?this.prefs.histogram_max:ah.max_val),ag=$("<div/>").text(am).make_text_editable({num_cols:12,on_finish:function(ax){$(".bs-tooltip").remove();var ax=parseFloat(ax);an.prefs.histogram_max=(!isNaN(ax)?ax:null);an.tile_cache.clear();an.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ag)}if(ah instanceof O){var ar=true;for(aq=0;aq<au.length;aq++){if(!au[aq].all_slotted){ar=false;break}}if(!ar){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(ae){var ae;if(this.mode==="Auto"){if(ae==="no_detail"){ae="feature spans"}else{if(ae==="summary_tree"){ae="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ae+")")}},incremental_slots:function(ai,ae,ah){var af=this.view.canvas_manager.dummy_context,ag=this.slotters[ai];if(!ag||(ag.mode!==ah)){ag=new (v.FeatureSlotter)(ai,ah,A,function(aj){return af.measureText(aj)});this.slotters[ai]=ag}return ag.slot_features(ae)},get_mode:function(ae){if(ae.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ae.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(ae,ai,aj,af){if(ai==="summary_tree"||ai==="Coverage"){return this.summary_draw_height}else{var ah=this.incremental_slots(aj,ae.data,ai);var ag=new (this.painter)(null,null,null,this.prefs,ai);return Math.max(ac,ag.get_required_height(ah,af))}},draw_tile:function(ao,at,aq,au,ah,al,ag){var ar=this,af=at.canvas,aA=ah.get("start"),ae=ah.get("end"),ai=this.left_offset;if(aq==="summary_tree"||aq==="Coverage"){var aC=new L.SummaryTreePainter(ao,aA,ae,this.prefs);aC.draw(at,af.width,af.height,al);return new k(ar,ah,au,af,ao.data,ao.max)}var ak=[],ap=this.slotters[al].slots;all_slotted=true;if(ao.data){var am=this.filters_manager.filters;for(var av=0,ax=ao.data.length;av<ax;av++){var aj=ao.data[av];var aw=false;var an;for(var az=0,aE=am.length;az<aE;az++){an=am[az];an.update_attrs(aj);if(!an.keep(aj)){aw=true;break}}if(!aw){ak.push(aj);if(!(aj[0] in ap)){all_slotted=false}}}}var aD=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null);var aB=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null);var aC=new (this.painter)(ak,aA,ae,this.prefs,aq,aD,aB,ag);var ay=null;at.fillStyle=this.prefs.block_color;at.font=at.canvas.manager.default_font;at.textAlign="right";if(ao.data){ay=aC.draw(at,af.width,af.height,al,ap);ay.translation=-ai}return new O(ar,ah,au,af,ao.data,al,aq,ao.message,all_slotted,ay)},data_and_mode_compatible:function(ae,af){if(af==="Auto"){return true}else{if(af==="Coverage"){return ae.dataset_type==="summary_tree"}else{if(ae.extra_info==="no_detail"||ae.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ae){if(ae.dataset_type==="summary_tree"||ae.message||ae.extra_info==="no_detail"){return false}return true}});var S=function(af,ae,ag){d.call(this,af,ae,ag);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:Q()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter};r(S.prototype,s.prototype,M.prototype,d.prototype);var V=function(ag,af,ai){d.call(this,ag,af,ai);var ah=Q(),ae=Q([ah,"#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:ah},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ae},{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:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ai.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter;this.update_icons()};r(V.prototype,s.prototype,M.prototype,d.prototype);var e={LineTrack:j,FeatureTrack:d,VcfTrack:S,ReadTrack:V,CompositeTrack:h,DrawableGroup:P};var q=function(ag,af,ae){if("copy" in ag){return ag.copy(ae)}else{var ah=ag.obj_type;if(!ah){ah=ag.track_type}return new e[ah](af,ae,ag)}};return{View:ab,DrawableGroup:P,LineTrack:j,FeatureTrack:d,DiagonalHeatmapTrack:u,ReadTrack:V,VcfTrack:S,CompositeTrack:h,object_from_template:q}});
\ No newline at end of file
diff -r 0e17b12c190312b7836d69d7852afbed15e81bb9 -r bba6f86ff735d9cc8e09c56383eeef84b2ac0303 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(["libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks"],function(h,f,b,e){var d=function(n,l,j){var p=$("#bookmarks-container"),r=$("<div/>").addClass("bookmark").appendTo(p);var s=$("<div/>").addClass("position").appendTo(r),o=$("<a href=''/>").text(n).appendTo(s).click(function(){view.go_to(n);return false}),m=$("<div/>").text(l).appendTo(r);if(j){var q=$("<div/>").addClass("delete-icon-container").prependTo(r).click(function(){r.slideUp("fast");r.remove();view.has_changes=true;return false}),k=$("<a href=''/>").addClass("icon-button delete").appendTo(q);m.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return r};var c={LineTrack:e.LineTrack,FeatureTrack:e.FeatureTrack,VcfTrack:e.VcfTrack,ReadTrack:e.ReadTrack,CompositeTrack:e.CompositeTrack,DrawableGroup:e.DrawableGroup};var i=function(l,k,j){if("copy" in l){return l.copy(j)}else{var m=l.obj_type;if(!m){m=l.track_type}return new c[m](k,j,l)}};var g=function(m,j,l,n,k){view=new e.View(m);view.editor=true;$.when(view.load_chroms_deferred).then(function(){if(j){var w=j.chrom,o=j.start,t=j.end,q=j.overview;if(w&&(o!==undefined)&&t){view.change_chrom(w,o,t)}}if(l){var r,p,s;for(var u=0;u<l.length;u++){view.add_drawable(i(l[u],view,view))}}view.update_intro_div();var x;for(var u=0;u<view.drawables.length;u++){if(view.drawables[u].name===q){view.set_overview(view.drawables[u]);break}}if(n){var v;for(var u=0;u<n.length;u++){v=n[u];d(v.position,v.annotation,k)}}view.has_changes=false});return view};var a=function(j){$(document).keydown(function(k){if($(k.srcElement).is(":input")){return}switch(k.which){case 37:j.move_fraction(0.25);break;case 38:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()-20);break;case 39:j.move_fraction(-0.25);break;case 40:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()+20);break}})};return{add_bookmark:d,object_from_template:i,create_visualization:g,init_keyboard_nav:a}});
\ No newline at end of file
+define(["libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks"],function(d,h,g,c){var a=c.object_from_template;var f=function(m,k,i){var o=$("#bookmarks-container"),q=$("<div/>").addClass("bookmark").appendTo(o);var r=$("<div/>").addClass("position").appendTo(q),n=$("<a href=''/>").text(m).appendTo(r).click(function(){view.go_to(m);return false}),l=$("<div/>").text(k).appendTo(q);if(i){var p=$("<div/>").addClass("delete-icon-container").prependTo(q).click(function(){q.slideUp("fast");q.remove();view.has_changes=true;return false}),j=$("<a href=''/>").addClass("icon-button delete").appendTo(p);l.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return q};var b=function(l,i,k,m,j){view=new c.View(l);view.editor=true;$.when(view.load_chroms_deferred).then(function(){if(i){var v=i.chrom,n=i.start,s=i.end,p=i.overview;if(v&&(n!==undefined)&&s){view.change_chrom(v,n,s)}}if(k){var q,o,r;for(var t=0;t<k.length;t++){view.add_drawable(a(k[t],view,view))}}view.update_intro_div();var w;for(var t=0;t<view.drawables.length;t++){if(view.drawables[t].name===p){view.set_overview(view.drawables[t]);break}}if(m){var u;for(var t=0;t<m.length;t++){u=m[t];f(u.position,u.annotation,j)}}view.has_changes=false});return view};var e=function(i){$(document).keydown(function(j){if($(j.srcElement).is(":input")){return}switch(j.which){case 37:i.move_fraction(0.25);break;case 38:var k=Math.round(i.viewport_container.height()/15);i.viewport_container.scrollTop(i.viewport_container.scrollTop()-20);break;case 39:i.move_fraction(-0.25);break;case 40:var k=Math.round(i.viewport_container.height()/15);i.viewport_container.scrollTop(i.viewport_container.scrollTop()+20);break}})};return{add_bookmark:f,object_from_template:a,create_visualization:b,init_keyboard_nav:e}});
\ No newline at end of file
diff -r 0e17b12c190312b7836d69d7852afbed15e81bb9 -r bba6f86ff735d9cc8e09c56383eeef84b2ac0303 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -4764,6 +4764,40 @@
};
extend(ReadTrack.prototype, Drawable.prototype, TiledTrack.prototype, FeatureTrack.prototype);
+/**
+ * Objects that can be added to a view.
+ */
+var addable_objects = {
+ "LineTrack": LineTrack,
+ "FeatureTrack": FeatureTrack,
+ "VcfTrack": VcfTrack,
+ "ReadTrack": ReadTrack,
+ // "DiagonalHeatmapTrack": DiagonalHeatmapTrack,
+ "CompositeTrack": CompositeTrack,
+ "DrawableGroup": DrawableGroup
+};
+
+/**
+ * Create new object from a template. A template can be either an object dictionary or an
+ * object itself.
+ */
+var object_from_template = function(template, view, container) {
+ if ('copy' in template) {
+ // Template is an object.
+ return template.copy(container);
+ }
+ else {
+ // Template is a dictionary.
+ var
+ drawable_type = template['obj_type'];
+ // For backward compatibility:
+ if (!drawable_type) {
+ drawable_type = template['track_type'];
+ }
+ return new addable_objects[ drawable_type ](view, container, template);
+ }
+};
+
// Exports
return {
View: View,
@@ -4773,7 +4807,8 @@
DiagonalHeatmapTrack: DiagonalHeatmapTrack,
ReadTrack: ReadTrack,
VcfTrack: VcfTrack,
- CompositeTrack: CompositeTrack
+ CompositeTrack: CompositeTrack,
+ object_from_template: object_from_template
};
// End trackster_module encapsulation
diff -r 0e17b12c190312b7836d69d7852afbed15e81bb9 -r bba6f86ff735d9cc8e09c56383eeef84b2ac0303 static/scripts/viz/trackster_ui.js
--- a/static/scripts/viz/trackster_ui.js
+++ b/static/scripts/viz/trackster_ui.js
@@ -4,6 +4,8 @@
* Functions used for creating and managing the Trackster user interface.
************************************************************************/
+var object_from_template = tracks.object_from_template;
+
/**
* Add bookmark.
*/
@@ -41,39 +43,6 @@
};
/**
- * Objects that can be added to a view.
- */
-var addable_objects = {
- "LineTrack": tracks.LineTrack,
- "FeatureTrack": tracks.FeatureTrack,
- "VcfTrack": tracks.VcfTrack,
- "ReadTrack": tracks.ReadTrack,
- // "DiagonalHeatmapTrack": DiagonalHeatmapTrack,
- "CompositeTrack": tracks.CompositeTrack,
- "DrawableGroup": tracks.DrawableGroup };
-
-/**
- * Create new object from a template. A template can be either an object dictionary or an
- * object itself.
- */
-var object_from_template = function(template, view, container) {
- if ('copy' in template) {
- // Template is an object.
- return template.copy(container);
- }
- else {
- // Template is a dictionary.
- var
- drawable_type = template['obj_type'];
- // For backward compatibility:
- if (!drawable_type) {
- drawable_type = template['track_type'];
- }
- return new addable_objects[ drawable_type ](view, container, template);
- }
-};
-
-/**
* Create a complete Trackster visualization. Returns view.
*/
var create_visualization = function(view_config, viewport_config, drawables_config, bookmarks_config, editable) {
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

17 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/0e17b12c1903/
changeset: 0e17b12c1903
user: james_taylor
date: 2012-09-17 21:23:45
summary: trackster: adding packed scripts
affected #: 10 files
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 static/scripts/packed/base.js
--- /dev/null
+++ b/static/scripts/packed/base.js
@@ -0,0 +1,1 @@
+define("libs/backbone",function(b){var a=function(){if(this.initialize){this.initialize.apply(this,arguments)}};a.extend=b.Backbone.Model.extend;return{Base:a,Backbone:b.Backbone}});
\ No newline at end of file
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 static/scripts/packed/galaxy.base.js
--- a/static/scripts/packed/galaxy.base.js
+++ b/static/scripts/packed/galaxy.base.js
@@ -1,1 +1,1 @@
-if(!Array.indexOf){Array.prototype.indexOf=function(c){for(var b=0,a=this.length;b<a;b++){if(this[b]==c){return b}}return -1}}function obj_length(c){if(c.length!==undefined){return c.length}var b=0;for(var a in c){b++}return b}$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function make_popupmenu(b,c){var a=(b.data("menu_options"));b.data("menu_options",c);if(a){return}b.bind("click.show_popup",function(d){$(".popmenu-wrapper").remove();setTimeout(function(){var g=$("<ul class='dropdown-menu' id='"+b.attr("id")+"-menu'></ul>");var f=b.data("menu_options");if(obj_length(f)<=0){$("<li>No Options.</li>").appendTo(g)}$.each(f,function(j,i){if(i){g.append($("<li></li>").append($("<a href='#'></a>").html(j).click(i)))}else{g.append($("<li></li>").addClass("head").append($("<a href='#'></a>").html(j)))}});var h=$("<div class='popmenu-wrapper' style='position: absolute;left: 0; top: -1000;'></div>").append(g).appendTo("body");var e=d.pageX-h.width()/2;e=Math.min(e,$(document).scrollLeft()+$(window).width()-$(h).width()-5);e=Math.max(e,$(document).scrollLeft()+5);h.css({top:d.pageY,left:e})},10);setTimeout(function(){var f=function(h){$(h).bind("click.close_popup",function(){$(".popmenu-wrapper").remove();h.unbind("click.close_popup")})};f($(window.document));f($(window.top.document));for(var e=window.top.frames.length;e--;){var g=$(window.top.frames[e].document);f(g)}},50);return false})}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var a={};var c=$(this);c.find("a").each(function(){var f=$(this),h=f.get(0);var d=h.getAttribute("confirm"),e=h.getAttribute("href"),g=h.getAttribute("target");if(!e){a[f.text()]=null}else{a[f.text()]=function(){if(!d||confirm(d)){var i;if(g=="_parent"){window.parent.location=e}else{if(g=="_top"){window.top.location=e}else{if(g=="demo"){if(i===undefined||i.closed){i=window.open(e,g);i.creator=self}}else{window.location=e}}}}}}});var b=$("#"+c.attr("popupmenu"));b.find("a").bind("click",function(d){d.stopPropagation();return true});make_popupmenu(b,a);b.addClass("popup");c.remove()})}function naturalSort(j,h){var p=/(-?[0-9\.]+)/g,k=j.toString().toLowerCase()||"",g=h.toString().toLowerCase()||"",l=String.fromCharCode(0),n=k.replace(p,l+"$1"+l).split(l),e=g.replace(p,l+"$1"+l).split(l),d=(new Date(k)).getTime(),o=d?(new Date(g)).getTime():null;if(o){if(d<o){return -1}else{if(d>o){return 1}}}var m,f;for(var i=0,c=Math.max(n.length,e.length);i<c;i++){m=parseFloat(n[i])||n[i];f=parseFloat(e[i])||e[i];if(m<f){return -1}else{if(m>f){return 1}}}return 0}function replace_big_select_inputs(a,c,b){if(!jQuery().autocomplete){return}if(a===undefined){a=20}if(c===undefined){c=3000}var b=b||$("select");b.each(function(){var e=$(this);var h=e.find("option").length;if((h<a)||(h>c)){return}if(e.attr("multiple")==="multiple"){return}if(e.hasClass("no-autocomplete")){return}var n=e.attr("value");var d=$("<input type='text' class='text-and-autocomplete-select'></input>");d.attr("size",40);d.attr("name",e.attr("name"));d.attr("id",e.attr("id"));d.click(function(){var o=$(this).val();$(this).val("Loading...");$(this).showAllInCache();$(this).val(o);$(this).select()});var f=[];var j={};e.children("option").each(function(){var p=$(this).text();var o=$(this).attr("value");f.push(p);j[p]=o;j[o]=o;if(o==n){d.attr("value",p)}});if(n===""||n==="?"){d.attr("value","Click to Search or Select")}if(e.attr("name")=="dbkey"){f=f.sort(naturalSort)}var g={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:c,minChars:0,hideForLessThanMinChars:false};d.autocomplete(f,g);e.replaceWith(d);var l=function(){var p=d.attr("value");var o=j[p];if(o!==null&&o!==undefined){d.attr("value",o)}else{if(n!==""){d.attr("value",n)}else{d.attr("value","?")}}};d.parents("form").submit(function(){l()});$(document).bind("convert_to_values",function(){l()});if(e.attr("refresh_on_change")=="true"){var i=e.attr("refresh_on_change_values"),m=e.attr("last_selected_value");if(i!==undefined){i=i.split(",")}var k=function(){var o=j[d.attr("value")];if(m!==o&&o!==null&&o!==undefined){if(i!==undefined&&$.inArray(o,i)===-1&&$.inArray(m,i)===-1){return}d.attr("value",o);$(window).trigger("refresh_on_change");d.parents("form").submit()}};d.bind("result",k);d.keyup(function(o){if(o.keyCode===13){k()}});d.keydown(function(o){if(o.keyCode===13){return false}})}})}$.fn.make_text_editable=function(g){var d=("num_cols" in g?g.num_cols:30),c=("num_rows" in g?g.num_rows:4),e=("use_textarea" in g?g.use_textarea:false),b=("on_finish" in g?g.on_finish:null),f=("help_text" in g?g.help_text:null);var a=$(this);a.addClass("editable-text").click(function(l){if($(this).children(":input").length>0){return}a.removeClass("editable-text");var i=function(m){a.find(":input").remove();if(m!==""){a.text(m)}else{a.html("<br>")}a.addClass("editable-text");if(b){b(m)}};var h=a.text(),k,j;if(e){k=$("<textarea/>").attr({rows:c,cols:d}).text($.trim(h)).keyup(function(m){if(m.keyCode===27){i(h)}});j=$("<button/>").text("Done").click(function(){i(k.val());return false})}else{k=$("<input type='text'/>").attr({value:$.trim(h),size:d}).blur(function(){i(h)}).keyup(function(m){if(m.keyCode===27){$(this).trigger("blur")}else{if(m.keyCode===13){i($(this).val())}}})}a.text("");a.append(k);if(j){a.append(j)}k.focus();k.select();l.stopPropagation()});if(f){a.attr("title",f).tooltip()}return a};function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-active").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text($.trim(k))}else{j=$("<input type='text'></input>").attr({value:$.trim(k),size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){if(o!==""){l.text(o)}else{l.html("<em>None</em>")}if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(d,a,c){var b=function(){try{var e=$.jStorage.get("history_expand_state");if(e){for(var g in e){$("#"+g+" div.historyItemBody").show()}}}catch(f){$.jStorage.deleteKey("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}d.each(function(){var j=this.id,h=$(this).children("div.historyItemBody"),i=h.find("pre.peek");$(this).find(".historyItemTitleBar > .historyItemTitle").wrap("<a href='javascript:void(0);'></a>").click(function(){var k;if(h.is(":visible")){if($.browser.mozilla){i.css("overflow","hidden")}h.slideUp("fast");if(!c){k=$.jStorage.get("history_expand_state");if(k){delete k[j];$.jStorage.set("history_expand_state",k)}}}else{h.slideDown("fast",function(){if($.browser.mozilla){i.css("overflow","auto")}});if(!c){k=$.jStorage.get("history_expand_state");if(!k){k={}}k[j]=true;$.jStorage.set("history_expand_state",k)}}return false})});$("#top-links > a.toggle").click(function(){var h=$.jStorage.get("history_expand_state");if(!h){h={}}$("div.historyItemBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(h){delete h[$(this).parent().attr("id")]}});$.jStorage.set("history_expand_state",h)}).show()};b()}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}function reset_tool_search(a){var c=$("#galaxy_tools").contents();if(c.length===0){c=$(document)}$(this).removeClass("search_active");c.find(".toolTitle").removeClass("search_match");c.find(".toolSectionBody").hide();c.find(".toolTitle").show();c.find(".toolPanelLabel").show();c.find(".toolSectionWrapper").each(function(){if($(this).attr("id")!="recently_used_wrapper"){$(this).show()}else{if($(this).hasClass("user_pref_visible")){$(this).show()}}});c.find("#search-no-results").hide();c.find("#search-spinner").hide();if(a){var b=c.find("#tool-search-query");b.val("search tools")}}var GalaxyAsync=function(a){this.url_dict={};this.log_action=(a===undefined?false:a)};GalaxyAsync.prototype.set_func_url=function(a,b){this.url_dict[a]=b};GalaxyAsync.prototype.set_user_pref=function(a,b){var c=this.url_dict[arguments.callee];if(c===undefined){return false}$.ajax({url:c,data:{pref_name:a,pref_value:b},error:function(){return false},success:function(){return true}})};GalaxyAsync.prototype.log_user_action=function(c,b,d){if(!this.log_action){return}var a=this.url_dict[arguments.callee];if(a===undefined){return false}$.ajax({url:a,data:{action:c,context:b,params:d},error:function(){return false},success:function(){return true}})};$(document).ready(function(){$("select[refresh_on_change='true']").change(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");$(document).trigger("convert_to_values");a.get(0).form.submit()});$(":checkbox[refresh_on_change='true']").click(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");a.get(0).form.submit()});$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tooltip){$(".tooltip").tooltip({placement:"top"})}make_popup_menus();replace_big_select_inputs(20,1500);$("a").click(function(){var b=$(this);var c=(parent.frames&&parent.frames.galaxy_main);if((b.attr("target")=="galaxy_main")&&(!c)){var a=b.attr("href");if(a.indexOf("?")==-1){a+="?"}else{a+="&"}a+="use_panels=True";b.attr("href",a);b.attr("target","_self")}return b})});
\ No newline at end of file
+(function(){var b=0;var c=["ms","moz","webkit","o"];for(var a=0;a<c.length&&!window.requestAnimationFrame;++a){window.requestAnimationFrame=window[c[a]+"RequestAnimationFrame"];window.cancelRequestAnimationFrame=window[c[a]+"CancelRequestAnimationFrame"]}if(!window.requestAnimationFrame){window.requestAnimationFrame=function(h,e){var d=new Date().getTime();var f=Math.max(0,16-(d-b));var g=window.setTimeout(function(){h(d+f)},f);b=d+f;return g}}if(!window.cancelAnimationFrame){window.cancelAnimationFrame=function(d){clearTimeout(d)}}}());if(!Array.indexOf){Array.prototype.indexOf=function(c){for(var b=0,a=this.length;b<a;b++){if(this[b]==c){return b}}return -1}}function obj_length(c){if(c.length!==undefined){return c.length}var b=0;for(var a in c){b++}return b}$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function make_popupmenu(b,c){var a=(b.data("menu_options"));b.data("menu_options",c);if(a){return}b.bind("click.show_popup",function(d){$(".popmenu-wrapper").remove();setTimeout(function(){var g=$("<ul class='dropdown-menu' id='"+b.attr("id")+"-menu'></ul>");var f=b.data("menu_options");if(obj_length(f)<=0){$("<li>No Options.</li>").appendTo(g)}$.each(f,function(j,i){if(i){g.append($("<li></li>").append($("<a href='#'></a>").html(j).click(i)))}else{g.append($("<li></li>").addClass("head").append($("<a href='#'></a>").html(j)))}});var h=$("<div class='popmenu-wrapper' style='position: absolute;left: 0; top: -1000;'></div>").append(g).appendTo("body");var e=d.pageX-h.width()/2;e=Math.min(e,$(document).scrollLeft()+$(window).width()-$(h).width()-5);e=Math.max(e,$(document).scrollLeft()+5);h.css({top:d.pageY,left:e})},10);setTimeout(function(){var f=function(h){$(h).bind("click.close_popup",function(){$(".popmenu-wrapper").remove();h.unbind("click.close_popup")})};f($(window.document));f($(window.top.document));for(var e=window.top.frames.length;e--;){var g=$(window.top.frames[e].document);f(g)}},50);return false})}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var a={};var c=$(this);c.find("a").each(function(){var f=$(this),h=f.get(0);var d=h.getAttribute("confirm"),e=h.getAttribute("href"),g=h.getAttribute("target");if(!e){a[f.text()]=null}else{a[f.text()]=function(){if(!d||confirm(d)){var i;if(g=="_parent"){window.parent.location=e}else{if(g=="_top"){window.top.location=e}else{if(g=="demo"){if(i===undefined||i.closed){i=window.open(e,g);i.creator=self}}else{window.location=e}}}}}}});var b=$("#"+c.attr("popupmenu"));b.find("a").bind("click",function(d){d.stopPropagation();return true});make_popupmenu(b,a);b.addClass("popup");c.remove()})}function naturalSort(j,h){var p=/(-?[0-9\.]+)/g,k=j.toString().toLowerCase()||"",g=h.toString().toLowerCase()||"",l=String.fromCharCode(0),n=k.replace(p,l+"$1"+l).split(l),e=g.replace(p,l+"$1"+l).split(l),d=(new Date(k)).getTime(),o=d?(new Date(g)).getTime():null;if(o){if(d<o){return -1}else{if(d>o){return 1}}}var m,f;for(var i=0,c=Math.max(n.length,e.length);i<c;i++){m=parseFloat(n[i])||n[i];f=parseFloat(e[i])||e[i];if(m<f){return -1}else{if(m>f){return 1}}}return 0}function replace_big_select_inputs(a,c,b){if(!jQuery().autocomplete){return}if(a===undefined){a=20}if(c===undefined){c=3000}var b=b||$("select");b.each(function(){var e=$(this);var h=e.find("option").length;if((h<a)||(h>c)){return}if(e.attr("multiple")==="multiple"){return}if(e.hasClass("no-autocomplete")){return}var n=e.attr("value");var d=$("<input type='text' class='text-and-autocomplete-select'></input>");d.attr("size",40);d.attr("name",e.attr("name"));d.attr("id",e.attr("id"));d.click(function(){var o=$(this).val();$(this).val("Loading...");$(this).showAllInCache();$(this).val(o);$(this).select()});var f=[];var j={};e.children("option").each(function(){var p=$(this).text();var o=$(this).attr("value");f.push(p);j[p]=o;j[o]=o;if(o==n){d.attr("value",p)}});if(n===""||n==="?"){d.attr("value","Click to Search or Select")}if(e.attr("name")=="dbkey"){f=f.sort(naturalSort)}var g={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:c,minChars:0,hideForLessThanMinChars:false};d.autocomplete(f,g);e.replaceWith(d);var l=function(){var p=d.attr("value");var o=j[p];if(o!==null&&o!==undefined){d.attr("value",o)}else{if(n!==""){d.attr("value",n)}else{d.attr("value","?")}}};d.parents("form").submit(function(){l()});$(document).bind("convert_to_values",function(){l()});if(e.attr("refresh_on_change")=="true"){var i=e.attr("refresh_on_change_values"),m=e.attr("last_selected_value");if(i!==undefined){i=i.split(",")}var k=function(){var o=j[d.attr("value")];if(m!==o&&o!==null&&o!==undefined){if(i!==undefined&&$.inArray(o,i)===-1&&$.inArray(m,i)===-1){return}d.attr("value",o);$(window).trigger("refresh_on_change");d.parents("form").submit()}};d.bind("result",k);d.keyup(function(o){if(o.keyCode===13){k()}});d.keydown(function(o){if(o.keyCode===13){return false}})}})}$.fn.make_text_editable=function(g){var d=("num_cols" in g?g.num_cols:30),c=("num_rows" in g?g.num_rows:4),e=("use_textarea" in g?g.use_textarea:false),b=("on_finish" in g?g.on_finish:null),f=("help_text" in g?g.help_text:null);var a=$(this);a.addClass("editable-text").click(function(l){if($(this).children(":input").length>0){return}a.removeClass("editable-text");var i=function(m){a.find(":input").remove();if(m!==""){a.text(m)}else{a.html("<br>")}a.addClass("editable-text");if(b){b(m)}};var h=a.text(),k,j;if(e){k=$("<textarea/>").attr({rows:c,cols:d}).text($.trim(h)).keyup(function(m){if(m.keyCode===27){i(h)}});j=$("<button/>").text("Done").click(function(){i(k.val());return false})}else{k=$("<input type='text'/>").attr({value:$.trim(h),size:d}).blur(function(){i(h)}).keyup(function(m){if(m.keyCode===27){$(this).trigger("blur")}else{if(m.keyCode===13){i($(this).val())}}})}a.text("");a.append(k);if(j){a.append(j)}k.focus();k.select();l.stopPropagation()});if(f){a.attr("title",f).tooltip()}return a};function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-active").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text($.trim(k))}else{j=$("<input type='text'></input>").attr({value:$.trim(k),size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){if(o!==""){l.text(o)}else{l.html("<em>None</em>")}if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(d,a,c){var b=function(){try{var e=$.jStorage.get("history_expand_state");if(e){for(var g in e){$("#"+g+" div.historyItemBody").show()}}}catch(f){$.jStorage.deleteKey("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}d.each(function(){var j=this.id,h=$(this).children("div.historyItemBody"),i=h.find("pre.peek");$(this).find(".historyItemTitleBar > .historyItemTitle").wrap("<a href='javascript:void(0);'></a>").click(function(){var k;if(h.is(":visible")){if($.browser.mozilla){i.css("overflow","hidden")}h.slideUp("fast");if(!c){k=$.jStorage.get("history_expand_state");if(k){delete k[j];$.jStorage.set("history_expand_state",k)}}}else{h.slideDown("fast",function(){if($.browser.mozilla){i.css("overflow","auto")}});if(!c){k=$.jStorage.get("history_expand_state");if(!k){k={}}k[j]=true;$.jStorage.set("history_expand_state",k)}}return false})});$("#top-links > a.toggle").click(function(){var h=$.jStorage.get("history_expand_state");if(!h){h={}}$("div.historyItemBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(h){delete h[$(this).parent().attr("id")]}});$.jStorage.set("history_expand_state",h)}).show()};b()}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}function reset_tool_search(a){var c=$("#galaxy_tools").contents();if(c.length===0){c=$(document)}$(this).removeClass("search_active");c.find(".toolTitle").removeClass("search_match");c.find(".toolSectionBody").hide();c.find(".toolTitle").show();c.find(".toolPanelLabel").show();c.find(".toolSectionWrapper").each(function(){if($(this).attr("id")!="recently_used_wrapper"){$(this).show()}else{if($(this).hasClass("user_pref_visible")){$(this).show()}}});c.find("#search-no-results").hide();c.find("#search-spinner").hide();if(a){var b=c.find("#tool-search-query");b.val("search tools")}}var GalaxyAsync=function(a){this.url_dict={};this.log_action=(a===undefined?false:a)};GalaxyAsync.prototype.set_func_url=function(a,b){this.url_dict[a]=b};GalaxyAsync.prototype.set_user_pref=function(a,b){var c=this.url_dict[arguments.callee];if(c===undefined){return false}$.ajax({url:c,data:{pref_name:a,pref_value:b},error:function(){return false},success:function(){return true}})};GalaxyAsync.prototype.log_user_action=function(c,b,d){if(!this.log_action){return}var a=this.url_dict[arguments.callee];if(a===undefined){return false}$.ajax({url:a,data:{action:c,context:b,params:d},error:function(){return false},success:function(){return true}})};$(document).ready(function(){$("select[refresh_on_change='true']").change(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");$(document).trigger("convert_to_values");a.get(0).form.submit()});$(":checkbox[refresh_on_change='true']").click(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");a.get(0).form.submit()});$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tooltip){$(".tooltip").tooltip({placement:"top"})}make_popup_menus();replace_big_select_inputs(20,1500);$("a").click(function(){var b=$(this);var c=(parent.frames&&parent.frames.galaxy_main);if((b.attr("target")=="galaxy_main")&&(!c)){var a=b.attr("href");if(a.indexOf("?")==-1){a+="?"}else{a+="&"}a+="use_panels=True";b.attr("href",a);b.attr("target","_self")}return b})});
\ No newline at end of file
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 static/scripts/packed/viz/sweepster.js
--- a/static/scripts/packed/viz/sweepster.js
+++ b/static/scripts/packed/viz/sweepster.js
@@ -1,1 +1,1 @@
-var ToolInputsSettings=Backbone.Model.extend({defaults:{inputs:null,values:null}});var ToolParameterTree=Backbone.RelationalModel.extend({defaults:{tool:null,tree_data:null},initialize:function(b){var a=this;this.get("tool").get("inputs").each(function(c){if(!c.get_samples()){return}c.on("change:min change:max change:num_samples",function(d){if(d.get("in_ptree")){a.set_tree_data()}},a);c.on("change:in_ptree",function(d){if(d.get("in_ptree")){a.add_param(d)}else{a.remove_param(d)}a.set_tree_data()},a)});if(b.config){_.each(b.config,function(d){var c=a.get("tool").get("inputs").find(function(e){return e.get("name")===d.name});a.add_param(c);c.set(d)})}},add_param:function(a){if(a.get("ptree_index")){return}a.set("in_ptree",true);a.set("ptree_index",this.get_tree_params().length)},remove_param:function(a){a.set("in_ptree",false);a.set("ptree_index",null);_(this.get_tree_params()).each(function(b,c){b.set("ptree_index",c+1)})},set_tree_data:function(){var b=_.map(this.get_tree_params(),function(d){return{param:d,samples:d.get_samples()}});var a=0,c=function(g,d){var i=g[d],h=i.param,f=h.get("label"),e=i.samples;if(g.length-1===d){return _.map(e,function(j){return{id:a++,name:j,param:h,value:j}})}return _.map(e,function(j){return{id:a++,name:j,param:h,value:j,children:c(g,d+1)}})};this.set("tree_data",{name:"Root",id:a++,children:(b.length!==0?c(b,0):null)})},get_tree_params:function(){return _(this.get("tool").get("inputs").where({in_ptree:true})).sortBy(function(a){return a.get("ptree_index")})},get_num_leaves:function(){return this.get_tree_params().reduce(function(a,b){return a*b.get_samples().length},1)},get_node_settings:function(e){var c=this.get("tool").get_inputs_dict();var f=e.parent;if(f){while(f.depth!==0){c[f.param.get("name")]=f.value;f=f.parent}}var a=this,b=function(h,g){if(h.param){g[h.param.get("name")]=h.value}if(!h.children){return new ToolInputsSettings({inputs:a.get("tool").get("inputs"),values:g})}else{return _.flatten(_.map(h.children,function(i){return b(i,_.clone(g))}))}},d=b(e,c);if(!_.isArray(d)){d=[d]}return d},get_connected_nodes:function(c){var d=function(e){if(!e.children){return e}else{return _.flatten([e,_.map(e.children,function(f){return d(f)})])}};var b=[],a=c.parent;while(a){b.push(a);a=a.parent}return _.flatten([b,d(c)])},get_leaf:function(b){var c=this.get("tree_data"),a=function(d){return _.find(d,function(e){return b[e.param.get("name")]===e.value})};while(c.children){c=a(c.children)}return c},toJSON:function(){return this.get_tree_params().map(function(a){return{name:a.get("name"),min:a.get("min"),max:a.get("max"),num_samples:a.get("num_samples")}})}});var SweepsterTrack=Backbone.RelationalModel.extend({defaults:{track:null,mode:"Pack",settings:null,regions:null},relations:[{type:Backbone.HasMany,key:"regions",relatedModel:"GenomeRegion"}],initialize:function(a){if(a.track){var b=_.extend({data_url:galaxy_paths.get("raw_data_url"),converted_datasets_state_url:galaxy_paths.get("dataset_state_url")},a.track);this.set("track",object_from_template(b,{},null))}},same_settings:function(a){var b=this.get("settings"),c=a.get("settings");for(var d in b){if(!c[d]||b[d]!==c[d]){return false}}return true},toJSON:function(){return{track:this.get("track").to_dict(),settings:this.get("settings"),regions:this.get("regions")}}});var TrackCollection=Backbone.Collection.extend({model:SweepsterTrack});var SweepsterVisualization=Visualization.extend({defaults:_.extend({},Visualization.prototype.defaults,{dataset:null,tool:null,parameter_tree:null,regions:null,tracks:null,default_mode:"Pack"}),relations:[{type:Backbone.HasOne,key:"dataset",relatedModel:"Dataset"},{type:Backbone.HasOne,key:"tool",relatedModel:"Tool"},{type:Backbone.HasMany,key:"regions",relatedModel:"GenomeRegion"},{type:Backbone.HasMany,key:"tracks",relatedModel:"SweepsterTrack"}],initialize:function(a){var b=this.get("tool").copy(true);this.set("tool_with_samplable_inputs",b);this.set("parameter_tree",new ToolParameterTree({tool:b,config:a.tree_config}))},add_track:function(a){this.get("tracks").add(a)},toJSON:function(){return{id:this.get("id"),title:"Parameter exploration for dataset '"+this.get("dataset").get("name")+"'",type:"sweepster",dataset_id:this.get("dataset").id,tool_id:this.get("tool").id,regions:this.get("regions").toJSON(),tree_config:this.get("parameter_tree").toJSON(),tracks:this.get("tracks").toJSON()}}});var SweepsterTrackView=Backbone.View.extend({tagName:"tr",TILE_LEN:250,initialize:function(a){this.canvas_manager=a.canvas_manager;this.render();this.model.on("change:track change:mode",this.draw_tiles,this)},render:function(){var f=this.model.get("settings"),b=f.get("values"),d=$("<td/>").addClass("settings").appendTo(this.$el),c=$("<div/>").addClass("track-info").hide().appendTo(d);c.append($("<div/>").css("font-weight","bold").text("Track Settings"));f.get("inputs").each(function(h){c.append(h.get("label")+": "+b[h.get("name")]+"<br/>")});var a=this,g=$("<button/>").appendTo(c).text("Run on complete dataset").click(function(){c.toggle();a.trigger("run_on_dataset",f)});var e=create_icon_buttons_menu([{title:"Settings",icon_class:"gear track-settings",on_click:function(){c.toggle()}},{title:"Remove",icon_class:"cross-circle",on_click:function(){a.$el.remove();$(".bs-tooltip").remove()}}]);d.prepend(e.$el);this.model.get("regions").each(function(){a.$el.append($("<td/>").addClass("tile").html($("<img/>").attr("src",galaxy_paths.get("image_path")+"/loading_large_white_bg.gif")))});if(this.model.get("track")){this.draw_tiles()}},draw_tiles:function(){var b=this,a=this.model.get("track"),d=this.model.get("regions"),c=this.$el.find("td.tile");if(!a){return}$.when(a.data_manager.data_is_ready()).then(function(e){d.each(function(h,g){var f=h.length()/b.TILE_LEN,j=1/f,i=b.model.get("mode");$.when(a.data_manager.get_data(h,i,f,{})).then(function(l){var k=b.canvas_manager.new_canvas();k.width=b.TILE_LEN;k.height=a.get_canvas_height(l,i,j,k.width);a.draw_tile(l,k.getContext("2d"),i,f,h,j);$(c[g]).empty().append(k)})})})}});var ToolInputValOrSweepView=Backbone.View.extend({number_input_template:'<div class="form-row-input sweep"><input class="min" type="text" size="6" value="<%= min %>"> - <input class="max" type="text" size="6" value="<%= max %>"> samples: <input class="num_samples" type="text" size="1" value="<%= num_samples %>"></div>',select_input_template:'<div class="form-row-input sweep"><%= options %></div>',initialize:function(a){this.$el=a.tool_row;this.render()},render:function(){var b=this.model,f=b.get("type"),h=this.$el.find(".form-row-input"),d=null;h.find(":input").change(function(){b.set("value",$(this).val())});if(f==="number"){d=$(_.template(this.number_input_template,this.model.toJSON()))}else{if(f==="select"){var c=_.map(this.$el.find("select option"),function(i){return $(i).val()}),e=c.join(", ");d=$(_.template(this.select_input_template,{options:e}))}}d.insertAfter(h);var a=this,g=create_icon_buttons_menu([{title:"Add parameter to tree",icon_class:"plus-button",on_click:function(){b.set("in_ptree",true);h.hide();d.show();$(this).hide();a.$el.find(".icon-button.toggle").show()}},{title:"Remove parameter from tree",icon_class:"toggle",on_click:function(){b.set("in_ptree",false);d.hide();h.show();$(this).hide();a.$el.find(".icon-button.plus-button").show()}}],{});this.$el.prepend(g.$el);if(b.get("in_ptree")){h.hide();a.$el.find(".icon-button.plus-button").hide()}else{a.$el.find(".icon-button.toggle").hide();d.hide()}_.each(["min","max","num_samples"],function(i){d.find("."+i).change(function(){b.set(i,parseFloat($(this).val()))})})}});var ToolParameterTreeDesignView=Backbone.View.extend({className:"tree-design",initialize:function(a){this.render()},render:function(){var c=new ToolFormView({model:this.model.get("tool")});c.render();this.$el.append(c.$el);var b=this,a=b.model.get("tool").get("inputs");this.$el.find(".form-row").not(".form-actions").each(function(d){var e=new ToolInputValOrSweepView({model:a.at(d),tool_row:$(this)})})}});var ToolParameterTreeView=Backbone.View.extend({className:"tool-parameter-tree",initialize:function(a){this.model.on("change:tree_data",this.render,this)},render:function(){this.$el.children().remove();var i=this.model.get_tree_params();if(!i.length){return}this.width=100*(2+i.length);this.height=15*this.model.get_num_leaves();var h=this;var g=d3.layout.cluster().size([this.height,this.width-160]);var c=d3.svg.diagonal().projection(function(j){return[j.y,j.x]});var a=g.nodes(this.model.get("tree_data"));var d=_.uniq(_.pluck(a,"y"));_.each(i,function(l,k){var j=d[k+1],m=$("#center").position().left;h.$el.append($("<div>").addClass("label").text(l.get("label")).css("left",j+m))});var b=d3.select(this.$el[0]).append("svg").attr("width",this.width).attr("height",this.height+30).append("g").attr("transform","translate(40, 20)");var f=b.selectAll("path.link").data(g.links(a)).enter().append("path").attr("class","link").attr("d",c);var e=b.selectAll("g.node").data(a).enter().append("g").attr("class","node").attr("transform",function(j){return"translate("+j.y+","+j.x+")"}).on("mouseover",function(k){var j=_.pluck(h.model.get_connected_nodes(k),"id");e.filter(function(l){return _.find(j,function(m){return m===l.id})!==undefined}).style("fill","#f00")}).on("mouseout",function(){e.style("fill","#000")});e.append("circle").attr("r",9);e.append("text").attr("dx",function(j){return j.children?-12:12}).attr("dy",3).attr("text-anchor",function(j){return j.children?"end":"start"}).text(function(j){return j.name})}});var SweepsterVisualizationView=Backbone.View.extend({className:"Sweepster",helpText:"<div><h4>Getting Started</h4><ol><li>Create a parameter tree by using the icons next to the tool's parameter names to add or remove parameters.<li>Adjust the tree by using parameter inputs to select min, max, and number of samples<li>Run the tool with different settings by clicking on tree nodes</ol></div>",initialize:function(b){this.canvas_manager=new CanvasManager(this.$el.parents("body"));this.tool_param_tree_view=new ToolParameterTreeView({model:this.model.get("parameter_tree")});this.track_collection_container=$("<table/>").addClass("tracks");this.model.get("parameter_tree").on("change:tree_data",this.handle_node_clicks,this);var a=this;this.model.get("tracks").each(function(c){c.get("track").view=a});this.block_color=get_random_color();this.reverse_strand_color=get_random_color([this.block_color,"#ffffff"])},render:function(){var g=new ToolParameterTreeDesignView({model:this.model.get("parameter_tree")});$("#left").append(g.$el);var j=this,d=j.model.get("regions"),h=$("<tr/>").appendTo(this.track_collection_container);d.each(function(k){h.append($("<th>").text(k.toString()))});h.children().first().attr("colspan",2);var e=$("<div>").addClass("tiles");$("#right").append(e.append(this.track_collection_container));j.model.get("tracks").each(function(k){j.add_track(k)});var i=$(this.helpText).addClass("help"),f=create_icon_buttons_menu([{title:"Close",icon_class:"cross-circle",on_click:function(){$(".bs-tooltip").remove();i.remove()}}]);i.prepend(f.$el.css("float","right"));$("#center").append(i);this.tool_param_tree_view.render();$("#center").append(this.tool_param_tree_view.$el);this.handle_node_clicks();var c=create_icon_buttons_menu([{icon_class:"chevron-expand",title:"Set display mode"},{icon_class:"cross-circle",title:"Close",on_click:function(){window.location="${h.url_for( controller='visualization', action='list' )}"}}],{tooltip_config:{placement:"bottom"}});var b=["Squish","Pack"],a={};_.each(b,function(k){a[k]=function(){j.model.set("default_mode",k);j.model.get("tracks").each(function(l){l.set("mode",k)})}});make_popupmenu(c.$el.find(".chevron-expand"),a);c.$el.attr("style","float: right");$("#right .unified-panel-header-inner").append(c.$el)},run_tool_on_dataset:function(b){var a=this.model.get("tool"),d=a.get("name"),c=this.model.get("dataset");a.set_input_values(b.get("values"));$.when(a.rerun(c)).then(function(e){});show_modal("Running "+d+" on complete dataset",d+" is running on dataset '"+c.get("name")+"'. Outputs are in the dataset's history.",{Ok:function(){hide_modal()}})},add_track:function(d){var b=this,c=this.model.get("parameter_tree");b.model.add_track(d);var a=new SweepsterTrackView({model:d,canvas_manager:b.canvas_manager});a.on("run_on_dataset",b.run_tool_on_dataset,b);b.track_collection_container.append(a.$el);a.$el.hover(function(){var f=c.get_leaf(d.get("settings").get("values"));var e=_.pluck(c.get_connected_nodes(f),"id");d3.select(b.tool_param_tree_view.$el[0]).selectAll("g.node").filter(function(g){return _.find(e,function(h){return h===g.id})!==undefined}).style("fill","#f00")},function(){d3.select(b.tool_param_tree_view.$el[0]).selectAll("g.node").style("fill","#000")});return d},handle_node_clicks:function(){var a=this,b=this.model.get("parameter_tree"),d=this.model.get("regions"),c=d3.select(this.tool_param_tree_view.$el[0]).selectAll("g.node");c.on("click",function(k,g){var f=a.model.get("tool"),j=a.model.get("dataset"),h=b.get_node_settings(k),e=$.Deferred();if(h.length>=10){show_modal("Whoa there cowboy!","You clicked on a node to try "+a.model.get("tool").get("name")+" with "+h.length+" different combinations of settings. You can only run 10 jobs at a time.",{Ok:function(){hide_modal();e.resolve(false)}})}else{e.resolve(true)}$.when(e).then(function(i){if(!i){return}var l=_.map(h,function(m){var n=new SweepsterTrack({settings:m,regions:d,mode:a.model.get("default_mode")});a.add_track(n);return n});_.each(l,function(n,m){setTimeout(function(){f.set_input_values(n.get("settings").get("values"));$.when(f.rerun(j,d)).then(function(p){var q=_.extend({data_url:galaxy_paths.get("raw_data_url"),converted_datasets_state_url:galaxy_paths.get("dataset_state_url")},p.first().get("track_config")),o=object_from_template(q,a,null);o.prefs.block_color=a.block_color;o.prefs.reverse_strand_color=a.reverse_strand_color;n.set("track",o)})},m*10000)})})})}});
\ No newline at end of file
+var ToolInputsSettings=Backbone.Model.extend({defaults:{inputs:null,values:null}});var ToolParameterTree=Backbone.RelationalModel.extend({defaults:{tool:null,tree_data:null},initialize:function(b){var a=this;this.get("tool").get("inputs").each(function(c){if(!c.get_samples()){return}c.on("change:min change:max change:num_samples",function(d){if(d.get("in_ptree")){a.set_tree_data()}},a);c.on("change:in_ptree",function(d){if(d.get("in_ptree")){a.add_param(d)}else{a.remove_param(d)}a.set_tree_data()},a)});if(b.config){_.each(b.config,function(d){var c=a.get("tool").get("inputs").find(function(e){return e.get("name")===d.name});a.add_param(c);c.set(d)})}},add_param:function(a){if(a.get("ptree_index")){return}a.set("in_ptree",true);a.set("ptree_index",this.get_tree_params().length)},remove_param:function(a){a.set("in_ptree",false);a.set("ptree_index",null);_(this.get_tree_params()).each(function(b,c){b.set("ptree_index",c+1)})},set_tree_data:function(){var b=_.map(this.get_tree_params(),function(d){return{param:d,samples:d.get_samples()}});var a=0,c=function(g,d){var i=g[d],h=i.param,f=h.get("label"),e=i.samples;if(g.length-1===d){return _.map(e,function(j){return{id:a++,name:j,param:h,value:j}})}return _.map(e,function(j){return{id:a++,name:j,param:h,value:j,children:c(g,d+1)}})};this.set("tree_data",{name:"Root",id:a++,children:(b.length!==0?c(b,0):null)})},get_tree_params:function(){return _(this.get("tool").get("inputs").where({in_ptree:true})).sortBy(function(a){return a.get("ptree_index")})},get_num_leaves:function(){return this.get_tree_params().reduce(function(a,b){return a*b.get_samples().length},1)},get_node_settings:function(e){var c=this.get("tool").get_inputs_dict();var f=e.parent;if(f){while(f.depth!==0){c[f.param.get("name")]=f.value;f=f.parent}}var a=this,b=function(h,g){if(h.param){g[h.param.get("name")]=h.value}if(!h.children){return new ToolInputsSettings({inputs:a.get("tool").get("inputs"),values:g})}else{return _.flatten(_.map(h.children,function(i){return b(i,_.clone(g))}))}},d=b(e,c);if(!_.isArray(d)){d=[d]}return d},get_connected_nodes:function(c){var d=function(e){if(!e.children){return e}else{return _.flatten([e,_.map(e.children,function(f){return d(f)})])}};var b=[],a=c.parent;while(a){b.push(a);a=a.parent}return _.flatten([b,d(c)])},get_leaf:function(b){var c=this.get("tree_data"),a=function(d){return _.find(d,function(e){return b[e.param.get("name")]===e.value})};while(c.children){c=a(c.children)}return c},toJSON:function(){return this.get_tree_params().map(function(a){return{name:a.get("name"),min:a.get("min"),max:a.get("max"),num_samples:a.get("num_samples")}})}});var SweepsterTrack=Backbone.RelationalModel.extend({defaults:{track:null,mode:"Pack",settings:null,regions:null},relations:[{type:Backbone.HasMany,key:"regions",relatedModel:"GenomeRegion"}],initialize:function(a){if(a.track){var b=_.extend({data_url:galaxy_paths.get("raw_data_url"),converted_datasets_state_url:galaxy_paths.get("dataset_state_url")},a.track);this.set("track",object_from_template(b,{},null))}},same_settings:function(a){var b=this.get("settings"),c=a.get("settings");for(var d in b){if(!c[d]||b[d]!==c[d]){return false}}return true},toJSON:function(){return{track:this.get("track").to_dict(),settings:this.get("settings"),regions:this.get("regions")}}});var TrackCollection=Backbone.Collection.extend({model:SweepsterTrack});var SweepsterVisualization=Visualization.extend({defaults:_.extend({},Visualization.prototype.defaults,{dataset:null,tool:null,parameter_tree:null,regions:null,tracks:null,default_mode:"Pack"}),relations:[{type:Backbone.HasOne,key:"dataset",relatedModel:"Dataset"},{type:Backbone.HasOne,key:"tool",relatedModel:"Tool"},{type:Backbone.HasMany,key:"regions",relatedModel:"GenomeRegion"},{type:Backbone.HasMany,key:"tracks",relatedModel:"SweepsterTrack"}],initialize:function(a){var b=this.get("tool").copy(true);this.set("tool_with_samplable_inputs",b);this.set("parameter_tree",new ToolParameterTree({tool:b,config:a.tree_config}))},add_track:function(a){this.get("tracks").add(a)},toJSON:function(){return{id:this.get("id"),title:"Parameter exploration for dataset '"+this.get("dataset").get("name")+"'",type:"sweepster",dataset_id:this.get("dataset").id,tool_id:this.get("tool").id,regions:this.get("regions").toJSON(),tree_config:this.get("parameter_tree").toJSON(),tracks:this.get("tracks").toJSON()}}});var SweepsterTrackView=Backbone.View.extend({tagName:"tr",TILE_LEN:250,initialize:function(a){this.canvas_manager=a.canvas_manager;this.render();this.model.on("change:track change:mode",this.draw_tiles,this)},render:function(){var f=this.model.get("settings"),b=f.get("values"),d=$("<td/>").addClass("settings").appendTo(this.$el),c=$("<div/>").addClass("track-info").hide().appendTo(d);c.append($("<div/>").css("font-weight","bold").text("Track Settings"));f.get("inputs").each(function(h){c.append(h.get("label")+": "+b[h.get("name")]+"<br/>")});var a=this,g=$("<button/>").appendTo(c).text("Run on complete dataset").click(function(){c.toggle();a.trigger("run_on_dataset",f)});var e=create_icon_buttons_menu([{title:"Settings",icon_class:"gear track-settings",on_click:function(){c.toggle()}},{title:"Remove",icon_class:"cross-circle",on_click:function(){a.$el.remove();$(".bs-tooltip").remove()}}]);d.prepend(e.$el);this.model.get("regions").each(function(){a.$el.append($("<td/>").addClass("tile").html($("<img/>").attr("src",galaxy_paths.get("image_path")+"/loading_large_white_bg.gif")))});if(this.model.get("track")){this.draw_tiles()}},draw_tiles:function(){var b=this,a=this.model.get("track"),d=this.model.get("regions"),c=this.$el.find("td.tile");if(!a){return}$.when(a.data_manager.data_is_ready()).then(function(e){d.each(function(h,g){var f=h.length()/b.TILE_LEN,j=1/f,i=b.model.get("mode");$.when(a.data_manager.get_data(h,i,f,{})).then(function(l){var k=b.canvas_manager.new_canvas();k.width=b.TILE_LEN;k.height=a.get_canvas_height(l,i,j,k.width);a.draw_tile(l,k.getContext("2d"),i,f,h,j);$(c[g]).empty().append(k)})})})}});var ToolInputValOrSweepView=Backbone.View.extend({number_input_template:'<div class="form-row-input sweep"><input class="min" type="text" size="6" value="<%= min %>"> - <input class="max" type="text" size="6" value="<%= max %>"> samples: <input class="num_samples" type="text" size="1" value="<%= num_samples %>"></div>',select_input_template:'<div class="form-row-input sweep"><%= options %></div>',initialize:function(a){this.$el=a.tool_row;this.render()},render:function(){var b=this.model,f=b.get("type"),h=this.$el.find(".form-row-input"),d=null;h.find(":input").change(function(){b.set("value",$(this).val())});if(f==="number"){d=$(_.template(this.number_input_template,this.model.toJSON()))}else{if(f==="select"){var c=_.map(this.$el.find("select option"),function(i){return $(i).val()}),e=c.join(", ");d=$(_.template(this.select_input_template,{options:e}))}}d.insertAfter(h);var a=this,g=create_icon_buttons_menu([{title:"Add parameter to tree",icon_class:"plus-button",on_click:function(){b.set("in_ptree",true);h.hide();d.show();$(this).hide();a.$el.find(".icon-button.toggle").show()}},{title:"Remove parameter from tree",icon_class:"toggle",on_click:function(){b.set("in_ptree",false);d.hide();h.show();$(this).hide();a.$el.find(".icon-button.plus-button").show()}}],{});this.$el.prepend(g.$el);if(b.get("in_ptree")){h.hide();a.$el.find(".icon-button.plus-button").hide()}else{a.$el.find(".icon-button.toggle").hide();d.hide()}_.each(["min","max","num_samples"],function(i){d.find("."+i).change(function(){b.set(i,parseFloat($(this).val()))})})}});var ToolParameterTreeDesignView=Backbone.View.extend({className:"tree-design",initialize:function(a){this.render()},render:function(){var c=new ToolFormView({model:this.model.get("tool")});c.render();this.$el.append(c.$el);var b=this,a=b.model.get("tool").get("inputs");this.$el.find(".form-row").not(".form-actions").each(function(d){var e=new ToolInputValOrSweepView({model:a.at(d),tool_row:$(this)})})}});var ToolParameterTreeView=Backbone.View.extend({className:"tool-parameter-tree",initialize:function(a){this.model.on("change:tree_data",this.render,this)},render:function(){this.$el.children().remove();var i=this.model.get_tree_params();if(!i.length){return}this.width=100*(2+i.length);this.height=15*this.model.get_num_leaves();var h=this;var g=d3.layout.cluster().size([this.height,this.width-160]);var c=d3.svg.diagonal().projection(function(j){return[j.y,j.x]});var a=g.nodes(this.model.get("tree_data"));var d=_.uniq(_.pluck(a,"y"));_.each(i,function(l,k){var j=d[k+1],m=$("#center").position().left;h.$el.append($("<div>").addClass("label").text(l.get("label")).css("left",j+m))});var b=d3.select(this.$el[0]).append("svg").attr("width",this.width).attr("height",this.height+30).append("g").attr("transform","translate(40, 20)");var f=b.selectAll("path.link").data(g.links(a)).enter().append("path").attr("class","link").attr("d",c);var e=b.selectAll("g.node").data(a).enter().append("g").attr("class","node").attr("transform",function(j){return"translate("+j.y+","+j.x+")"}).on("mouseover",function(k){var j=_.pluck(h.model.get_connected_nodes(k),"id");e.filter(function(l){return _.find(j,function(m){return m===l.id})!==undefined}).style("fill","#f00")}).on("mouseout",function(){e.style("fill","#000")});e.append("circle").attr("r",9);e.append("text").attr("dx",function(j){return j.children?-12:12}).attr("dy",3).attr("text-anchor",function(j){return j.children?"end":"start"}).text(function(j){return j.name})}});var SweepsterVisualizationView=Backbone.View.extend({className:"Sweepster",helpText:"<div><h4>Getting Started</h4><ol><li>Create a parameter tree by using the icons next to the tool's parameter names to add or remove parameters.<li>Adjust the tree by using parameter inputs to select min, max, and number of samples<li>Run the tool with different settings by clicking on tree nodes</ol></div>",initialize:function(b){this.canvas_manager=new CanvasManager(this.$el.parents("body"));this.tool_param_tree_view=new ToolParameterTreeView({model:this.model.get("parameter_tree")});this.track_collection_container=$("<table/>").addClass("tracks");this.model.get("parameter_tree").on("change:tree_data",this.handle_node_clicks,this);var a=this;this.model.get("tracks").each(function(c){c.get("track").view=a});this.block_color=get_random_color();this.reverse_strand_color=get_random_color([this.block_color,"#ffffff"])},render:function(){var g=new ToolParameterTreeDesignView({model:this.model.get("parameter_tree")});$("#left").append(g.$el);var j=this,d=j.model.get("regions"),h=$("<tr/>").appendTo(this.track_collection_container);d.each(function(k){h.append($("<th>").text(k.toString()))});h.children().first().attr("colspan",2);var e=$("<div>").addClass("tiles");$("#right").append(e.append(this.track_collection_container));j.model.get("tracks").each(function(k){j.add_track(k)});var i=$(this.helpText).addClass("help"),f=create_icon_buttons_menu([{title:"Close",icon_class:"cross-circle",on_click:function(){$(".bs-tooltip").remove();i.remove()}}]);i.prepend(f.$el.css("float","right"));$("#center").append(i);this.tool_param_tree_view.render();$("#center").append(this.tool_param_tree_view.$el);this.handle_node_clicks();var c=create_icon_buttons_menu([{icon_class:"chevron-expand",title:"Set display mode"},{icon_class:"cross-circle",title:"Close",on_click:function(){window.location="${h.url_for( controller='visualization', action='list' )}"}}],{tooltip_config:{placement:"bottom"}});var b=["Squish","Pack"],a={};_.each(b,function(k){a[k]=function(){j.model.set("default_mode",k);j.model.get("tracks").each(function(l){l.set("mode",k)})}});make_popupmenu(c.$el.find(".chevron-expand"),a);c.$el.attr("style","float: right");$("#right .unified-panel-header-inner").append(c.$el)},run_tool_on_dataset:function(b){var a=this.model.get("tool"),d=a.get("name"),c=this.model.get("dataset");a.set_input_values(b.get("values"));$.when(a.rerun(c)).then(function(e){});show_modal("Running "+d+" on complete dataset",d+" is running on dataset '"+c.get("name")+"'. Outputs are in the dataset's history.",{Ok:function(){hide_modal()}})},add_track:function(d){var b=this,c=this.model.get("parameter_tree");b.model.add_track(d);var a=new SweepsterTrackView({model:d,canvas_manager:b.canvas_manager});a.on("run_on_dataset",b.run_tool_on_dataset,b);b.track_collection_container.append(a.$el);a.$el.hover(function(){var f=c.get_leaf(d.get("settings").get("values"));var e=_.pluck(c.get_connected_nodes(f),"id");d3.select(b.tool_param_tree_view.$el[0]).selectAll("g.node").filter(function(g){return _.find(e,function(h){return h===g.id})!==undefined}).style("fill","#f00")},function(){d3.select(b.tool_param_tree_view.$el[0]).selectAll("g.node").style("fill","#000")});return d},handle_node_clicks:function(){var a=this,b=this.model.get("parameter_tree"),d=this.model.get("regions"),c=d3.select(this.tool_param_tree_view.$el[0]).selectAll("g.node");c.on("click",function(k,g){var f=a.model.get("tool"),j=a.model.get("dataset"),h=b.get_node_settings(k),e=$.Deferred();if(h.length>=10){show_modal("Whoa there cowboy!","You clicked on a node to try "+a.model.get("tool").get("name")+" with "+h.length+" different combinations of settings. You can only run 10 jobs at a time.",{Ok:function(){hide_modal();e.resolve(false)}})}else{e.resolve(true)}$.when(e).then(function(i){if(!i){return}var l=_.map(h,function(m){var n=new SweepsterTrack({settings:m,regions:d,mode:a.model.get("default_mode")});a.add_track(n);return n});_.each(l,function(n,m){setTimeout(function(){f.set_input_values(n.get("settings").get("values"));$.when(f.rerun(j,d)).then(function(p){var q=_.extend({data_url:galaxy_paths.get("raw_data_url"),converted_datasets_state_url:galaxy_paths.get("dataset_state_url")},p.first().get("track_config")),o=object_from_template(q,a,null);o.data_manager.set("data_type","raw_data");o.prefs.block_color=a.block_color;o.prefs.reverse_strand_color=a.reverse_strand_color;n.set("track",o)})},m*10000)})})})}});
\ No newline at end of file
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 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 class_module=function(b,a){var c=function(){var g=arguments[0];for(var f=1;f<arguments.length;f++){var d=arguments[f];for(var e in d){g[e]=d[e]}}return g};a.extend=c};var requestAnimationFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(b,a){window.setTimeout(b,1000/60)}})();var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(e,b){var g=e[0],f=e[1],d=b[0],c=b[1],a;if(g<d){if(f<d){a=BEFORE}else{if(f<=c){a=OVERLAP_START}else{a=CONTAINS}}}else{if(g>c){a=AFTER}else{if(f<=c){a=CONTAINED_BY}else{a=OVERLAP_END}}}return a};var is_overlap=function(c,b){var a=compute_overlap(c,b);return(a!==BEFORE&&a!==AFTER)};var is_deferred=function(a){return("isResolved" in a)};var get_random_color=function(a){if(!a){a="#ffffff"}if(typeof(a)==="string"){a=[a]}for(var j=0;j<a.length;j++){a[j]=parseInt(a[j].slice(1),16)}var n=function(t,s,i){return((t*299)+(s*587)+(i*114))/1000};var e=function(v,u,w,s,i,t){return(Math.max(v,s)-Math.min(v,s))+(Math.max(u,i)-Math.min(u,i))+(Math.max(w,t)-Math.min(w,t))};var g,o,f,k,q,h,r,c,d,b,p,m=false,l=0;do{g=Math.round(Math.random()*16777215);o=(g&16711680)>>16;f=(g&65280)>>8;k=g&255;d=n(o,f,k);m=true;for(j=0;j<a.length;j++){q=a[j];h=(q&16711680)>>16;r=(q&65280)>>8;c=q&255;b=n(h,r,c);p=e(o,f,k,h,r,c);if((Math.abs(d-b)<40)||(p<200)){m=false;break}}l++}while(!m&&l<=10);return"#"+(16777216+g).toString(16).substr(1,6)};var create_action_icon=function(c,b,a){return $("<a/>").attr("href","javascript:void(0);").attr("title",c).addClass("icon-button").addClass(b).tooltip().click(a)};var trackster_module=function(d,S){var o=d("class").extend,s=d("slotting"),I=d("painters");var m={};var k=function(Z,aa){m[Z.attr("id")]=aa};var l=function(Z,ab,ad,ac){ad=".group";var aa={};m[Z.attr("id")]=ac;Z.bind("drag",{handle:"."+ab,relative:true},function(al,am){var ak=$(this),ap=$(this).parent(),ah=ap.children(),aj=m[$(this).attr("id")],ag,af,an,ae,ai;af=$(this).parents(ad);if(af.length!==0){an=af.position().top;ae=an+af.outerHeight();if(am.offsetY<an){$(this).insertBefore(af);var ao=m[af.attr("id")];ao.remove_drawable(aj);ao.container.add_drawable_before(aj,ao);return}else{if(am.offsetY>ae){$(this).insertAfter(af);var ao=m[af.attr("id")];ao.remove_drawable(aj);ao.container.add_drawable(aj);return}}}af=null;for(ai=0;ai<ah.length;ai++){ag=$(ah.get(ai));an=ag.position().top;ae=an+ag.outerHeight();if(ag.is(ad)&&this!==ag.get(0)&&am.offsetY>=an&&am.offsetY<=ae){if(am.offsetY-an<ae-am.offsetY){ag.find(".content-div").prepend(this)}else{ag.find(".content-div").append(this)}if(aj.container){aj.container.remove_drawable(aj)}m[ag.attr("id")].add_drawable(aj);return}}for(ai=0;ai<ah.length;ai++){ag=$(ah.get(ai));if(am.offsetY<ag.position().top&&!(ag.hasClass("reference-track")||ag.hasClass("intro"))){break}}if(ai===ah.length){if(this!==ah.get(ai-1)){ap.append(this);m[ap.attr("id")].move_drawable(aj,ai)}}else{if(this!==ah.get(ai)){$(this).insertBefore(ah.get(ai));m[ap.attr("id")].move_drawable(aj,(am.deltaY>0?ai-1:ai))}}}).bind("dragstart",function(){aa["border-top"]=Z.css("border-top");aa["border-bottom"]=Z.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(aa)})};S.moveable=l;var Y=16,D=9,A=20,x=100,F=12000,P=400,H=5000,u=100,n="There was an error in indexing this dataset. ",G="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",B="No data for this chrom/contig.",t="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",v="Tool cannot be rerun: ",a="Loading data...",T="Ready for display",N=10,E=20;function U(aa,Z){if(!Z){Z=0}var ab=Math.pow(10,Z);return Math.round(aa*ab)/ab}var p=function(aa,Z,ac){if(!p.id_counter){p.id_counter=0}this.id=p.id_counter++;this.name=ac.name;this.view=aa;this.container=Z;this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:ac.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=ac.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(ad){ad.stopPropagation()});var ab=this;this.container_div.hover(function(){ab.icons_div.show()},function(){ab.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};p.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(Z){if(Z.content_visible){Z.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");Z.hide_contents();Z.content_visible=false}else{Z.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");Z.content_visible=true;Z.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(aa){var ac=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},Z=function(){aa.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ab=function(ad){if((ad.keyCode||ad.which)===27){ac()}else{if((ad.keyCode||ad.which)===13){Z()}}};$(window).bind("keypress.check_enter_esc",ab);show_modal("Configure",aa.config.build_form(),{Cancel:ac,OK:Z})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(Z){$(".bs-tooltip").remove();Z.remove()}}];o(p.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(){},to_dict:function(){},set_name:function(Z){this.old_name=this.name;this.name=Z;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 Z=this.view;this.container_div.hide(0,function(){$(this).remove();Z.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(aa,af,ae,ad,Z,ac){var ab=this;this.action_icons[aa]=$("<a/>").attr("href","javascript:void(0);").attr("title",af).addClass("icon-button").addClass(ae).tooltip().click(function(){ad(ab)}).appendTo(this.icons_div);if(ac){this.action_icons[aa].hide()}},build_action_icons:function(Z){var ab;for(var aa=0;aa<Z.length;aa++){ab=Z[aa];this.add_action_icon(ab.name,ab.title,ab.css_class,ab.on_click_fn,ab.prepend,ab.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var w=function(aa,Z,ab){p.call(this,aa,Z,ab);this.obj_type=ab.obj_type;this.drawables=[]};o(w.prototype,p.prototype,{unpack_drawables:function(ab){this.drawables=[];var aa;for(var Z=0;Z<ab.length;Z++){aa=object_from_template(ab[Z],this.view,this);this.add_drawable(aa)}},init:function(){for(var Z=0;Z<this.drawables.length;Z++){this.drawables[Z].init()}},_draw:function(){for(var Z=0;Z<this.drawables.length;Z++){this.drawables[Z]._draw()}},to_dict:function(){var aa=[];for(var Z=0;Z<this.drawables.length;Z++){aa.push(this.drawables[Z].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:aa}},add_drawable:function(Z){this.drawables.push(Z);Z.container=this;this.changed()},add_drawable_before:function(ab,Z){this.changed();var aa=this.drawables.indexOf(Z);if(aa!==-1){this.drawables.splice(aa,0,ab);return true}return false},replace_drawable:function(ab,Z,aa){var ac=this.drawables.indexOf(ab);if(ac!==-1){this.drawables[ac]=Z;if(aa){ab.container_div.replaceWith(Z.container_div)}this.changed()}return ac},remove_drawable:function(aa){var Z=this.drawables.indexOf(aa);if(Z!==-1){this.drawables.splice(Z,1);aa.container=null;this.changed();return true}return false},move_drawable:function(aa,ab){var Z=this.drawables.indexOf(aa);if(Z!==-1){this.drawables.splice(Z,1);this.drawables.splice(ab,0,aa);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var M=function(aa,Z,ac){o(ac,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});w.call(this,aa,Z,ac);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);l(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new V(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ac){this.unpack_drawables(ac.drawables)}if("filters" in ac){var ab=this.filters_manager;this.filters_manager=new V(this,ac.filters);ab.parent_div.replaceWith(this.filters_manager.parent_div);if(ac.filters.visible){this.setup_multitrack_filtering()}}};o(M.prototype,p.prototype,w.prototype,{action_icons_def:[p.prototype.action_icons_def[0],p.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(Z){$(".bs-tooltip").remove();Z.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(Z){if(Z.filters_manager.visible()){Z.filters_manager.clear_filters();Z._restore_filter_managers()}else{Z.setup_multitrack_filtering();Z.request_draw(true)}Z.filters_manager.toggle()}},p.prototype.action_icons_def[2]],build_container_div:function(){var Z=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(Z)}return Z},build_header_div:function(){var Z=$("<div/>").addClass("track-header");Z.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(Z);return Z},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ab=this.drawables.length;if(ab===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ab===1){if(this.drawables[0] instanceof g){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var ai,ah,af,al=true,ad=this.drawables[0].get_type(),Z=0;for(ai=0;ai<ab;ai++){af=this.drawables[ai];if(af.get_type()!==ad){can_composite=false;break}if(af instanceof c){Z++}}if(al||Z===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(Z>1&&Z===this.drawables.length){var am={},aa;af=this.drawables[0];for(ah=0;ah<af.filters_manager.filters.length;ah++){aa=af.filters_manager.filters[ah];am[aa.name]=[aa]}for(ai=1;ai<this.drawables.length;ai++){af=this.drawables[ai];for(ah=0;ah<af.filters_manager.filters.length;ah++){aa=af.filters_manager.filters[ah];if(aa.name in am){am[aa.name].push(aa)}}}this.filters_manager.remove_all();var ac,ae,ag,aj;for(var ak in am){ac=am[ak];if(ac.length===Z){ae=new Q({name:ac[0].name,index:ac[0].index});this.filters_manager.add_filter(ae)}}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 Z=0;Z<this.drawables.length;Z++){this.drawables[Z].filters_manager=this.saved_filters_managers[Z]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var Z=0;Z<this.drawables.length;Z++){drawable=this.drawables[Z];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=[];for(var aa=0;aa<this.drawables.length;aa++){ad.push(this.drawables[aa].name)}var ab="Composite Track of "+this.drawables.length+" tracks ("+ad.join(", ")+")";var ac=new g(this.view,this.view,{name:ab,drawables:this.drawables});var Z=this.container.replace_drawable(this,ac,true);ac.request_draw()},add_drawable:function(Z){w.prototype.add_drawable.call(this,Z);this.update_icons()},remove_drawable:function(Z){w.prototype.remove_drawable.call(this,Z);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var Z=o(w.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return Z},request_draw:function(Z,ab){for(var aa=0;aa<this.drawables.length;aa++){this.drawables[aa].request_draw(Z,ab)}}});var X=function(Z){o(Z,{obj_type:"View"});w.call(this,"View",Z.container,Z);this.chrom=null;this.vis_id=Z.vis_id;this.dbkey=Z.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.init();this.canvas_manager=new CanvasManager(this.container.get(0).ownerDocument);this.reset()};_.extend(X.prototype,Backbone.Events);o(X.prototype,w.prototype,{init:function(){this.requested_redraw=false;var ab=this.container,Z=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ab);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ab);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ab);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;k(this.viewport_container,Z);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ac=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){add_datasets(add_datasets_url,add_track_async_url,function(ad){_.each(ad,function(ae){Z.add_drawable(object_from_template(ae,Z,Z))})})});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 aa=function(ad){if(ad.type==="focusout"||(ad.keyCode||ad.which)===13||(ad.keyCode||ad.which)===27){if((ad.keyCode||ad.which)!==27){Z.go_to($(this).val())}$(this).hide();$(this).val("");Z.location_span.show();Z.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",aa).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(){Z.location_span.hide();Z.chrom_select.hide();Z.nav_input.val(Z.chrom+":"+Z.low+"-"+Z.high);Z.nav_input.css("display","inline-block");Z.nav_input.select();Z.nav_input.focus();Z.nav_input.autocomplete({source:function(af,ad){var ag=[],ae=$.map(Z.get_drawables(),function(ah){return ah.data_manager.search_features(af.term).success(function(ai){ag=ag.concat(ai)})});$.when.apply($,ae).done(function(){ad($.map(ag,function(ah){return{label:ah[0],value:ah[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(){Z.zoom_out();Z.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){Z.zoom_in();Z.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){Z.change_chrom(Z.chrom_select.val())});this.browser_content_div.click(function(ad){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ad){Z.zoom_in(ad.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ad,ae){this.current_x=ae.offsetX}).bind("drag",function(ad,af){var ag=af.offsetX-this.current_x;this.current_x=af.offsetX;var ae=Math.round(ag/Z.viewport_container.width()*(Z.max_high-Z.max_low));Z.move_delta(-ae)});this.overview_close.click(function(){Z.reset_overview()});this.viewport_container.bind("draginit",function(ad,ae){if(ad.clientX>Z.viewport_container.width()-16){return false}}).bind("dragstart",function(ad,ae){ae.original_low=Z.low;ae.current_height=ad.clientY;ae.current_x=ae.offsetX}).bind("drag",function(af,ah){var ad=$(this);var ai=ah.offsetX-ah.current_x;var ae=ad.scrollTop()-(af.clientY-ah.current_height);ad.scrollTop(ae);ah.current_height=af.clientY;ah.current_x=ah.offsetX;var ag=Math.round(ai/Z.viewport_container.width()*(Z.high-Z.low));Z.move_delta(ag)}).bind("mousewheel",function(af,ah,ae,ad){if(ae){ae*=50;var ag=Math.round(-ae/Z.viewport_container.width()*(Z.high-Z.low));Z.move_delta(ag)}});this.top_labeltrack.bind("dragstart",function(ad,ae){return $("<div />").css({height:Z.browser_content_div.height()+Z.top_labeltrack.height()+Z.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ah,ai){$(ai.proxy).css({left:Math.min(ah.pageX,ai.startX)-Z.container.offset().left,width:Math.abs(ah.pageX-ai.startX)});var ae=Math.min(ah.pageX,ai.startX)-Z.container.offset().left,ad=Math.max(ah.pageX,ai.startX)-Z.container.offset().left,ag=(Z.high-Z.low),af=Z.viewport_container.width();Z.update_location(Math.round(ae/af*ag)+Z.low,Math.round(ad/af*ag)+Z.low)}).bind("dragend",function(ai,aj){var ae=Math.min(ai.pageX,aj.startX),ad=Math.max(ai.pageX,aj.startX),ag=(Z.high-Z.low),af=Z.viewport_container.width(),ah=Z.low;Z.low=Math.round(ae/af*ag)+ah;Z.high=Math.round(ad/af*ag)+ah;$(aj.proxy).remove();Z.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(){Z.resize_window()},500)});$(document).bind("redraw",function(){Z.redraw()});this.reset();$(window).trigger("resize")},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(aa,ac,Z,ad){if(this.timer){clearTimeout(this.timer)}if(ad){var ab=this;this.timer=setTimeout(function(){ab.trigger("navigate",aa+":"+ac+"-"+Z)},500)}else{view.trigger("navigate",aa+":"+ac+"-"+Z)}},update_location:function(Z,ab){this.location_span.text(commatize(Z)+" - "+commatize(ab));this.nav_input.val(this.chrom+":"+commatize(Z)+"-"+commatize(ab));var aa=view.chrom_select.val();if(aa!==""){this.trigger_navigate(aa,view.low,view.high,true)}},load_chroms:function(ab){ab.num=u;var Z=this,aa=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ab,dataType:"json",success:function(ad){if(ad.chrom_info.length===0){return}if(ad.reference){Z.add_label_track(new y(Z))}Z.chrom_data=ad.chrom_info;var ag='<option value="">Select Chrom/Contig</option>';for(var af=0,ac=Z.chrom_data.length;af<ac;af++){var ae=Z.chrom_data[af].chrom;ag+='<option value="'+ae+'">'+ae+"</option>"}if(ad.prev_chroms){ag+='<option value="previous">Previous '+u+"</option>"}if(ad.next_chroms){ag+='<option value="next">Next '+u+"</option>"}Z.chrom_select.html(ag);Z.chrom_start_index=ad.start_index;aa.resolve(ad)},error:function(){alert("Could not load chroms for this dbkey:",Z.dbkey)}});return aa},change_chrom:function(ae,aa,ag){var ab=this;if(!ab.chrom_data){ab.load_chroms_deferred.then(function(){ab.change_chrom(ae,aa,ag)});return}if(!ae||ae==="None"){return}if(ae==="previous"){ab.load_chroms({low:this.chrom_start_index-u});return}if(ae==="next"){ab.load_chroms({low:this.chrom_start_index+u});return}var af=$.grep(ab.chrom_data,function(ah,ai){return ah.chrom===ae})[0];if(af===undefined){ab.load_chroms({chrom:ae},function(){ab.change_chrom(ae,aa,ag)});return}else{if(ae!==ab.chrom){ab.chrom=ae;ab.chrom_select.val(ab.chrom);ab.max_high=af.len-1;ab.reset();ab.request_redraw(true);for(var ad=0,Z=ab.drawables.length;ad<Z;ad++){var ac=ab.drawables[ad];if(ac.init){ac.init()}}if(ab.reference_track){ab.reference_track.init()}}if(aa!==undefined&&ag!==undefined){ab.low=Math.max(aa,0);ab.high=Math.min(ag,ab.max_high)}else{ab.low=0;ab.high=ab.max_high}ab.reset_overview();ab.request_redraw()}},go_to:function(ad){ad=ad.replace(/ |,/g,"");var ah=this,Z,ac,aa=ad.split(":"),af=aa[0],ag=aa[1];if(ag!==undefined){try{var ae=ag.split("-");Z=parseInt(ae[0],10);ac=parseInt(ae[1],10)}catch(ab){return false}}ah.change_chrom(af,Z,ac)},move_fraction:function(ab){var Z=this;var aa=Z.high-Z.low;this.move_delta(ab*aa)},move_delta:function(ac){var Z=this;var ab=Z.high-Z.low;if(Z.low-ac<Z.max_low){Z.low=Z.max_low;Z.high=Z.max_low+ab}else{if(Z.high-ac>Z.max_high){Z.high=Z.max_high;Z.low=Z.max_high-ab}else{Z.high-=ac;Z.low-=ac}}Z.request_redraw();var aa=Z.chrom_select.val();this.trigger_navigate(aa,Z.low,Z.high,true)},add_drawable:function(Z){w.prototype.add_drawable.call(this,Z);Z.init();this.changed();this.update_intro_div()},add_label_track:function(Z){Z.view=this;Z.init();this.label_tracks.push(Z)},remove_drawable:function(ab,aa){w.prototype.remove_drawable.call(this,ab);if(aa){var Z=this;ab.container_div.hide(0,function(){$(this).remove();Z.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ah,Z,ag,ai){var af=this,ae=(ai?[ai]:af.drawables),ab;var aa;for(var ad=0;ad<ae.length;ad++){aa=ae[ad];ab=-1;for(var ac=0;ac<af.tracks_to_be_redrawn.length;ac++){if(af.tracks_to_be_redrawn[ac][0]===aa){ab=ac;break}}if(ab<0){af.tracks_to_be_redrawn.push([aa,Z,ag])}else{af.tracks_to_be_redrawn[ad][1]=Z;af.tracks_to_be_redrawn[ad][2]=ag}}if(!this.requested_redraw){requestAnimationFrame(function(){af._redraw(ah)});this.requested_redraw=true}},_redraw:function(aj){this.requested_redraw=false;var ag=this.low,ac=this.high;if(ag<this.max_low){ag=this.max_low}if(ac>this.max_high){ac=this.max_high}var ai=this.high-this.low;if(this.high!==0&&ai<this.min_separation){ac=ag+this.min_separation}this.low=Math.floor(ag);this.high=Math.ceil(ac);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var Z=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var af=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ak=13;this.overview_box.css({left:Z,width:Math.max(ak,af)}).show();if(af<ak){this.overview_box.css("left",Z-(ak-af)/2)}if(this.overview_highlight){this.overview_highlight.css({left:Z,width:af})}if(!aj){var ab,aa,ah;for(var ad=0,ae=this.tracks_to_be_redrawn.length;ad<ae;ad++){ab=this.tracks_to_be_redrawn[ad][0];aa=this.tracks_to_be_redrawn[ad][1];ah=this.tracks_to_be_redrawn[ad][2];if(ab){ab._draw(aa,ah)}}this.tracks_to_be_redrawn=[];for(ad=0,ae=this.label_tracks.length;ad<ae;ad++){this.label_tracks[ad]._draw()}}},zoom_in:function(aa,ab){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ac=this.high-this.low,ad=ac/2+this.low,Z=(ac/this.zoom_factor)/2;if(aa){ad=aa/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ad-Z);this.high=Math.round(ad+Z);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var aa=this.high-this.low,ab=aa/2+this.low,Z=(aa*this.zoom_factor)/2;this.low=Math.round(ab-Z);this.high=Math.round(ab+Z);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(ab){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ab.dataset_id){return}this.overview_viewport.find(".track").remove()}var aa=ab.copy({content_div:this.overview_viewport}),Z=this;aa.header_div.hide();aa.is_overview=true;Z.overview_drawable=aa;this.overview_drawable.postdraw_actions=function(){Z.overview_highlight.show().height(Z.overview_drawable.content_div.height());Z.overview_viewport.height(Z.overview_drawable.content_div.height()+Z.overview_box.outerHeight());Z.overview_close.show();Z.resize_window()};Z.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 q=function(ab,ag,ac){this.track=ab;this.name=ag.name;this.params=[];var an=ag.params;for(var ad=0;ad<an.length;ad++){var ai=an[ad],aa=ai.name,am=ai.label,ae=unescape(ai.html),ao=ai.value,ak=ai.type;if(ak==="number"){this.params.push(new e(aa,am,ae,(aa in ac?ac[aa]:ao),ai.min,ai.max))}else{if(ak==="select"){this.params.push(new K(aa,am,ae,(aa in ac?ac[aa]:ao)))}else{console.log("WARNING: unrecognized tool parameter type:",aa,ak)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(aq){aq.stopPropagation()}).click(function(aq){aq.stopPropagation()}).bind("dblclick",function(aq){aq.stopPropagation()});var al=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var aj=this.params;var ah=this;$.each(this.params,function(ar,av){var au=$("<div>").addClass("param-row").appendTo(ah.parent_div);var aq=$("<div>").addClass("param-label").text(av.label).appendTo(au);var at=$("<div/>").addClass("param-input").html(av.html).appendTo(au);at.find(":input").val(av.value);$("<div style='clear: both;'/>").appendTo(au)});this.parent_div.find("input").click(function(){$(this).select()});var ap=$("<div>").addClass("param-row").appendTo(this.parent_div);var af=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(ap);var Z=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(ap);Z.click(function(){ah.run_on_region()});af.click(function(){ah.run_on_dataset()});if("visible" in ac&&ac.visible){this.parent_div.show()}};o(q.prototype,{update_params:function(){for(var Z=0;Z<this.params.length;Z++){this.params[Z].update_value()}},state_dict:function(){var aa={};for(var Z=0;Z<this.params.length;Z++){aa[this.params[Z].name]=this.params[Z].value}aa.visible=this.parent_div.is(":visible");return aa},get_param_values_dict:function(){var Z={};this.parent_div.find(":input").each(function(){var aa=$(this).attr("name"),ab=$(this).val();Z[aa]=ab});return Z},get_param_values:function(){var Z=[];this.parent_div.find(":input").each(function(){var aa=$(this).attr("name"),ab=$(this).val();if(aa){Z[Z.length]=ab}});return Z},run_on_dataset:function(){var Z=this;Z.run({target_dataset_id:this.track.original_dataset_id,tool_id:Z.name},null,function(aa){show_modal(Z.name+" is Running",Z.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var aa={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},ae=this.track,ab=aa.tool_id+ae.tool_region_and_parameters_str(aa.chrom,aa.low,aa.high),Z;if(ae.container===view){var ad=new M(view,view,{name:this.name});var ac=ae.container.replace_drawable(ae,ad,false);ad.container_div.insertBefore(ae.view.content_div.children()[ac]);ad.add_drawable(ae);ae.container_div.appendTo(ad.content_div);Z=ad}else{Z=ae.container}var af=new ae.constructor(view,Z,{name:ab,hda_ldda:"hda"});af.init_for_tool_data();af.change_mode(ae.mode);af.set_filters_manager(ae.filters_manager.copy(af));af.update_icons();Z.add_drawable(af);af.tiles_div.text("Starting job.");this.update_params();this.run(aa,af,function(ag){af.set_dataset(new Dataset(ag));af.tiles_div.text("Running job.");af.init()})},run:function(Z,ab,ac){Z.inputs=this.get_param_values_dict();var aa=new ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(Z),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ad){return ad!=="pending"}});$.when(aa.go()).then(function(ad){if(ad==="no converter"){ab.container_div.addClass("error");ab.content_div.text(G)}else{if(ad.error){ab.container_div.addClass("error");ab.content_div.text(v+ad.message)}else{ac(ad)}}})}});var K=function(aa,Z,ab,ac){this.name=aa;this.label=Z;this.html=$(ab);this.value=ac};o(K.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ab,aa,ad,ae,ac,Z){K.call(this,ab,aa,ad,ae);this.min=ac;this.max=Z};o(e.prototype,K.prototype,{update_value:function(){K.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var f=function(Z){this.manager=null;this.name=Z.name;this.index=Z.index;this.tool_id=Z.tool_id;this.tool_exp_name=Z.tool_exp_name};o(f.prototype,{to_dict:function(){return{name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name}}});var Q=function(ah){f.call(this,ah);this.low=("low" in ah?ah.low:-Number.MAX_VALUE);this.high=("high" in ah?ah.high:Number.MAX_VALUE);this.min=("min" in ah?ah.min:Number.MAX_VALUE);this.max=("max" in ah?ah.max:-Number.MAX_VALUE);this.container=null;this.slider=null;this.slider_label=null;var ad=function(ai,aj,ak){ai.click(function(){var ap=aj.text(),an=parseFloat(ak.slider("option","max")),am=(an<=1?4:an<=1000000?an.toString().length:6),ao=false,al=$(this).parents(".slider-row");al.addClass("input");if(ak.slider("option","values")){am=2*am+1;ao=true}aj.text("");$("<input type='text'/>").attr("size",am).attr("maxlength",am).attr("value",ap).appendTo(aj).focus().select().click(function(aq){aq.stopPropagation()}).blur(function(){$(this).remove();aj.text(ap);al.removeClass("input")}).keyup(function(av){if(av.keyCode===27){$(this).trigger("blur")}else{if(av.keyCode===13){var at=ak.slider("option","min"),aq=ak.slider("option","max"),au=function(aw){return(isNaN(aw)||aw>aq||aw<at)},ar=$(this).val();if(!ao){ar=parseFloat(ar);if(au(ar)){alert("Parameter value must be in the range ["+at+"-"+aq+"]");return $(this)}}else{ar=ar.split("-");ar=[parseFloat(ar[0]),parseFloat(ar[1])];if(au(ar[0])||au(ar[1])){alert("Parameter value must be in the range ["+at+"-"+aq+"]");return $(this)}}ak.slider((ao?"values":"value"),ar);al.removeClass("input")}}})})};var aa=this;aa.parent_div=$("<div/>").addClass("filter-row slider-row");var Z=$("<div/>").addClass("elt-label").appendTo(aa.parent_div),af=$("<span/>").addClass("slider-name").text(aa.name+" ").appendTo(Z),ab=$("<span/>").text(this.low+"-"+this.high),ac=$("<span/>").addClass("slider-value").appendTo(Z).append("[").append(ab).append("]");aa.values_span=ab;var ae=$("<div/>").addClass("slider").appendTo(aa.parent_div);aa.control_element=$("<div/>").attr("id",aa.name+"-filter-control").appendTo(ae);aa.control_element.slider({range:true,min:this.min,max:this.max,step:this.get_slider_step(this.min,this.max),values:[this.low,this.high],slide:function(ai,aj){aa.slide(ai,aj)},change:function(ai,aj){aa.control_element.slider("option","slide").call(aa.control_element,ai,aj)}});aa.slider=aa.control_element;aa.slider_label=ab;ad(ac,ab,aa.control_element);var ag=$("<div/>").addClass("display-controls").appendTo(aa.parent_div);this.transparency_icon=create_action_icon("Use filter for data transparency","layer-transparent",function(){if(aa.manager.alpha_filter!==aa){aa.manager.alpha_filter=aa;aa.manager.parent_div.find(".layer-transparent").removeClass("active").hide();aa.transparency_icon.addClass("active").show()}else{aa.manager.alpha_filter=null;aa.transparency_icon.removeClass("active")}aa.manager.track.request_draw(true,true)}).appendTo(ag).hide();this.height_icon=create_action_icon("Use filter for data height","arrow-resize-090",function(){if(aa.manager.height_filter!==aa){aa.manager.height_filter=aa;aa.manager.parent_div.find(".arrow-resize-090").removeClass("active").hide();aa.height_icon.addClass("active").show()}else{aa.manager.height_filter=null;aa.height_icon.removeClass("active")}aa.manager.track.request_draw(true,true)}).appendTo(ag).hide();aa.parent_div.hover(function(){aa.transparency_icon.show();aa.height_icon.show()},function(){if(aa.manager.alpha_filter!==aa){aa.transparency_icon.hide()}if(aa.manager.height_filter!==aa){aa.height_icon.hide()}});$("<div style='clear: both;'/>").appendTo(aa.parent_div)};o(Q.prototype,{to_dict:function(){var Z=f.prototype.to_dict.call(this);return o(Z,{type:"number",min:this.min,max:this.max,low:this.low,high:this.high})},copy:function(){return new Q({name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name})},get_slider_step:function(ab,Z){var aa=Z-ab;return(aa<=2?0.01:1)},slide:function(ab,ac){var aa=ac.values;this.values_span.text(aa[0]+"-"+aa[1]);this.low=aa[0];this.high=aa[1];var Z=this;setTimeout(function(){if(aa[0]===Z.low&&aa[1]===Z.high){Z.manager.track.request_draw(true,true)}},25)},applies_to:function(Z){if(Z.length>this.index){return true}return false},_keep_val:function(Z){return(isNaN(Z)||(Z>=this.low&&Z<=this.high))},keep:function(aa){if(!this.applies_to(aa)){return true}var ac=this;var ad=aa[this.index];if(ad instanceof Array){var ab=true;for(var Z=0;Z<ad.length;Z++){if(!this._keep_val(ad[Z])){ab=false;break}}return ab}else{return this._keep_val(aa[this.index])}},update_attrs:function(ac){var Z=false;if(!this.applies_to(ac)){return Z}var aa=ac[this.index];if(!(aa instanceof Array)){aa=[aa]}for(var ab=0;ab<aa.length;ab++){var ad=aa[ab];if(ad<this.min){this.min=Math.floor(ad);Z=true}if(ad>this.max){this.max=Math.ceil(ad);Z=true}}return Z},update_ui_elt:function(){if(this.min<this.max){this.parent_div.show()}else{this.parent_div.hide()}var aa=this.slider.slider("option","min"),Z=this.slider.slider("option","max");if(this.min<aa||this.max>Z){this.slider.slider("option","min",this.min);this.slider.slider("option","max",this.max);this.slider.slider("option","step",this.get_slider_step(this.min,this.max));this.slider.slider("option","values",[this.min,this.max])}}});var V=function(ab,ah){this.track=ab;this.alpha_filter=null;this.height_filter=null;this.filters=[];this.parent_div=$("<div/>").addClass("filters").hide();this.parent_div.bind("drag",function(aj){aj.stopPropagation()}).click(function(aj){aj.stopPropagation()}).bind("dblclick",function(aj){aj.stopPropagation()}).bind("keydown",function(aj){aj.stopPropagation()});if(ah&&"filters" in ah){var Z=("alpha_filter" in ah?ah.alpha_filter:null),ac=("height_filter" in ah?ah.height_filter:null),ae=ah.filters,aa;for(var af=0;af<ae.length;af++){if(ae[af].type==="number"){aa=new Q(ae[af]);this.add_filter(aa);if(aa.name===Z){this.alpha_filter=aa;aa.transparency_icon.addClass("active").show()}if(aa.name===ac){this.height_filter=aa;aa.height_icon.addClass("active").show()}}else{console.log("ERROR: unsupported filter: ",name,type)}}if("visible" in ah&&ah.visible){this.parent_div.show()}}if(this.filters.length!==0){var ai=$("<div/>").addClass("param-row").appendTo(this.parent_div);var ag=$("<input type='submit'/>").attr("value","Run on complete dataset").appendTo(ai);var ad=this;ag.click(function(){ad.run_on_dataset()})}};o(V.prototype,{show:function(){this.parent_div.show()},hide:function(){this.parent_div.hide()},toggle:function(){this.parent_div.toggle()},visible:function(){return this.parent_div.is(":visible")},to_dict:function(){var ac={},ab=[],aa;for(var Z=0;Z<this.filters.length;Z++){aa=this.filters[Z];ab.push(aa.to_dict())}ac.filters=ab;ac.alpha_filter=(this.alpha_filter?this.alpha_filter.name:null);ac.height_filter=(this.height_filter?this.height_filter.name:null);ac.visible=this.parent_div.is(":visible");return ac},copy:function(aa){var ab=new V(aa);for(var Z=0;Z<this.filters.length;Z++){ab.add_filter(this.filters[Z].copy())}return ab},add_filter:function(Z){Z.manager=this;this.parent_div.append(Z.parent_div);this.filters.push(Z)},remove_all:function(){this.filters=[];this.parent_div.children().remove()},init_filters:function(){for(var Z=0;Z<this.filters.length;Z++){var aa=this.filters[Z];aa.update_ui_elt()}},clear_filters:function(){for(var Z=0;Z<this.filters.length;Z++){var aa=this.filters[Z];aa.slider.slider("option","values",[aa.min,aa.max])}this.alpha_filter=null;this.height_filter=null;this.parent_div.find(".icon-button").hide()},run_on_dataset:function(){var af=function(aj,ah,ai){if(!(ah in aj)){aj[ah]=ai}return aj[ah]};var ae={},ag,Z;for(var ad=0;ad<this.filters.length;ad++){ag=this.filters[ad];if(ag.tool_id){if(ag.min!==ag.low){Z=af(ae,ag.tool_id,[]);Z[Z.length]=ag.tool_exp_name+" >= "+ag.low}if(ag.max!==ag.high){Z=af(ae,ag.tool_id,[]);Z[Z.length]=ag.tool_exp_name+" <= "+ag.high}}}var aa=[];for(var ac in ae){aa[aa.length]=[ac,ae[ac]]}(function ab(an,ak){var ai=ak[0],aj=ai[0],am=ai[1],al="("+am.join(") and (")+")",ah={cond:al,input:an,target_dataset_id:an,tool_id:aj},ak=ak.slice(1);$.getJSON(run_tool_url,ah,function(ao){if(ao.error){show_modal("Filter Dataset","Error running tool "+aj,{Close:hide_modal})}else{if(ak.length===0){show_modal("Filtering Dataset","Filter(s) are running on the complete dataset. Outputs are in dataset's history.",{Close:hide_modal})}else{ab(ao.dataset_id,ak)}}})})(this.track.dataset_id,aa)}});var z=function(Z,aa){I.Scaler.call(this,aa);this.filter=Z};z.prototype.gen_val=function(Z){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(Z[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var C=function(Z){this.track=Z.track;this.params=Z.params;this.values={};this.restore_values((Z.saved_values?Z.saved_values:{}));this.onchange=Z.onchange};o(C.prototype,{restore_values:function(Z){var aa=this;$.each(this.params,function(ab,ac){if(Z[ac.key]!==undefined){aa.values[ac.key]=Z[ac.key]}else{aa.values[ac.key]=ac.default_value}})},build_form:function(){var ac=this;var Z=$("<div />");var ab;function aa(ah,ad){for(var al=0;al<ah.length;al++){ab=ah[al];if(ab.hidden){continue}var af="param_"+al;var ap=ac.values[ab.key];var ar=$("<div class='form-row' />").appendTo(ad);ar.append($("<label />").attr("for",af).text(ab.label+":"));if(ab.type==="bool"){ar.append($('<input type="checkbox" />').attr("id",af).attr("name",af).attr("checked",ap))}else{if(ab.type==="text"){ar.append($('<input type="text"/>').attr("id",af).val(ap).click(function(){$(this).select()}))}else{if(ab.type==="select"){var an=$("<select />").attr("id",af);for(var aj=0;aj<ab.options.length;aj++){$("<option/>").text(ab.options[aj].label).attr("value",ab.options[aj].value).appendTo(an)}an.val(ap);ar.append(an)}else{if(ab.type==="color"){var aq=$("<div/>").appendTo(ar),am=$("<input />").attr("id",af).attr("name",af).val(ap).css("float","left").appendTo(aq).click(function(au){$(".bs-tooltip").removeClass("in");var at=$(this).siblings(".bs-tooltip").addClass("in");at.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(at).height()/2)+($(this).height()/2)}).show();at.click(function(av){av.stopPropagation()});$(document).bind("click.color-picker",function(){at.hide();$(document).unbind("click.color-picker")});au.stopPropagation()}),ak=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(aq).attr("title","Set new random color").tooltip(),ao=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(aq).hide(),ag=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ao),ae=$("<div class='tooltip-arrow'></div>").appendTo(ao),ai=$.farbtastic(ag,{width:100,height:100,callback:am,color:ap});aq.append($("<div/>").css("clear","both"));(function(at){ak.click(function(){at.setColor(get_random_color())})})(ai)}else{ar.append($("<input />").attr("id",af).attr("name",af).val(ap))}}}}if(ab.help){ar.append($("<div class='help'/>").text(ab.help))}}}aa(this.params,Z);return Z},update_from_form:function(Z){var ab=this;var aa=false;$.each(this.params,function(ac,ae){if(!ae.hidden){var af="param_"+ac;var ad=Z.find("#"+af).val();if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad)}else{if(ae.type==="bool"){ad=Z.find("#"+af).is(":checked")}}}if(ad!==ab.values[ae.key]){ab.values[ae.key]=ad;aa=true}}});if(aa){this.onchange();this.track.changed()}}});var b=function(Z,ad,ab,aa,ac){this.track=Z;this.region=ad;this.low=ad.get("start");this.high=ad.get("end");this.resolution=ab;this.html_elt=$("<div class='track-tile'/>").append(aa).height($(aa).attr("height"));this.data=ac;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(Z,ae,ab,aa,ac,ad){b.call(this,Z,ae,ab,aa,ac);this.max_val=ad};o(j.prototype,b.prototype);var L=function(ac,ak,ad,ab,af,am,ag,an,aa,aj){b.call(this,ac,ak,ad,ab,af);this.mode=ag;this.all_slotted=aa;this.feature_mapper=aj;this.has_icons=false;if(an){this.has_icons=true;var ah=this;ab=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:A-1,width:ab.width}).prependTo(this.html_elt);var ai=new GenomeRegion({chrom:ac.view.chrom,start:this.low,end:this.high}),al=af.length,ae=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+al+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),Z=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+al+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ae.click(function(){ah.stale=true;ac.data_manager.get_more_data(ai,ac.mode,ah.resolution,{},ac.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();ac.request_draw(true)}).dblclick(function(ao){ao.stopPropagation()});Z.click(function(){ah.stale=true;ac.data_manager.get_more_data(ai,ac.mode,ah.resolution,{},ac.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();ac.request_draw(true)}).dblclick(function(ao){ao.stopPropagation()})}};o(L.prototype,b.prototype);L.prototype.predisplay_actions=function(){var aa=this,Z={};if(aa.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(al){if(!this.hovered){return}var ag=$(this).offset(),ak=al.pageX-ag.left,aj=al.pageY-ag.top,ap=aa.feature_mapper.get_feature_data(ak,aj),ah=(ap?ap[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ah||$(this).attr("id")!==ah.toString()){$(this).remove()}});if(ap){var ac=Z[ah];if(!ac){var ah=ap[0],am={name:ap[3],start:ap[1],end:ap[2],strand:ap[4]},af=aa.track.filters_manager.filters,ae;for(var ai=0;ai<af.length;ai++){ae=af[ai];am[ae.name]=ap[ae.index]}var ac=$("<div/>").attr("id",ah).addClass("feature-popup"),aq=$("<table/>"),ao,an,ar;for(ao in am){an=am[ao];ar=$("<tr/>").appendTo(aq);$("<th/>").appendTo(ar).text(ao);$("<td/>").attr("align","left").appendTo(ar).text(typeof(an)==="number"?U(an,2):an)}ac.append($("<div class='feature-popup-inner'>").append(aq));Z[ah]=ac}ac.appendTo($(this).parents(".track-content").children(".overlay"));var ad=ak+parseInt(aa.html_elt.css("left"))-ac.width()/2,ab=aj+parseInt(aa.html_elt.css("top"))+7;ac.css("left",ad+"px").css("top",ab+"px")}else{if(!al.isPropagationStopped()){al.stopPropagation();$(this).siblings().each(function(){$(this).trigger(al)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var h=function(aa,Z,ab){o(ab,{drag_handle_class:"draghandle"});p.call(this,aa,Z,ab);this.dataset=new Dataset({id:ab.dataset_id,hda_ldda:ab.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ab?ab.data_query_wait:H);this.data_manager=("data_manager" in ab?ab.data_manager:new GenomeDataManager({dataset:this.dataset,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 ab)||ab.resize){this.add_resize_handle()}}};o(h.prototype,p.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},p.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(Z){Z.view.set_overview(Z)}},p.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(Z){if(Z.filters_manager.visible()){Z.filters_manager.clear_filters()}else{Z.filters_manager.init_filters()}Z.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(Z){Z.dynamic_tool_div.toggle();if(Z.dynamic_tool_div.is(":visible")){Z.set_name(Z.name+Z.tool_region_and_parameters_str())}else{Z.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(Z){var ac='<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>',ab=_.template(ac,{track:Z});var ae=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},aa=function(){var ag=$('select[name="regions"] option:selected').val(),ai,af=new GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ah=_.map($(".bookmark"),function(aj){return new GenomeRegion({from_str:$(aj).children(".position").text()})});if(ag==="cur"){ai=[af]}else{if(ag==="bookmarks"){ai=ah}else{ai=[af].concat(ah)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:Z.dataset_id,hda_ldda:Z.hda_ldda,regions:JSON.stringify(new Backbone.Collection(ai).toJSON())})},ad=function(af){if((af.keyCode||af.which)===27){ae()}else{if((af.keyCode||af.which)===13){aa()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ab,{No:ae,Yes:aa})}},p.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&p.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 Z=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(Z)}this.name_div=$("<div/>").addClass("track-name").appendTo(Z).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return Z},on_resize:function(){},add_resize_handle:function(){var Z=this;var ac=false;var ab=false;var aa=$("<div class='track-resize'>");$(Z.container_div).hover(function(){if(Z.content_visible){ac=true;aa.show()}},function(){ac=false;if(!ab){aa.hide()}});aa.hide().bind("dragstart",function(ad,ae){ab=true;ae.original_height=$(Z.content_div).height()}).bind("drag",function(ae,af){var ad=Math.min(Math.max(af.original_height+af.deltaY,Z.min_height_px),Z.max_height_px);$(Z.tiles_div).css("height",ad);Z.visible_height_px=(Z.max_height_px===ad?0:ad);Z.on_resize()}).bind("dragend",function(ad,ae){Z.tile_cache.clear();ab=false;if(!ac){aa.hide()}Z.config.values.height=Z.visible_height_px;Z.changed()}).appendTo(Z.container_div)},set_display_modes:function(ac,af){this.display_modes=ac;this.mode=(af?af:(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 aa=this,ad={};for(var ab=0,Z=aa.display_modes.length;ab<Z;ab++){var ae=aa.display_modes[ab];ad[ae]=function(ag){return function(){aa.change_mode(ag);aa.icons_div.show();aa.container_div.mouseleave(function(){aa.icons_div.hide()})}}(ae)}make_popupmenu(this.action_icons.mode_icon,ad)},build_action_icons:function(){p.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 y){return"ReferenceTrack"}else{if(this instanceof i){return"LineTrack"}else{if(this instanceof R){return"ReadTrack"}else{if(this instanceof O){return"VcfTrack"}else{if(this instanceof g){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(){var aa=this;aa.enabled=false;aa.tile_cache.clear();aa.data_manager.clear();aa.content_div.css("height","auto");aa.tiles_div.children().remove();aa.container_div.removeClass("nodata error pending");if(!aa.dataset_id){return}var Z=$.Deferred(),ab={hda_ldda:aa.hda_ldda,data_type:this.dataset_check_type,chrom:aa.view.chrom};$.getJSON(this.dataset.url(),ab,function(ac){if(!ac||ac==="error"||ac.kind==="error"){aa.container_div.addClass("error");aa.tiles_div.text(n);if(ac.message){var ad=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ac.message+"</pre>",{Close:hide_modal})});aa.tiles_div.append(ad)}}else{if(ac==="no converter"){aa.container_div.addClass("error");aa.tiles_div.text(G)}else{if(ac==="no data"||(ac.data!==undefined&&(ac.data===null||ac.data.length===0))){aa.container_div.addClass("nodata");aa.tiles_div.text(B)}else{if(ac==="pending"){aa.container_div.addClass("pending");aa.tiles_div.html(t);setTimeout(function(){aa.init()},aa.data_query_wait)}else{if(ac==="data"||ac.status==="data"){if(ac.valid_chroms){aa.valid_chroms=ac.valid_chroms;aa.update_icons()}aa.tiles_div.text(T);if(aa.view.chrom){aa.tiles_div.text("");aa.tiles_div.css("height",aa.visible_height_px+"px");aa.enabled=true;$.when(aa.predraw_init()).done(function(){Z.resolve();aa.container_div.removeClass("nodata error pending");aa.request_draw()})}else{Z.resolve()}}}}}}});this.update_icons();return Z},predraw_init:function(){},get_drawables:function(){return this}});var J=function(ab,aa,ac){h.call(this,ab,aa,ac);var Z=this;l(Z.container_div,Z.drag_handle_class,".group",Z);this.filters_manager=new V(this,("filters" in ac?ac.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in ac&&ac.tool?new q(this,ac.tool,ac.tool_state):null);this.tile_cache=new Cache(N);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(ac.mode){this.change_mode(ac.mode)}};o(J.prototype,p.prototype,h.prototype,{action_icons_def:h.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(Z){$(".bs-tooltip").remove();Z.slotters[Z.view.resolution_px_b].max_rows*=2;Z.request_draw(true)},hide:true}]),copy:function(Z){var aa=this.to_dict();o(aa,{data_manager:this.data_manager});var ab=new this.constructor(this.view,Z,aa);ab.change_mode(this.mode);ab.enabled=this.enabled;return ab},set_filters_manager:function(Z){this.filters_manager=Z;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(aa){var Z=this;Z.mode=aa;Z.config.values.mode=aa;Z.tile_cache.clear();Z.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+Z.mode+")");return Z},update_icons:function(){var Z=this;if(Z.filters_available){Z.action_icons.filters_icon.show()}else{Z.action_icons.filters_icon.hide()}if(Z.tool){Z.action_icons.tools_icon.show();Z.action_icons.param_space_viz_icon.show()}else{Z.action_icons.tools_icon.hide();Z.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(aa,ab,Z){return aa+"_"+ab+"_"+Z},request_draw:function(aa,Z){this.view.request_redraw(false,aa,Z,this)},before_draw:function(){},_draw:function(aa,ak){if(!this.can_draw()){return}var ai=this.view.low,ae=this.view.high,ag=ae-ai,ab=this.view.container.width(),am=this.view.resolution_px_b,ad=this.view.resolution_b_px;if(this.is_overview){ai=this.view.max_low;ae=this.view.max_high;ad=(view.max_high-view.max_low)/ab;am=1/ad}this.before_draw();this.tiles_div.children().addClass("remove");var Z=Math.floor(ai/(ad*P)),ah=true,al=[],af=function(an){return(an&&"track" in an)};while((Z*P*ad)<ae){var aj=this.draw_helper(aa,ab,Z,ad,this.tiles_div,am);if(af(aj)){al.push(aj)}else{ah=false}Z+=1}if(!ak){this.tiles_div.children(".remove").removeClass("remove").remove()}var ac=this;if(ah){this.tiles_div.children(".remove").remove();ac.postdraw_actions(al,ab,am,ak)}},postdraw_actions:function(ab,ac,ae,Z){var ad=false;for(var aa=0;aa<ab.length;aa++){if(ab[aa].has_icons){ad=true;break}}if(ad){for(var aa=0;aa<ab.length;aa++){tile=ab[aa];if(!tile.has_icons){tile.html_elt.css("padding-top",A)}}}},draw_helper:function(Z,al,aq,ao,ae,af,am){var ak=this,au=this._gen_tile_cache_key(al,af,aq),ac=this._get_tile_bounds(aq,ao);if(!am){am={}}var at=(Z?undefined:ak.tile_cache.get_elt(au));if(at){ak.show_tile(at,ae,af);return at}var ai=true;var ap=ak.data_manager.get_data(ac,ak.mode,ao,ak.data_url_extra_params);if(is_deferred(ap)){ai=false}var ag;if(view.reference_track&&af>view.canvas_manager.char_width_px){ag=view.reference_track.data_manager.get_data(ac,ak.mode,ao,view.reference_track.data_url_extra_params);if(is_deferred(ag)){ai=false}}if(ai){o(ap,am.more_tile_data);var ah=ak.mode;if(ah==="Auto"){ah=ak.get_mode(ap);ak.update_auto_mode(ah)}var ab=ak.view.canvas_manager.new_canvas(),ar=ac.get("start"),aa=ac.get("end"),al=Math.ceil((aa-ar)*af)+ak.left_offset,aj=ak.get_canvas_height(ap,ah,af,al);ab.width=al;ab.height=aj;var an=ab.getContext("2d");an.translate(this.left_offset,0);var at=ak.draw_tile(ap,an,ah,ao,ac,af,ag);if(at!==undefined){ak.tile_cache.set_elt(au,at);ak.show_tile(at,ae,af)}return at}var ad=$.Deferred();$.when(ap,ag).then(function(){view.request_redraw(false,false,false,ak);ad.resolve()});return ad},get_canvas_height:function(Z,ab,ac,aa){return this.visible_height_px},draw_tile:function(Z,aa,ae,ac,ad,af,ab){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ab,ad,ae){var aa=this,Z=ab.html_elt;ab.predisplay_actions();var ac=(ab.low-(this.is_overview?this.view.max_low:this.view.low))*ae;if(this.left_offset){ac-=this.left_offset}Z.css({position:"absolute",top:0,left:ac});if(Z.hasClass("remove")){Z.removeClass("remove")}else{ad.append(Z)}aa.after_show_tile(ab)},after_show_tile:function(Z){this.max_height_px=Math.max(this.max_height_px,Z.html_elt.height());Z.html_elt.parent().children().css("height",this.max_height_px+"px");var aa=this.max_height_px;if(this.visible_height_px!==0){aa=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",aa+"px")},_get_tile_bounds:function(Z,aa){var ac=Math.floor(Z*P*aa),ad=Math.ceil(P*aa),ab=(ac+ad<=this.view.max_high?ac+ad:this.view.max_high);return new GenomeRegion({chrom:this.view.chrom,start:ac,end:ab})},tool_region_and_parameters_str:function(ab,Z,ac){var aa=this,ad=(ab!==undefined&&Z!==undefined&&ac!==undefined?ab+":"+Z+"-"+ac:"all");return" - region=["+ad+"], parameters=["+aa.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(Z,aa){return true},can_subset:function(Z){return false},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(ab,ac,ae,Z){var aa=this;aa.normal_postdraw_actions(ab,ac,ae,Z);aa.dataset_state_url=converted_datasets_state_url;aa.data_query_wait=H;var ad=new ServerStateDeferred({url:aa.dataset_state_url,url_params:{dataset_id:aa.dataset_id,hda_ldda:aa.hda_ldda},interval:aa.data_query_wait,success_fn:function(af){return af!=="pending"}});$.when(ad.go()).then(function(){aa.data_manager.set("data_type","data");aa.dataset_check_type="converted_datasets_state";this.data_query_wait=5000});aa.postdraw_actions=aa.normal_postdraw_actions}}});var W=function(aa,Z){var ab={resize:false};h.call(this,aa,Z,ab);this.container_div.addClass("label-track")};o(W.prototype,h.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ab=this.view,ac=ab.high-ab.low,af=Math.floor(Math.pow(10,Math.floor(Math.log(ac)/Math.log(10)))),Z=Math.floor(ab.low/af)*af,ad=this.view.container.width(),aa=$("<div style='position: relative; height: 1.3em;'></div>");while(Z<ab.high){var ae=(Z-ab.low)/ac*ad;aa.append($("<div class='label'>"+commatize(Z)+"</div>").css({position:"absolute",left:ae-1}));Z+=af}this.content_div.children(":first").remove();this.content_div.append(aa)}});var g=function(aa,Z,ad){J.call(this,aa,Z,ad);this.drawables=[];this.left_offset=0;if("drawables" in ad){var ac;for(var ab=0;ab<ad.drawables.length;ab++){ac=ad.drawables[ab];this.drawables[ab]=object_from_template(ac,aa,null);if(ac.left_offset>this.left_offset){this.left_offset=ac.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};o(g.prototype,J.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(Z){$(".bs-tooltip").remove();Z.show_group()}}].concat(J.prototype.action_icons_def),to_dict:w.prototype.to_dict,add_drawable:w.prototype.add_drawable,unpack_drawables:w.prototype.unpack_drawables,change_mode:function(Z){J.prototype.change_mode.call(this,Z);for(var aa=0;aa<this.drawables.length;aa++){this.drawables[aa].change_mode(Z)}},init:function(){var ab=[];for(var aa=0;aa<this.drawables.length;aa++){ab.push(this.drawables[aa].init())}var Z=this;$.when.apply($,ab).then(function(){Z.enabled=true;Z.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:p.prototype.can_draw,draw_helper:function(aa,ap,aw,at,ah,aj,aq){var ao=this,aA=this._gen_tile_cache_key(ap,aj,aw),ae=this._get_tile_bounds(aw,at);if(!aq){aq={}}var az=(aa?undefined:ao.tile_cache.get_elt(aA));if(az){ao.show_tile(az,ah,aj);return az}var ai=[],ao,am=true,au,ak;for(var av=0;av<this.drawables.length;av++){ao=this.drawables[av];au=ao.data_manager.get_data(ae,ao.mode,at,ao.data_url_extra_params);if(is_deferred(au)){am=false}ai.push(au);ak=null;if(view.reference_track&&aj>view.canvas_manager.char_width_px){ak=view.reference_track.data_manager.get_data(ae,ao.mode,at,view.reference_track.data_url_extra_params);if(is_deferred(ak)){am=false}}ai.push(ak)}if(am){o(au,aq.more_tile_data);this.tile_predraw_init();var ad=ao.view.canvas_manager.new_canvas(),af=ao._get_tile_bounds(aw,at),ax=ae.get("start"),ab=ae.get("end"),ay=0,ap=Math.ceil((ab-ax)*aj)+this.left_offset,an=0,ac=[],av;var Z=0;for(av=0;av<this.drawables.length;av++,ay+=2){ao=this.drawables[av];au=ai[ay];var al=ao.mode;if(al==="Auto"){al=ao.get_mode(au);ao.update_auto_mode(al)}ac.push(al);Z=ao.get_canvas_height(au,al,aj,ap);if(Z>an){an=Z}}ad.width=ap;ad.height=(aq.height?aq.height:an);ay=0;var ar=ad.getContext("2d");ar.translate(this.left_offset,0);ar.globalAlpha=0.5;ar.globalCompositeOperation="source-over";for(av=0;av<this.drawables.length;av++,ay+=2){ao=this.drawables[av];au=ai[ay];ak=ai[ay+1];az=ao.draw_tile(au,ar,ac[av],at,ae,aj,ak)}this.tile_cache.set_elt(aA,az);this.show_tile(az,ah,aj);return az}var ag=$.Deferred(),ao=this;$.when.apply($,ai).then(function(){view.request_redraw(false,false,false,ao);ag.resolve()});return ag},show_group:function(){var ac=new M(this.view,this.container,{name:this.name}),Z;for(var ab=0;ab<this.drawables.length;ab++){Z=this.drawables[ab];Z.update_icons();ac.add_drawable(Z);Z.container=ac;ac.content_div.append(Z.container_div)}var aa=this.container.replace_drawable(this,ac,true);ac.request_draw()},tile_predraw_init:function(){var ac=Number.MAX_VALUE,Z=-ac,aa;for(var ab=0;ab<this.drawables.length;ab++){aa=this.drawables[ab];if(aa instanceof i){if(aa.prefs.min_value<ac){ac=aa.prefs.min_value}if(aa.prefs.max_value>Z){Z=aa.prefs.max_value}}}for(var ab=0;ab<this.drawables.length;ab++){aa=this.drawables[ab];aa.prefs.min_value=ac;aa.prefs.max_value=Z}},postdraw_actions:function(ab,ae,ag,aa){J.prototype.postdraw_actions.call(this,ab,ae,ag,aa);var ad=-1;for(var ac=0;ac<ab.length;ac++){var Z=ab[ac].html_elt.find("canvas").height();if(Z>ad){ad=Z}}for(var ac=0;ac<ab.length;ac++){var af=ab[ac];if(af.html_elt.find("canvas").height()!==ad){this.draw_helper(true,ae,af.index,af.resolution,af.html_elt.parent(),ag,{height:ad});af.html_elt.remove()}}}});var y=function(Z){J.call(this,Z,{content_div:Z.top_labeltrack},{resize:false});Z.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=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};o(y.prototype,p.prototype,J.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:p.prototype.can_draw,draw_helper:function(ad,ab,Z,aa,ae,af,ac){if(af>this.view.canvas_manager.char_width_px){return J.prototype.draw_helper.call(this,ad,ab,Z,aa,ae,af,ac)}else{this.hide_contents();return null}},draw_tile:function(ah,ai,ad,ac,af,aj){var ab=this;if(aj>this.view.canvas_manager.char_width_px){if(ah.data===null){this.hide_contents();return}var aa=ai.canvas;ai.font=ai.canvas.manager.default_font;ai.textAlign="center";ah=ah.data;for(var ae=0,ag=ah.length;ae<ag;ae++){var Z=Math.floor(ae*aj);ai.fillText(ah[ae],Z,10)}this.show_contents();return new b(ab,af,ac,aa,ah)}this.hide_contents()}});var i=function(ab,aa,ac){var Z=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";J.call(this,ab,aa,ac);this.hda_ldda=ac.hda_ldda;this.dataset_id=ac.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value: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:ac.prefs,onchange:function(){Z.set_name(Z.prefs.name);Z.vertical_range=Z.prefs.max_value-Z.prefs.min_value;Z.set_min_value(Z.prefs.min_value);Z.set_max_value(Z.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};o(i.prototype,p.prototype,J.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(Z){this.prefs.min_value=Z;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(Z){this.prefs.max_value=Z;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var Z=this;Z.vertical_range=undefined;return $.getJSON(Z.dataset.url(),{data_type:"data",stats:true,chrom:Z.view.chrom,low:0,high:Z.view.max_high,hda_ldda:Z.hda_ldda,dataset_id:Z.dataset_id},function(aa){Z.container_div.addClass("line-track");var ad=aa.data;if(isNaN(parseFloat(Z.prefs.min_value))||isNaN(parseFloat(Z.prefs.max_value))){var ab=ad.min,af=ad.max;ab=Math.floor(Math.min(0,Math.max(ab,ad.mean-2*ad.sd)));af=Math.ceil(Math.max(0,Math.min(af,ad.mean+2*ad.sd)));Z.prefs.min_value=ab;Z.prefs.max_value=af;$("#track_"+Z.dataset_id+"_minval").val(Z.prefs.min_value);$("#track_"+Z.dataset_id+"_maxval").val(Z.prefs.max_value)}Z.vertical_range=Z.prefs.max_value-Z.prefs.min_value;Z.total_frequency=ad.total_frequency;Z.container_div.find(".yaxislabel").remove();var ae=$("<div/>").text(U(Z.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(ag){$(".bs-tooltip").remove();var ag=parseFloat(ag);if(!isNaN(ag)){Z.set_min_value(ag)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+Z.dataset_id+"_minval").prependTo(Z.container_div),ac=$("<div/>").text(U(Z.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(ag){$(".bs-tooltip").remove();var ag=parseFloat(ag);if(!isNaN(ag)){Z.set_max_value(ag)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+Z.dataset_id+"_maxval").prependTo(Z.container_div)})},draw_tile:function(ai,ag,ab,aa,ad,ah){var Z=ag.canvas,ac=ad.get("start"),af=ad.get("end"),ae=new I.LinePainter(ai.data,ac,af,this.prefs,ab);ae.draw(ag,Z.width,Z.height,ah);return new b(this,ad,aa,Z,ai.data)},can_subset:function(Z){return false}});var r=function(ab,aa,ac){var Z=this;this.display_modes=["Heatmap"];this.mode="Heatmap";J.call(this,ab,aa,ac);this.hda_ldda=ac.hda_ldda;this.dataset_id=ac.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{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:ac.prefs,onchange:function(){Z.set_name(Z.prefs.name);Z.vertical_range=Z.prefs.max_value-Z.prefs.min_value;Z.set_min_value(Z.prefs.min_value);Z.set_max_value(Z.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};o(r.prototype,p.prototype,J.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(Z){this.prefs.min_value=Z;this.tile_cache.clear();this.request_draw()},set_max_value:function(Z){this.prefs.max_value=Z;this.tile_cache.clear();this.request_draw()},draw_tile:function(aj,ah,ae,ac,aa,ai){var ab=ah.canvas,Z=this._get_tile_bounds(aa,ac),ad=Z[0],ag=Z[1],af=new I.DiagonalHeatmapPainter(aj.data,ad,ag,this.prefs,ae);af.draw(ah,ab.width,ab.height,ai);return new b(this,aa,ac,ab,aj.data)}});var c=function(ac,ab,ae){var aa=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];J.call(this,ac,ab,ae);var ad=get_random_color(),Z=get_random_color([ad,"#ffffff"]);this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ad},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:Z},{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:"histogram_max",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:ae.prefs,onchange:function(){aa.set_name(aa.prefs.name);aa.tile_cache.clear();aa.set_painter_from_config();aa.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ae.hda_ldda;this.dataset_id=ae.dataset_id;this.original_dataset_id=ae.dataset_id;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()};o(c.prototype,p.prototype,J.prototype,{set_dataset:function(Z){this.dataset_id=Z.get("id");this.hda_ldda=Z.get("hda_ldda");this.dataset=Z;this.data_manager.set("dataset",Z)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=I.ArcLinkedFeaturePainter}else{this.painter=I.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ao,aj,ae,ad){J.prototype.postdraw_actions.call(this,ao,ad);var ai=this,al;if(ai.mode==="Coverage"){var aa=-1;for(al=0;al<ao.length;al++){var ak=ao[al].max_val;if(ak>aa){aa=ak}}for(al=0;al<ao.length;al++){var aq=ao[al];if(aq.max_val!==aa){aq.html_elt.remove();ai.draw_helper(true,aj,aq.index,aq.resolution,aq.html_elt.parent(),ae,{more_tile_data:{max:aa}})}}}if(ai.filters_manager){var af=ai.filters_manager.filters;for(var an=0;an<af.length;an++){af[an].update_ui_elt()}var ap=false,Z,ag;for(al=0;al<ao.length;al++){if(ao[al].data.length){Z=ao[al].data[0];for(var an=0;an<af.length;an++){ag=af[an];if(ag.applies_to(Z)&&ag.min!==ag.max){ap=true;break}}}}if(ai.filters_available!==ap){ai.filters_available=ap;if(!ai.filters_available){ai.filters_manager.hide()}ai.update_icons()}}this.container_div.find(".yaxislabel").remove();var ac=ao[0];if(ac instanceof j){var ah=(this.prefs.histogram_max?this.prefs.histogram_max:ac.max_val),ab=$("<div/>").text(ah).make_text_editable({num_cols:12,on_finish:function(ar){$(".bs-tooltip").remove();var ar=parseFloat(ar);ai.prefs.histogram_max=(!isNaN(ar)?ar:null);ai.tile_cache.clear();ai.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ab)}if(ac instanceof L){var am=true;for(al=0;al<ao.length;al++){if(!ao[al].all_slotted){am=false;break}}if(!am){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(Z){var Z;if(this.mode==="Auto"){if(Z==="no_detail"){Z="feature spans"}else{if(Z==="summary_tree"){Z="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+Z+")")}},incremental_slots:function(ad,Z,ac){var aa=this.view.canvas_manager.dummy_context,ab=this.slotters[ad];if(!ab||(ab.mode!==ac)){ab=new (s.FeatureSlotter)(ad,ac,x,function(ae){return aa.measureText(ae)});this.slotters[ad]=ab}return ab.slot_features(Z)},get_mode:function(Z){if(Z.dataset_type==="summary_tree"){mode="summary_tree"}else{if(Z.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>F){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(Z,ad,ae,aa){if(ad==="summary_tree"||ad==="Coverage"){return this.summary_draw_height}else{var ac=this.incremental_slots(ae,Z.data,ad);var ab=new (this.painter)(null,null,null,this.prefs,ad);return Math.max(Y,ab.get_required_height(ac,aa))}},draw_tile:function(aj,an,al,ao,ac,ag,ab){var am=this,aa=an.canvas,av=ac.get("start"),Z=ac.get("end"),ad=this.left_offset;if(al==="summary_tree"||al==="Coverage"){var ax=new I.SummaryTreePainter(aj,av,Z,this.prefs);ax.draw(an,aa.width,aa.height,ag);return new j(am,ac,ao,aa,aj.data,aj.max)}var af=[],ak=this.slotters[ag].slots;all_slotted=true;if(aj.data){var ah=this.filters_manager.filters;for(var ap=0,ar=aj.data.length;ap<ar;ap++){var ae=aj.data[ap];var aq=false;var ai;for(var au=0,az=ah.length;au<az;au++){ai=ah[au];ai.update_attrs(ae);if(!ai.keep(ae)){aq=true;break}}if(!aq){af.push(ae);if(!(ae[0] in ak)){all_slotted=false}}}}var ay=(this.filters_manager.alpha_filter?new z(this.filters_manager.alpha_filter):null);var aw=(this.filters_manager.height_filter?new z(this.filters_manager.height_filter):null);var ax=new (this.painter)(af,av,Z,this.prefs,al,ay,aw,ab);var at=null;an.fillStyle=this.prefs.block_color;an.font=an.canvas.manager.default_font;an.textAlign="right";if(aj.data){at=ax.draw(an,aa.width,aa.height,ag,ak);at.translation=-ad}return new L(am,ac,ao,aa,aj.data,ag,al,aj.message,all_slotted,at)},data_and_mode_compatible:function(Z,aa){if(aa==="Auto"){return true}else{if(aa==="Coverage"){return Z.dataset_type==="summary_tree"}else{if(Z.extra_info==="no_detail"||Z.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(Z){if(Z.dataset_type==="summary_tree"||Z.message||Z.extra_info==="no_detail"){return false}return true}});var O=function(aa,Z,ab){c.call(this,aa,Z,ab);this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ab.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=I.ReadPainter};o(O.prototype,p.prototype,J.prototype,c.prototype);var R=function(ab,aa,ad){c.call(this,ab,aa,ad);var ac=get_random_color(),Z=get_random_color([ac,"#ffffff"]);this.config=new C({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:ac},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:Z},{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:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ad.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=I.ReadPainter;this.update_icons()};o(R.prototype,p.prototype,J.prototype,c.prototype);S.View=X;S.DrawableGroup=M;S.LineTrack=i;S.FeatureTrack=c;S.DiagonalHeatmapTrack=r;S.ReadTrack=R;S.VcfTrack=O;S.CompositeTrack=g};var slotting_module=function(c,b){var e=c("class").extend;var d=2,a=5;b.FeatureSlotter=function(i,h,f,g){this.slots={};this.start_end_dct={};this.w_scale=i;this.mode=h;this.include_label=(h==="Pack");this.max_rows=f;this.measureText=g};e(b.FeatureSlotter.prototype,{slot_features:function(m){var p=this.w_scale,h=this.start_end_dct,x=[],z=[],n=0,y=this.max_rows;for(var v=0,w=m.length;v<w;v++){var k=m[v],o=k[0];if(this.slots[o]!==undefined){n=Math.max(n,this.slots[o]);z.push(this.slots[o])}else{x.push(v)}}var q=function(E,F){for(var D=0;D<=y;D++){var B=false,G=h[D];if(G!==undefined){for(var A=0,C=G.length;A<C;A++){var i=G[A];if(F>i[0]&&E<i[1]){B=true;break}}}if(!B){return D}}return -1};for(var v=0,w=x.length;v<w;v++){var k=m[x[v]],o=k[0],t=k[1],f=k[2],r=k[3],g=Math.floor(t*p),l=Math.ceil(f*p),u=this.measureText(r).width,j;if(r!==undefined&&this.include_label){u+=(d+a);if(g-u>=0){g-=u;j="left"}else{l+=u;j="right"}}var s=q(g,l);if(s>=0){if(h[s]===undefined){h[s]=[]}h[s].push([g,l]);this.slots[o]=s;n=Math.max(n,s)}}return n+1}})};var painters_module=function(require,exports){var extend=require("class").extend;var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var SummaryTreePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode)};SummaryTreePainter.prototype.default_prefs={show_counts:false};SummaryTreePainter.prototype.draw=function(ctx,width,height,w_scale){var view_start=this.view_start,points=this.data.data,max=(this.prefs.histogram_max?this.prefs.histogram_max:this.data.max),base_y=height;delta_x_px=Math.ceil(this.data.delta*w_scale);ctx.save();for(var i=0,len=points.length;i<len;i++){var x=Math.floor((points[i][0]-view_start)*w_scale);var y=points[i][1];if(!y){continue}var y_px=y/max*height;if(y!==0&&y_px<1){y_px=1}ctx.fillStyle=this.prefs.block_color;ctx.fillRect(x,base_y-y_px,delta_x_px,y_px);var text_padding_req_x=4;if(this.prefs.show_counts&&(ctx.measureText(y).width+text_padding_req_x)<delta_x_px){ctx.fillStyle=this.prefs.label_color;ctx.textAlign="center";ctx.fillText(y,x+(delta_x_px/2),10)}}ctx.restore()};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][1])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][1])}this.prefs.max_value=max_value}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var pref_color=parseInt(this.prefs.color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=this.prefs.color;x_scaled=Math.round((data[i][0]-view_start-1)*w_scale);y=data[i][1];var top_overflow=false,bot_overflow=false;if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=this.prefs.color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler())};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)+this.get_bottom_padding(width)},get_top_padding:function(width){return 0},get_bottom_padding:function(width){return Math.max(Math.round(this.get_row_height()/2),5)},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords;for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((feature_start<view_end&&feature_end>view_start)&&(this.mode==="Dense"||slot!==null)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1])}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return feature_mapper},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){console.log("WARNING: Unimplemented function.");return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2]-1,feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low)*w_scale))),draw_start=f_start,draw_end=f_end,y_center=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_center+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_center+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_center+1,f_end-f_start,thick_height)}}else{var cur_y_center,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_center=y_center+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_center=y_center;cur_height=thick_height}else{cur_y_center+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_center,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-1-tile_low)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_center+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_center+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_center+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_center)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_center+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_center+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_center+8);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_center+8);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null)};extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},draw_read:function(ctx,mode,w_scale,y_center,tile_low,tile_high,feature_start,cigar,strand,orig_seq){ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=0,char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.block_color:this.prefs.reverse_strand_color);var draw_last=[];if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){gap=Math.round(w_scale/2)}if(!cigar){cigar=[[0,orig_seq.length]]}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];if(cig_op==="H"||cig_op==="S"){base_offset-=cig_len}var seq_start=(feature_start-1)+base_offset,s_start=Math.floor(Math.max(0,(seq_start-tile_low)*w_scale)),s_end=Math.floor(Math.max(0,(seq_start+cig_len-tile_low)*w_scale));if(s_start===s_end){s_end+=1}switch(cig_op){case"H":break;case"S":case"M":case"=":if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=orig_seq.slice(seq_offset,seq_offset+cig_len);if(gap>0){ctx.fillStyle=block_color;ctx.fillRect(s_start-gap,y_center+1,s_end-s_start,9);ctx.fillStyle=CONNECTOR_COLOR;for(var c=0,str_len=seq.length;c<str_len;c++){if(this.prefs.show_differences){if(this.ref_seq){var ref_char=this.ref_seq[seq_start-tile_low+c];if(!ref_char||ref_char.toLowerCase()===seq[c].toLowerCase()){continue}}else{continue}}if(seq_start+c>=tile_low&&seq_start+c<=tile_high){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start,y_center+9)}}}else{ctx.fillStyle=block_color;ctx.fillRect(s_start,y_center+4,s_end-s_start,SQUISH_FEATURE_HEIGHT)}}seq_offset+=cig_len;base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start-gap,y_center+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":ctx.fillStyle="red";ctx.fillRect(s_start-gap,y_center+4,s_end-s_start,3);base_offset+=cig_len;break;case"P":break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=orig_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_center-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_center+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_center)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_center+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_center+9]})}else{}}}seq_offset+=cig_len;break;case"X":seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(0,(feature_start-tile_low)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low)*w_scale))),y_center=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color,gap=0;if((mode==="Pack"||this.mode==="Auto")&&w_scale>ctx.canvas.manager.char_width_px){var gap=Math.round(w_scale/2)}if(feature[5] instanceof Array){var b1_start=Math.floor(Math.max(0,(feature[4][0]-tile_low)*w_scale)),b1_end=Math.ceil(Math.min(width,Math.max(0,(feature[4][1]-tile_low)*w_scale))),b2_start=Math.floor(Math.max(0,(feature[5][0]-tile_low)*w_scale)),b2_end=Math.ceil(Math.min(width,Math.max(0,(feature[5][1]-tile_low)*w_scale))),connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end-gap,y_center+5,b2_start-gap,y_center+5)}}else{this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;var tile_index=1;if(tile_index===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING-gap,y_center+8)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING-gap,y_center+8)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_center){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_center,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"4169E1",neg_color:"FF8C00"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};exports.Scaler=Scaler;exports.SummaryTreePainter=SummaryTreePainter;exports.LinePainter=LinePainter;exports.LinkedFeaturePainter=LinkedFeaturePainter;exports.ReadPainter=ReadPainter;exports.ArcLinkedFeaturePainter=ArcLinkedFeaturePainter;exports.DiagonalHeatmapPainter=DiagonalHeatmapPainter};(function(d){var c={};var b=function(e){return c[e]};var a=function(f,g){var e={};g(b,e);c[f]=e};a("class",class_module);a("slotting",slotting_module);a("painters",painters_module);a("trackster",trackster_module);for(key in c.trackster){d[key]=c.trackster[key]}})(window);
\ No newline at end of file
+define(["libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks"],function(b,d,c,a){});
\ No newline at end of file
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 static/scripts/packed/viz/trackster/painters.js
--- /dev/null
+++ b/static/scripts/packed/viz/trackster/painters.js
@@ -0,0 +1,1 @@
+define(["libs/underscore"],function(_){var extend=_.extend;var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var SummaryTreePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode)};SummaryTreePainter.prototype.default_prefs={show_counts:false};SummaryTreePainter.prototype.draw=function(ctx,width,height,w_scale){var view_start=this.view_start,points=this.data.data,max=(this.prefs.histogram_max?this.prefs.histogram_max:this.data.max),base_y=height;delta_x_px=Math.ceil(this.data.delta*w_scale);ctx.save();for(var i=0,len=points.length;i<len;i++){var x=Math.floor((points[i][0]-view_start)*w_scale);var y=points[i][1];if(!y){continue}var y_px=y/max*height;if(y!==0&&y_px<1){y_px=1}ctx.fillStyle=this.prefs.block_color;ctx.fillRect(x,base_y-y_px,delta_x_px,y_px);var text_padding_req_x=4;if(this.prefs.show_counts&&(ctx.measureText(y).width+text_padding_req_x)<delta_x_px){ctx.fillStyle=this.prefs.label_color;ctx.textAlign="center";ctx.fillText(y,x+(delta_x_px/2),10)}}ctx.restore()};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][1])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][1])}this.prefs.max_value=max_value}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var pref_color=parseInt(this.prefs.color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=this.prefs.color;x_scaled=Math.round((data[i][0]-view_start-1)*w_scale);y=data[i][1];var top_overflow=false,bot_overflow=false;if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=this.prefs.color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler())};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)+this.get_bottom_padding(width)},get_top_padding:function(width){return 0},get_bottom_padding:function(width){return Math.max(Math.round(this.get_row_height()/2),5)},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords;for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((feature_start<view_end&&feature_end>view_start)&&(this.mode==="Dense"||slot!==null)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1])}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return feature_mapper},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){console.log("WARNING: Unimplemented function.");return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2]-1,feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low)*w_scale))),draw_start=f_start,draw_end=f_end,y_center=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_center+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_center+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_center+1,f_end-f_start,thick_height)}}else{var cur_y_center,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_center=y_center+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_center=y_center;cur_height=thick_height}else{cur_y_center+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_center,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-1-tile_low)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_center+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_center+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_center+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_center)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_center+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_center+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_center+8);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_center+8);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null)};extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},draw_read:function(ctx,mode,w_scale,y_center,tile_low,tile_high,feature_start,cigar,strand,orig_seq){ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=0,char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.block_color:this.prefs.reverse_strand_color);var draw_last=[];if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){gap=Math.round(w_scale/2)}if(!cigar){cigar=[[0,orig_seq.length]]}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];if(cig_op==="H"||cig_op==="S"){base_offset-=cig_len}var seq_start=(feature_start-1)+base_offset,s_start=Math.floor(Math.max(0,(seq_start-tile_low)*w_scale)),s_end=Math.floor(Math.max(0,(seq_start+cig_len-tile_low)*w_scale));if(s_start===s_end){s_end+=1}switch(cig_op){case"H":break;case"S":case"M":case"=":if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=orig_seq.slice(seq_offset,seq_offset+cig_len);if(gap>0){ctx.fillStyle=block_color;ctx.fillRect(s_start-gap,y_center+1,s_end-s_start,9);ctx.fillStyle=CONNECTOR_COLOR;for(var c=0,str_len=seq.length;c<str_len;c++){if(this.prefs.show_differences){if(this.ref_seq){var ref_char=this.ref_seq[seq_start-tile_low+c];if(!ref_char||ref_char.toLowerCase()===seq[c].toLowerCase()){continue}}else{continue}}if(seq_start+c>=tile_low&&seq_start+c<=tile_high){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start,y_center+9)}}}else{ctx.fillStyle=block_color;ctx.fillRect(s_start,y_center+4,s_end-s_start,SQUISH_FEATURE_HEIGHT)}}seq_offset+=cig_len;base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start-gap,y_center+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":ctx.fillStyle="red";ctx.fillRect(s_start-gap,y_center+4,s_end-s_start,3);base_offset+=cig_len;break;case"P":break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=orig_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_center-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_center+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_center)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_center+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_center+9]})}else{}}}seq_offset+=cig_len;break;case"X":seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(0,(feature_start-tile_low)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low)*w_scale))),y_center=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color,gap=0;if((mode==="Pack"||this.mode==="Auto")&&w_scale>ctx.canvas.manager.char_width_px){var gap=Math.round(w_scale/2)}if(feature[5] instanceof Array){var b1_start=Math.floor(Math.max(0,(feature[4][0]-tile_low)*w_scale)),b1_end=Math.ceil(Math.min(width,Math.max(0,(feature[4][1]-tile_low)*w_scale))),b2_start=Math.floor(Math.max(0,(feature[5][0]-tile_low)*w_scale)),b2_end=Math.ceil(Math.min(width,Math.max(0,(feature[5][1]-tile_low)*w_scale))),connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end-gap,y_center+5,b2_start-gap,y_center+5)}}else{this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;var tile_index=1;if(tile_index===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING-gap,y_center+8)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING-gap,y_center+8)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_center){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_center,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"4169E1",neg_color:"FF8C00"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};return{Scaler:Scaler,SummaryTreePainter:SummaryTreePainter,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter}});
\ No newline at end of file
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 static/scripts/packed/viz/trackster/slotting.js
--- /dev/null
+++ b/static/scripts/packed/viz/trackster/slotting.js
@@ -0,0 +1,1 @@
+define(["libs/underscore"],function(b){var e=b.extend;var c=2,a=5;var d=function(i,h,f,g){this.slots={};this.start_end_dct={};this.w_scale=i;this.mode=h;this.include_label=(h==="Pack");this.max_rows=f;this.measureText=g};e(d.prototype,{slot_features:function(m){var p=this.w_scale,h=this.start_end_dct,x=[],z=[],n=0,y=this.max_rows;for(var v=0,w=m.length;v<w;v++){var k=m[v],o=k[0];if(this.slots[o]!==undefined){n=Math.max(n,this.slots[o]);z.push(this.slots[o])}else{x.push(v)}}var q=function(E,F){for(var D=0;D<=y;D++){var B=false,G=h[D];if(G!==undefined){for(var A=0,C=G.length;A<C;A++){var i=G[A];if(F>i[0]&&E<i[1]){B=true;break}}}if(!B){return D}}return -1};for(var v=0,w=x.length;v<w;v++){var k=m[x[v]],o=k[0],t=k[1],f=k[2],r=k[3],g=Math.floor(t*p),l=Math.ceil(f*p),u=this.measureText(r).width,j;if(r!==undefined&&this.include_label){u+=(c+a);if(g-u>=0){g-=u;j="left"}else{l+=u;j="right"}}var s=q(g,l);if(s>=0){if(h[s]===undefined){h[s]=[]}h[s].push([g,l]);this.slots[o]=s;n=Math.max(n,s)}}return n+1}});return{FeatureSlotter:d}});
\ No newline at end of file
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 static/scripts/packed/viz/trackster/tracks.js
--- /dev/null
+++ b/static/scripts/packed/viz/trackster/tracks.js
@@ -0,0 +1,1 @@
+define(["libs/underscore","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters"],function(ab,l,t,J){var p=ab.extend;var O=l.get_random_color;var V=function(ac){return("isResolved" in ac)};var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=n[$(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=n[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=n[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)}n[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);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[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)})};exports.moveable=m;var aa=16,E=9,B=20,y=100,G=12000,R=400,I=5000,v=100,o="There was an error in indexing this dataset. ",H="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",C="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.",w="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",P=10,F=20;function W(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 D({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(){},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 x=function(ad,ac,ae){q.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};p(x.prototype,q.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=object_from_template(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(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw()}},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}});var N=function(ad,ac,af){p(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});x.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new X(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 X(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};p(N.prototype,q.prototype,x.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(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 g){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 d){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 S({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 ag=[];for(var ad=0;ad<this.drawables.length;ad++){ag.push(this.drawables[ad].name)}var ae="Composite Track of "+this.drawables.length+" tracks ("+ag.join(", ")+")";var af=new g(this.view,this.view,{name:ae,drawables:this.drawables});var ac=this.container.replace_drawable(this,af,true);af.request_draw()},add_drawable:function(ac){x.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){x.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=p(x.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,ae){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].request_draw(ac,ae)}}});var Z=function(ac){p(ac,{obj_type:"View"});x.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.init();this.canvas_manager=new CanvasManager(this.container.get(0).ownerDocument);this.reset()};ab.extend(Z.prototype,Backbone.Events);p(Z.prototype,x.prototype,{init: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;k(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(){add_datasets(add_datasets_url,add_track_async_url,function(ag){ab.each(ag,function(ah){ac.add_drawable(object_from_template(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_drawables(),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 Y(this,{content_div:this.top_labeltrack}));this.add_label_track(new Y(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")},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:chrom_url+"/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new z(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)},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();ae.request_redraw(true);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!==undefined&&aj!==undefined){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,"");var ak=this,ac,af,ad=ag.split(":"),ai=ad[0],aj=ad[1];if(aj!==undefined){try{var ah=aj.split("-");ac=parseInt(ah[0],10);af=parseInt(ah[1],10)}catch(ae){return false}}ak.change_chrom(ai,ac,af)},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();var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){x.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){x.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(ak,ac,aj,al){var ai=this,ah=(al?[al]:ai.drawables),ae;var ad;for(var ag=0;ag<ah.length;ag++){ad=ah[ag];ae=-1;for(var af=0;af<ai.tracks_to_be_redrawn.length;af++){if(ai.tracks_to_be_redrawn[af][0]===ad){ae=af;break}}if(ae<0){ai.tracks_to_be_redrawn.push([ad,ac,aj])}else{ai.tracks_to_be_redrawn[ag][1]=ac;ai.tracks_to_be_redrawn[ag][2]=aj}}if(!this.requested_redraw){requestAnimationFrame(function(){ai._redraw(ak)});this.requested_redraw=true}},_redraw:function(am){this.requested_redraw=false;var aj=this.low,af=this.high;if(aj<this.max_low){aj=this.max_low}if(af>this.max_high){af=this.max_high}var al=this.high-this.low;if(this.high!==0&&al<this.min_separation){af=aj+this.min_separation}this.low=Math.floor(aj);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var ac=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ai=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var an=13;this.overview_box.css({left:ac,width:Math.max(an,ai)}).show();if(ai<an){this.overview_box.css("left",ac-(an-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ac,width:ai})}if(!am){var ae,ad,ak;for(var ag=0,ah=this.tracks_to_be_redrawn.length;ag<ah;ag++){ae=this.tracks_to_be_redrawn[ag][0];ad=this.tracks_to_be_redrawn[ag][1];ak=this.tracks_to_be_redrawn[ag][2];if(ae){ae._draw(ad,ak)}}this.tracks_to_be_redrawn=[];for(ag=0,ah=this.label_tracks.length;ag<ah;ag++){this.label_tracks[ag]._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.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 L(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.original_dataset_id,tool_id:ac.name},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 ad={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ad.chrom,ad.low,ad.high),ac;if(ah.container===view){var ag=new N(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 ai=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});ai.init_for_tool_data();ai.change_mode(ah.mode);ai.set_filters_manager(ah.filters_manager.copy(ai));ai.update_icons();ac.add_drawable(ai);ai.tiles_div.text("Starting job.");this.update_params();this.run(ad,ai,function(aj){ai.set_dataset(new Dataset(aj));ai.tiles_div.text("Running job.");ai.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),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(H)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(w+ag.message)}else{af(ag)}}})}});var L=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};p(L.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){L.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};p(e.prototype,L.prototype,{update_value:function(){L.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var f=function(ac){this.manager=null;this.name=ac.name;this.index=ac.index;this.tool_id=ac.tool_id;this.tool_exp_name=ac.tool_exp_name};p(f.prototype,{to_dict:function(){return{name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name}}});var c=function(ae,ad,ac){return $("<a/>").attr("href","javascript:void(0);").attr("title",ae).addClass("icon-button").addClass(ad).tooltip().click(ac)};var S=function(ak){f.call(this,ak);this.low=("low" in ak?ak.low:-Number.MAX_VALUE);this.high=("high" in ak?ak.high:Number.MAX_VALUE);this.min=("min" in ak?ak.min:Number.MAX_VALUE);this.max=("max" in ak?ak.max:-Number.MAX_VALUE);this.container=null;this.slider=null;this.slider_label=null;var ag=function(al,am,an){al.click(function(){var at=am.text(),aq=parseFloat(an.slider("option","max")),ap=(aq<=1?4:aq<=1000000?aq.toString().length:6),ar=false,ao=$(this).parents(".slider-row");ao.addClass("input");if(an.slider("option","values")){ap=2*ap+1;ar=true}am.text("");$("<input type='text'/>").attr("size",ap).attr("maxlength",ap).attr("value",at).appendTo(am).focus().select().click(function(au){au.stopPropagation()}).blur(function(){$(this).remove();am.text(at);ao.removeClass("input")}).keyup(function(ay){if(ay.keyCode===27){$(this).trigger("blur")}else{if(ay.keyCode===13){var aw=an.slider("option","min"),au=an.slider("option","max"),ax=function(az){return(isNaN(az)||az>au||az<aw)},av=$(this).val();if(!ar){av=parseFloat(av);if(ax(av)){alert("Parameter value must be in the range ["+aw+"-"+au+"]");return $(this)}}else{av=av.split("-");av=[parseFloat(av[0]),parseFloat(av[1])];if(ax(av[0])||ax(av[1])){alert("Parameter value must be in the range ["+aw+"-"+au+"]");return $(this)}}an.slider((ar?"values":"value"),av);ao.removeClass("input")}}})})};var ad=this;ad.parent_div=$("<div/>").addClass("filter-row slider-row");var ac=$("<div/>").addClass("elt-label").appendTo(ad.parent_div),ai=$("<span/>").addClass("slider-name").text(ad.name+" ").appendTo(ac),ae=$("<span/>").text(this.low+"-"+this.high),af=$("<span/>").addClass("slider-value").appendTo(ac).append("[").append(ae).append("]");ad.values_span=ae;var ah=$("<div/>").addClass("slider").appendTo(ad.parent_div);ad.control_element=$("<div/>").attr("id",ad.name+"-filter-control").appendTo(ah);ad.control_element.slider({range:true,min:this.min,max:this.max,step:this.get_slider_step(this.min,this.max),values:[this.low,this.high],slide:function(al,am){ad.slide(al,am)},change:function(al,am){ad.control_element.slider("option","slide").call(ad.control_element,al,am)}});ad.slider=ad.control_element;ad.slider_label=ae;ag(af,ae,ad.control_element);var aj=$("<div/>").addClass("display-controls").appendTo(ad.parent_div);this.transparency_icon=c("Use filter for data transparency","layer-transparent",function(){if(ad.manager.alpha_filter!==ad){ad.manager.alpha_filter=ad;ad.manager.parent_div.find(".layer-transparent").removeClass("active").hide();ad.transparency_icon.addClass("active").show()}else{ad.manager.alpha_filter=null;ad.transparency_icon.removeClass("active")}ad.manager.track.request_draw(true,true)}).appendTo(aj).hide();this.height_icon=c("Use filter for data height","arrow-resize-090",function(){if(ad.manager.height_filter!==ad){ad.manager.height_filter=ad;ad.manager.parent_div.find(".arrow-resize-090").removeClass("active").hide();ad.height_icon.addClass("active").show()}else{ad.manager.height_filter=null;ad.height_icon.removeClass("active")}ad.manager.track.request_draw(true,true)}).appendTo(aj).hide();ad.parent_div.hover(function(){ad.transparency_icon.show();ad.height_icon.show()},function(){if(ad.manager.alpha_filter!==ad){ad.transparency_icon.hide()}if(ad.manager.height_filter!==ad){ad.height_icon.hide()}});$("<div style='clear: both;'/>").appendTo(ad.parent_div)};p(S.prototype,{to_dict:function(){var ac=f.prototype.to_dict.call(this);return p(ac,{type:"number",min:this.min,max:this.max,low:this.low,high:this.high})},copy:function(){return new S({name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name})},get_slider_step:function(ae,ac){var ad=ac-ae;return(ad<=2?0.01:1)},slide:function(ae,af){var ad=af.values;this.values_span.text(ad[0]+"-"+ad[1]);this.low=ad[0];this.high=ad[1];var ac=this;setTimeout(function(){if(ad[0]===ac.low&&ad[1]===ac.high){ac.manager.track.request_draw(true,true)}},25)},applies_to:function(ac){if(ac.length>this.index){return true}return false},_keep_val:function(ac){return(isNaN(ac)||(ac>=this.low&&ac<=this.high))},keep:function(ad){if(!this.applies_to(ad)){return true}var af=this;var ag=ad[this.index];if(ag instanceof Array){var ae=true;for(var ac=0;ac<ag.length;ac++){if(!this._keep_val(ag[ac])){ae=false;break}}return ae}else{return this._keep_val(ad[this.index])}},update_attrs:function(af){var ac=false;if(!this.applies_to(af)){return ac}var ad=af[this.index];if(!(ad instanceof Array)){ad=[ad]}for(var ae=0;ae<ad.length;ae++){var ag=ad[ae];if(ag<this.min){this.min=Math.floor(ag);ac=true}if(ag>this.max){this.max=Math.ceil(ag);ac=true}}return ac},update_ui_elt:function(){if(this.min<this.max){this.parent_div.show()}else{this.parent_div.hide()}var ad=this.slider.slider("option","min"),ac=this.slider.slider("option","max");if(this.min<ad||this.max>ac){this.slider.slider("option","min",this.min);this.slider.slider("option","max",this.max);this.slider.slider("option","step",this.get_slider_step(this.min,this.max));this.slider.slider("option","values",[this.min,this.max])}}});var X=function(ae,ak){this.track=ae;this.alpha_filter=null;this.height_filter=null;this.filters=[];this.parent_div=$("<div/>").addClass("filters").hide();this.parent_div.bind("drag",function(am){am.stopPropagation()}).click(function(am){am.stopPropagation()}).bind("dblclick",function(am){am.stopPropagation()}).bind("keydown",function(am){am.stopPropagation()});if(ak&&"filters" in ak){var ac=("alpha_filter" in ak?ak.alpha_filter:null),af=("height_filter" in ak?ak.height_filter:null),ah=ak.filters,ad;for(var ai=0;ai<ah.length;ai++){if(ah[ai].type==="number"){ad=new S(ah[ai]);this.add_filter(ad);if(ad.name===ac){this.alpha_filter=ad;ad.transparency_icon.addClass("active").show()}if(ad.name===af){this.height_filter=ad;ad.height_icon.addClass("active").show()}}else{console.log("ERROR: unsupported filter: ",name,type)}}if("visible" in ak&&ak.visible){this.parent_div.show()}}if(this.filters.length!==0){var al=$("<div/>").addClass("param-row").appendTo(this.parent_div);var aj=$("<input type='submit'/>").attr("value","Run on complete dataset").appendTo(al);var ag=this;aj.click(function(){ag.run_on_dataset()})}};p(X.prototype,{show:function(){this.parent_div.show()},hide:function(){this.parent_div.hide()},toggle:function(){this.parent_div.toggle()},visible:function(){return this.parent_div.is(":visible")},to_dict:function(){var af={},ae=[],ad;for(var ac=0;ac<this.filters.length;ac++){ad=this.filters[ac];ae.push(ad.to_dict())}af.filters=ae;af.alpha_filter=(this.alpha_filter?this.alpha_filter.name:null);af.height_filter=(this.height_filter?this.height_filter.name:null);af.visible=this.parent_div.is(":visible");return af},copy:function(ad){var ae=new X(ad);for(var ac=0;ac<this.filters.length;ac++){ae.add_filter(this.filters[ac].copy())}return ae},add_filter:function(ac){ac.manager=this;this.parent_div.append(ac.parent_div);this.filters.push(ac)},remove_all:function(){this.filters=[];this.parent_div.children().remove()},init_filters:function(){for(var ac=0;ac<this.filters.length;ac++){var ad=this.filters[ac];ad.update_ui_elt()}},clear_filters:function(){for(var ac=0;ac<this.filters.length;ac++){var ad=this.filters[ac];ad.slider.slider("option","values",[ad.min,ad.max])}this.alpha_filter=null;this.height_filter=null;this.parent_div.find(".icon-button").hide()},run_on_dataset:function(){var ai=function(am,ak,al){if(!(ak in am)){am[ak]=al}return am[ak]};var ah={},aj,ac;for(var ag=0;ag<this.filters.length;ag++){aj=this.filters[ag];if(aj.tool_id){if(aj.min!==aj.low){ac=ai(ah,aj.tool_id,[]);ac[ac.length]=aj.tool_exp_name+" >= "+aj.low}if(aj.max!==aj.high){ac=ai(ah,aj.tool_id,[]);ac[ac.length]=aj.tool_exp_name+" <= "+aj.high}}}var ad=[];for(var af in ah){ad[ad.length]=[af,ah[af]]}(function ae(aq,an){var al=an[0],am=al[0],ap=al[1],ao="("+ap.join(") and (")+")",ak={cond:ao,input:aq,target_dataset_id:aq,tool_id:am},an=an.slice(1);$.getJSON(run_tool_url,ak,function(ar){if(ar.error){show_modal("Filter Dataset","Error running tool "+am,{Close:hide_modal})}else{if(an.length===0){show_modal("Filtering Dataset","Filter(s) are running on the complete dataset. Outputs are in dataset's history.",{Close:hide_modal})}else{ae(ar.dataset_id,an)}}})})(this.track.dataset_id,ad)}});var A=function(ac,ad){J.Scaler.call(this,ad);this.filter=ac};A.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 D=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(D.prototype,{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(O())})})(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==="float"){ag=parseFloat(ag)}else{if(ah.type==="int"){ag=parseInt(ag)}else{if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}}}if(ag!==ae.values[ah.key]){ae.values[ah.key]=ag;ad=true}}});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 j=function(ac,ah,ae,ad,af,ag){b.call(this,ac,ah,ae,ad,af);this.max_val=ag};p(j.prototype,b.prototype);var M=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:B-1,width:ae.width}).prependTo(this.html_elt);var al=new 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(true)}).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(true)}).dblclick(function(ar){ar.stopPropagation()})}};p(M.prototype,b.prototype);M.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"?W(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 h=function(ad,ac,ae){p(ae,{drag_handle_class:"draghandle"});q.call(this,ad,ac,ae);this.dataset=new Dataset({id:ae.dataset_id,hda_ldda:ae.hda_ldda});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:I);this.data_manager=("data_manager" in ae?ae.data_manager:new GenomeDataManager({dataset:this.dataset,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(h.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 GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new 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=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ac.dataset_id,hda_ldda:ac.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},on_resize:function(){},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 Y){return"LabelTrack"}else{if(this instanceof z){return"ReferenceTrack"}else{if(this instanceof i){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Q){return"VcfTrack"}else{if(this instanceof g){return"CompositeTrack"}else{if(this instanceof d){return"FeatureTrack"}}}}}}}return""},init:function(){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.content_div.css("height","auto");ad.tiles_div.children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset_id){return}var ac=$.Deferred(),ae={hda_ldda:ad.hda_ldda,data_type:this.dataset_check_type,chrom:ad.view.chrom};$.getJSON(this.dataset.url(),ae,function(af){if(!af||af==="error"||af.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(o);if(af.message){var ag=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+af.message+"</pre>",{Close:hide_modal})});ad.tiles_div.append(ag)}}else{if(af==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(H)}else{if(af==="no data"||(af.data!==undefined&&(af.data===null||af.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(C)}else{if(af==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(u);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(af==="data"||af.status==="data"){if(af.valid_chroms){ad.valid_chroms=af.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(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(){},get_drawables:function(){return this}});var K=function(ae,ad,af){h.call(this,ae,ad,af);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new X(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 Cache(P);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(K.prototype,q.prototype,h.prototype,{action_icons_def:h.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(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,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;ac.tile_cache.clear();ac.request_draw();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,ae,ac){return ad+"_"+ae+"_"+ac},request_draw:function(ad,ac){this.view.request_redraw(false,ad,ac,this)},before_draw:function(){},_draw:function(ad,an){if(!this.can_draw()){return}var al=this.view.low,ah=this.view.high,aj=ah-al,ae=this.view.container.width(),ap=this.view.resolution_px_b,ag=this.view.resolution_b_px;if(this.is_overview){al=this.view.max_low;ah=this.view.max_high;ag=(view.max_high-view.max_low)/ae;ap=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(ag*R)),ak=true,ao=[],ai=function(aq){return(aq&&"track" in aq)};while((ac*R*ag)<ah){var am=this.draw_helper(ad,ae,ac,ag,this.tiles_div,ap);if(ai(am)){ao.push(am)}else{ak=false}ac+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;if(ak){this.tiles_div.children(".remove").remove();af.postdraw_actions(ao,ae,ap,an)}},postdraw_actions:function(ae,af,ah,ac){var ag=false;for(var ad=0;ad<ae.length;ad++){if(ae[ad].has_icons){ag=true;break}}if(ag){for(var ad=0;ad<ae.length;ad++){tile=ae[ad];if(!tile.has_icons){tile.html_elt.css("padding-top",B)}}}},draw_helper:function(ac,ao,au,ar,ah,ai,ap){var an=this,ax=this._gen_tile_cache_key(ao,ai,au),af=this._get_tile_bounds(au,ar);if(!ap){ap={}}var aw=(ac?undefined:an.tile_cache.get_elt(ax));if(aw){an.show_tile(aw,ah,ai);return aw}var al=true;var at=an.data_manager.get_data(af,an.mode,ar,an.data_url_extra_params);if(V(at)){al=false}var aj;if(view.reference_track&&ai>view.canvas_manager.char_width_px){aj=view.reference_track.data_manager.get_data(af,an.mode,ar,view.reference_track.data_url_extra_params);if(V(aj)){al=false}}if(al){p(at,ap.more_tile_data);var ak=an.mode;if(ak==="Auto"){ak=an.get_mode(at);an.update_auto_mode(ak)}var ae=an.view.canvas_manager.new_canvas(),av=af.get("start"),ad=af.get("end"),ao=Math.ceil((ad-av)*ai)+an.left_offset,am=an.get_canvas_height(at,ak,ai,ao);ae.width=ao;ae.height=am;var aq=ae.getContext("2d");aq.translate(this.left_offset,0);var aw=an.draw_tile(at,aq,ak,ar,af,ai,aj);if(aw!==undefined){an.tile_cache.set_elt(ax,aw);an.show_tile(aw,ah,ai)}return aw}var ag=$.Deferred();$.when(at,aj).then(function(){view.request_redraw(false,false,false,an);ag.resolve()});return ag},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ag,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var af=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){af-=this.left_offset}ac.css({position:"absolute",top:0,left:af});if(ac.hasClass("remove")){ac.removeClass("remove")}else{ag.append(ac)}ad.after_show_tile(ae)},after_show_tile:function(ac){this.max_height_px=Math.max(this.max_height_px,ac.html_elt.height());ac.html_elt.parent().children().css("height",this.max_height_px+"px");var ad=this.max_height_px;if(this.visible_height_px!==0){ad=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",ad+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*R*ad),ag=Math.ceil(R*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae,ac,af){var ad=this,ag=(ae!==undefined&&ac!==undefined&&af!==undefined?ae+":"+ac+"-"+af:"all");return" - region=["+ag+"], parameters=["+ad.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){return true},can_subset:function(ac){return false},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=I;var ag=new ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset_id,hda_ldda:ad.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 Y=function(ad,ac){var ae={resize:false};h.call(this,ad,ac,ae);this.container_div.addClass("label-track")};p(Y.prototype,h.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ae=this.view,af=ae.high-ae.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/ai)*ai,ag=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ah=(ac-ae.low)/af*ag;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ah-1}));ac+=ai}this.content_div.children(":first").remove();this.content_div.append(ad)}});var g=function(ad,ac,ag){K.call(this,ad,ac,ag);this.drawables=[];this.left_offset=0;if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=object_from_template(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};p(g.prototype,K.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(K.prototype.action_icons_def),to_dict:x.prototype.to_dict,add_drawable:x.prototype.add_drawable,unpack_drawables:x.prototype.unpack_drawables,change_mode:function(ac){K.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,draw_helper:function(ad,at,az,aw,ak,am,au){var ar=this,aD=this._gen_tile_cache_key(at,am,az),ah=this._get_tile_bounds(az,aw);if(!au){au={}}var aC=(ad?undefined:ar.tile_cache.get_elt(aD));if(aC){ar.show_tile(aC,ak,am);return aC}var al=[],ar,ap=true,ax,an;for(var ay=0;ay<this.drawables.length;ay++){ar=this.drawables[ay];ax=ar.data_manager.get_data(ah,ar.mode,aw,ar.data_url_extra_params);if(V(ax)){ap=false}al.push(ax);an=null;if(view.reference_track&&am>view.canvas_manager.char_width_px){an=view.reference_track.data_manager.get_data(ah,ar.mode,aw,view.reference_track.data_url_extra_params);if(V(an)){ap=false}}al.push(an)}if(ap){p(ax,au.more_tile_data);this.tile_predraw_init();var ag=ar.view.canvas_manager.new_canvas(),ai=ar._get_tile_bounds(az,aw),aA=ah.get("start"),ae=ah.get("end"),aB=0,at=Math.ceil((ae-aA)*am)+this.left_offset,aq=0,af=[],ay;var ac=0;for(ay=0;ay<this.drawables.length;ay++,aB+=2){ar=this.drawables[ay];ax=al[aB];var ao=ar.mode;if(ao==="Auto"){ao=ar.get_mode(ax);ar.update_auto_mode(ao)}af.push(ao);ac=ar.get_canvas_height(ax,ao,am,at);if(ac>aq){aq=ac}}ag.width=at;ag.height=(au.height?au.height:aq);aB=0;var av=ag.getContext("2d");av.translate(this.left_offset,0);av.globalAlpha=0.5;av.globalCompositeOperation="source-over";for(ay=0;ay<this.drawables.length;ay++,aB+=2){ar=this.drawables[ay];ax=al[aB];an=al[aB+1];aC=ar.draw_tile(ax,av,af[ay],aw,ah,am,an)}this.tile_cache.set_elt(aD,aC);this.show_tile(aC,ak,am);return aC}var aj=$.Deferred(),ar=this;$.when.apply($,al).then(function(){view.request_redraw(false,false,false,ar);aj.resolve()});return aj},show_group:function(){var af=new N(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()},tile_predraw_init:function(){var af=Number.MAX_VALUE,ac=-af,ad;for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];if(ad instanceof i){if(ad.prefs.min_value<af){af=ad.prefs.min_value}if(ad.prefs.max_value>ac){ac=ad.prefs.max_value}}}for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];ad.prefs.min_value=af;ad.prefs.max_value=ac}},postdraw_actions:function(ae,ah,aj,ad){K.prototype.postdraw_actions.call(this,ae,ah,aj,ad);var ag=-1;for(var af=0;af<ae.length;af++){var ac=ae[af].html_elt.find("canvas").height();if(ac>ag){ag=ac}}for(var af=0;af<ae.length;af++){var ai=ae[af];if(ai.html_elt.find("canvas").height()!==ag){this.draw_helper(true,ah,ai.index,ai.resolution,ai.html_elt.parent(),aj,{height:ag});ai.html_elt.remove()}}}});var z=function(ac){K.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=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};p(z.prototype,q.prototype,K.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:q.prototype.can_draw,draw_helper:function(ag,ae,ac,ad,ah,ai,af){if(ai>this.view.canvas_manager.char_width_px){return K.prototype.draw_helper.call(this,ag,ae,ac,ad,ah,ai,af)}else{this.hide_contents();return null}},draw_tile:function(ak,al,ag,af,ai,am){var ae=this;if(am>this.view.canvas_manager.char_width_px){if(ak.data===null){this.hide_contents();return}var ad=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";ak=ak.data;for(var ah=0,aj=ak.length;ah<aj;ah++){var ac=Math.floor(ah*am);al.fillText(ak[ah],ac,10)}this.show_contents();return new b(ae,ai,af,ad,ak)}this.hide_contents()}});var i=function(ae,ad,af){var ac=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";K.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new D({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:O()},{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.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};p(i.prototype,q.prototype,K.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ac=this;ac.vertical_range=undefined;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.hda_ldda,dataset_id:ac.dataset_id},function(ad){ac.container_div.addClass("line-track");var ag=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=ag.min,ai=ag.max;ae=Math.floor(Math.min(0,Math.max(ae,ag.mean-2*ag.sd)));ai=Math.ceil(Math.max(0,Math.min(ai,ag.mean+2*ag.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ai;$("#track_"+ac.dataset_id+"_minval").val(ac.prefs.min_value);$("#track_"+ac.dataset_id+"_maxval").val(ac.prefs.max_value)}ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.total_frequency=ag.total_frequency;ac.container_div.find(".yaxislabel").remove();var ah=$("<div/>").text(W(ac.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_min_value(aj)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ac.dataset_id+"_minval").prependTo(ac.container_div),af=$("<div/>").text(W(ac.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_max_value(aj)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ac.dataset_id+"_maxval").prependTo(ac.container_div)})},draw_tile:function(al,aj,ae,ad,ag,ak){var ac=aj.canvas,af=ag.get("start"),ai=ag.get("end"),ah=new J.LinePainter(al.data,af,ai,this.prefs,ae);ah.draw(aj,ac.width,ac.height,ak);return new b(this,ag,ad,ac,al.data)},can_subset:function(ac){return false}});var s=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";K.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new D({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{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);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};p(s.prototype,q.prototype,K.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;this.tile_cache.clear();this.request_draw()},draw_tile:function(am,ak,ah,af,ad,al){var ae=ak.canvas,ac=this._get_tile_bounds(ad,af),ag=ac[0],aj=ac[1],ai=new J.DiagonalHeatmapPainter(am.data,ag,aj,this.prefs,ah);ai.draw(ak,ae.width,ae.height,al);return new b(this,ad,af,ae,am.data)}});var d=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];K.call(this,af,ae,ah);var ag=O(),ac=O([ag,"#ffffff"]);this.config=new D({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:"histogram_max",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.tile_cache.clear();ad.set_painter_from_config();ad.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=ah.dataset_id;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(d.prototype,q.prototype,K.prototype,{set_dataset:function(ac){this.dataset_id=ac.get("id");this.hda_ldda=ac.get("hda_ldda");this.dataset=ac;this.data_manager.set("dataset",ac)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=J.ArcLinkedFeaturePainter}else{this.painter=J.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ar,am,ah,ag){K.prototype.postdraw_actions.call(this,ar,ag);var al=this,ao;if(al.mode==="Coverage"){var ad=-1;for(ao=0;ao<ar.length;ao++){var an=ar[ao].max_val;if(an>ad){ad=an}}for(ao=0;ao<ar.length;ao++){var au=ar[ao];if(au.max_val!==ad){au.html_elt.remove();al.draw_helper(true,am,au.index,au.resolution,au.html_elt.parent(),ah,{more_tile_data:{max:ad}})}}}if(al.filters_manager){var ai=al.filters_manager.filters;for(var aq=0;aq<ai.length;aq++){ai[aq].update_ui_elt()}var at=false,ac,aj;for(ao=0;ao<ar.length;ao++){if(ar[ao].data.length){ac=ar[ao].data[0];for(var aq=0;aq<ai.length;aq++){aj=ai[aq];if(aj.applies_to(ac)&&aj.min!==aj.max){at=true;break}}}}if(al.filters_available!==at){al.filters_available=at;if(!al.filters_available){al.filters_manager.hide()}al.update_icons()}}this.container_div.find(".yaxislabel").remove();var af=ar[0];if(af instanceof j){var ak=(this.prefs.histogram_max?this.prefs.histogram_max:af.max_val),ae=$("<div/>").text(ak).make_text_editable({num_cols:12,on_finish:function(av){$(".bs-tooltip").remove();var av=parseFloat(av);al.prefs.histogram_max=(!isNaN(av)?av:null);al.tile_cache.clear();al.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ae)}if(af instanceof M){var ap=true;for(ao=0;ao<ar.length;ao++){if(!ar[ao].all_slotted){ap=false;break}}if(!ap){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"}else{if(ac==="summary_tree"){ac="coverage histogram"}}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,y,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>G){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="summary_tree"||ag==="Coverage"){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(ao==="summary_tree"||ao==="Coverage"){var aA=new J.SummaryTreePainter(am,ay,ac,this.prefs);aA.draw(aq,ad.width,ad.height,aj);return new j(ap,af,ar,ad,am.data,am.max)}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 A(this.filters_manager.alpha_filter):null);var az=(this.filters_manager.height_filter?new A(this.filters_manager.height_filter):null);var aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae);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 M(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="summary_tree"}else{if(ac.extra_info==="no_detail"||ac.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="summary_tree"||ac.message||ac.extra_info==="no_detail"){return false}return true}});var Q=function(ad,ac,ae){d.call(this,ad,ac,ae);this.config=new D({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:O()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{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.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=J.ReadPainter};p(Q.prototype,q.prototype,K.prototype,d.prototype);var T=function(ae,ad,ag){d.call(this,ae,ad,ag);var af=O(),ac=O([af,"#ffffff"]);this.config=new D({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:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=J.ReadPainter;this.update_icons()};p(T.prototype,q.prototype,K.prototype,d.prototype);return{View:Z,DrawableGroup:N,LineTrack:i,FeatureTrack:d,DiagonalHeatmapTrack:s,ReadTrack:T,VcfTrack:Q,CompositeTrack:g}});
\ No newline at end of file
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 static/scripts/packed/viz/trackster/util.js
--- /dev/null
+++ b/static/scripts/packed/viz/trackster/util.js
@@ -0,0 +1,1 @@
+define(function(){exports={};exports.get_random_color=function(a){if(!a){a="#ffffff"}if(typeof(a)==="string"){a=[a]}for(var j=0;j<a.length;j++){a[j]=parseInt(a[j].slice(1),16)}var n=function(t,s,i){return((t*299)+(s*587)+(i*114))/1000};var e=function(v,u,w,s,i,t){return(Math.max(v,s)-Math.min(v,s))+(Math.max(u,i)-Math.min(u,i))+(Math.max(w,t)-Math.min(w,t))};var g,o,f,k,q,h,r,c,d,b,p,m=false,l=0;do{g=Math.round(Math.random()*16777215);o=(g&16711680)>>16;f=(g&65280)>>8;k=g&255;d=n(o,f,k);m=true;for(j=0;j<a.length;j++){q=a[j];h=(q&16711680)>>16;r=(q&65280)>>8;c=q&255;b=n(h,r,c);p=e(o,f,k,h,r,c);if((Math.abs(d-b)<40)||(p<200)){m=false;break}}l++}while(!m&&l<=10);return"#"+(16777216+g).toString(16).substr(1,6)};return exports});
\ No newline at end of file
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 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 @@
-var add_bookmark=function(e,c,a){var g=$("#bookmarks-container"),i=$("<div/>").addClass("bookmark").appendTo(g);var j=$("<div/>").addClass("position").appendTo(i),f=$("<a href=''/>").text(e).appendTo(j).click(function(){view.go_to(e);return false}),d=$("<div/>").text(c).appendTo(i);if(a){var h=$("<div/>").addClass("delete-icon-container").prependTo(i).click(function(){i.slideUp("fast");i.remove();view.has_changes=true;return false}),b=$("<a href=''/>").addClass("icon-button delete").appendTo(h);d.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return i};var object_from_template=function(c,b,a){if("copy" in c){return c.copy(a)}else{var d=c.obj_type;if(!d){d=c.track_type}return new addable_objects[d](b,a,c)}};var addable_objects={LineTrack:LineTrack,FeatureTrack:FeatureTrack,VcfTrack:VcfTrack,ReadTrack:ReadTrack,CompositeTrack:CompositeTrack,DrawableGroup:DrawableGroup};var create_visualization=function(d,a,c,e,b){view=new View(d);view.editor=true;$.when(view.load_chroms_deferred).then(function(){if(a){var o=a.chrom,f=a.start,l=a.end,h=a.overview;if(o&&(f!==undefined)&&l){view.change_chrom(o,f,l)}}if(c){var j,g,k;for(var m=0;m<c.length;m++){view.add_drawable(object_from_template(c[m],view,view))}}view.update_intro_div();var p;for(var m=0;m<view.drawables.length;m++){if(view.drawables[m].name===h){view.set_overview(view.drawables[m]);break}}if(e){var n;for(var m=0;m<e.length;m++){n=e[m];add_bookmark(n.position,n.annotation,b)}}view.has_changes=false});return view};var init_keyboard_nav=function(a){$(document).keydown(function(b){if($(b.srcElement).is(":input")){return}switch(b.which){case 37:a.move_fraction(0.25);break;case 38:var c=Math.round(a.viewport_container.height()/15);a.viewport_container.scrollTop(a.viewport_container.scrollTop()-20);break;case 39:a.move_fraction(-0.25);break;case 40:var c=Math.round(a.viewport_container.height()/15);a.viewport_container.scrollTop(a.viewport_container.scrollTop()+20);break}})};
\ No newline at end of file
+define(["libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks"],function(h,f,b,e){var d=function(n,l,j){var p=$("#bookmarks-container"),r=$("<div/>").addClass("bookmark").appendTo(p);var s=$("<div/>").addClass("position").appendTo(r),o=$("<a href=''/>").text(n).appendTo(s).click(function(){view.go_to(n);return false}),m=$("<div/>").text(l).appendTo(r);if(j){var q=$("<div/>").addClass("delete-icon-container").prependTo(r).click(function(){r.slideUp("fast");r.remove();view.has_changes=true;return false}),k=$("<a href=''/>").addClass("icon-button delete").appendTo(q);m.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return r};var c={LineTrack:e.LineTrack,FeatureTrack:e.FeatureTrack,VcfTrack:e.VcfTrack,ReadTrack:e.ReadTrack,CompositeTrack:e.CompositeTrack,DrawableGroup:e.DrawableGroup};var i=function(l,k,j){if("copy" in l){return l.copy(j)}else{var m=l.obj_type;if(!m){m=l.track_type}return new c[m](k,j,l)}};var g=function(m,j,l,n,k){view=new e.View(m);view.editor=true;$.when(view.load_chroms_deferred).then(function(){if(j){var w=j.chrom,o=j.start,t=j.end,q=j.overview;if(w&&(o!==undefined)&&t){view.change_chrom(w,o,t)}}if(l){var r,p,s;for(var u=0;u<l.length;u++){view.add_drawable(i(l[u],view,view))}}view.update_intro_div();var x;for(var u=0;u<view.drawables.length;u++){if(view.drawables[u].name===q){view.set_overview(view.drawables[u]);break}}if(n){var v;for(var u=0;u<n.length;u++){v=n[u];d(v.position,v.annotation,k)}}view.has_changes=false});return view};var a=function(j){$(document).keydown(function(k){if($(k.srcElement).is(":input")){return}switch(k.which){case 37:j.move_fraction(0.25);break;case 38:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()-20);break;case 39:j.move_fraction(-0.25);break;case 40:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()+20);break}})};return{add_bookmark:d,object_from_template:i,create_visualization:g,init_keyboard_nav:a}});
\ No newline at end of file
diff -r 4809c1f1265d27420472b230fce282995aae02d8 -r 0e17b12c190312b7836d69d7852afbed15e81bb9 static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-(function(){var f=Backbone.Model.extend({defaults:{ajax_settings:{},interval:1000,success_fn:function(t){return true}},go:function(){var w=$.Deferred(),v=this,y=v.get("ajax_settings"),x=v.get("success_fn"),u=v.get("interval"),t=function(){$.ajax(y).success(function(z){if(x(z)){w.resolve(z)}else{setTimeout(t,u)}})};t();return w}});var g=function(t){this.default_font=t!==undefined?t:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};_.extend(g.prototype,{load_pattern:function(t,x){var u=this.patterns,v=this.dummy_context,w=new Image();w.src=galaxy_paths.attributes.image_path+x;w.onload=function(){u[t]=v.createPattern(w,"repeat")}},get_pattern:function(t){return this.patterns[t]},new_canvas:function(){var t=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(t)}t.manager=this;return t}});var p=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(t){this.clear()},get_elt:function(u){var v=this.attributes.obj_cache,w=this.attributes.key_ary,t=w.indexOf(u);if(t!==-1){if(v[u].stale){w.splice(t,1);delete v[u]}else{this.move_key_to_end(u,t)}}return v[u]},set_elt:function(u,w){var x=this.attributes.obj_cache,y=this.attributes.key_ary,v=this.attributes.num_elements;if(!x[u]){if(y.length>=v){var t=y.shift();delete x[t]}y.push(u)}x[u]=w;return w},move_key_to_end:function(u,t){this.attributes.key_ary.splice(t,1);this.attributes.key_ary.push(u)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=p.extend({defaults:_.extend({},p.prototype.defaults,{dataset:null,filters_manager:null,data_type:"data",genome_wide_summary_data:null,data_mode_compatible:function(t,u){return true},can_subset:function(t){return false}}),data_is_ready:function(){var v=this.get("dataset"),u=$.Deferred(),t=new f({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:v.get("hda_ldda"),data_type:"state"},dataType:"json"},interval:5000,success_fn:function(w){return w!=="pending"}});$.when(t.go()).then(function(w){u.resolve(w==="ok"||w==="data")});return u},search_features:function(t){var u=this.get("dataset"),v={query:t,dataset_id:u.id,hda_ldda:u.get("hda_ldda"),data_type:"features"};return $.getJSON(u.url(),v)},load_data:function(B,A,u,z){var w={data_type:this.get("data_type"),chrom:B.get("chrom"),low:B.get("start"),high:B.get("end"),mode:A,resolution:u},x=this.get("dataset");if(x){w.dataset_id=x.id;w.hda_ldda=x.get("hda_ldda")}$.extend(w,z);var C=this.get("filters_manager");if(C){var D=[];var t=C.filters;for(var y=0;y<t.length;y++){D.push(t[y].name)}w.filter_cols=JSON.stringify(D)}var v=this;return $.getJSON(x.url(),w,function(E){v.set_data(B,E)})},get_data:function(z,y,v,x){var A=this.get_elt(z);if(A&&(is_deferred(A)||this.get("data_mode_compatible")(A,y))){return A}var B=this.get("key_ary"),u=this.get("obj_cache"),C,t;for(var w=0;w<B.length;w++){C=B[w];t=new h({from_str:C});if(t.contains(z)){A=u[C];if(is_deferred(A)||(this.get("data_mode_compatible")(A,y)&&this.get("can_subset")(A))){this.move_key_to_end(C,w);return A}}}A=this.load_data(z,y,v,x);this.set_data(z,A);return A},set_data:function(u,t){this.set_elt(u,t)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(B,A,w,z,x){var D=this.get_elt(B);if(!(D&&this.get("data_mode_compatible")(D,A))){console.log("ERROR: no current data for: ",dataset,B.toString(),A,w,z);return}D.stale=true;var v=B.get("start");if(x===this.DEEP_DATA_REQ){$.extend(z,{start_val:D.data.length+1})}else{if(x===this.BROAD_DATA_REQ){v=(D.max_high?D.max_high:D.data[D.data.length-1][2])+1}}var C=B.copy().set("start",v);var u=this,y=this.load_data(C,A,w,z),t=$.Deferred();this.set_data(B,t);$.when(y).then(function(E){if(E.data){E.data=D.data.concat(E.data);if(E.max_low){E.max_low=D.max_low}if(E.message){E.message=E.message.replace(/[0-9]+/,E.data.length)}}u.set_data(B,E);t.resolve(E)});return t},get_elt:function(t){return p.prototype.get_elt.call(this,t.toString())},set_elt:function(u,t){return p.prototype.set_elt.call(this,u.toString(),t)}});var n=d.extend({load_data:function(t,w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,t,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info}});var h=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006},initialize:function(u){if(u.from_str){var w=u.from_str.split(":"),v=w[0],t=w[1].split("-");this.set({chrom:v,start:parseInt(t[0],10),end:parseInt(t[1],10)})}},copy:function(){return new h({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(A){var u=this.get("chrom"),z=A.get("chrom"),y=this.get("start"),w=A.get("start"),x=this.get("end"),v=A.get("end"),t;if(u&&z&&u!==z){return this.get("DIF_CHROMS")}if(y<w){if(x<w){t=this.get("BEFORE")}else{if(x<=v){t=this.get("OVERLAP_START")}else{t=this.get("CONTAINS")}}}else{if(y>v){t=this.get("AFTER")}else{if(x<=v){t=this.get("CONTAINED_BY")}else{t=this.get("OVERLAP_END")}}}return t},contains:function(t){return this.compute_overlap(t)===this.get("CONTAINS")},overlaps:function(t){return _.intersection([this.compute_overlap(t)],[this.get("DIF_CHROMS"),this.get("BEFORE"),this.get("AFTER")]).length===0}});var l=Backbone.Collection.extend({model:h});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:h}]});var q=Backbone.Collection.extend({model:e});var b=Backbone.Model.extend({defaults:{data:null,min:0,max:0},initialize:function(u){var t=_.flatten(_.map(this.get("data"),function(v){if(v.data.length!==0){return _.map(v.data,function(w){return w[1]})}else{return 0}}));this.set("max",_.max(t));this.set("min",_.min(t))}});var m=Backbone.RelationalModel.extend({defaults:{data:null,min:0,max:0},initialize:function(u){var t=_.max(this.get("data"),function(v){if(!v||typeof v==="string"){return 0}return v[1]});this.attributes.max=(t&&typeof t!=="string"?t[1]:0)}});var s=Dataset.extend({initialize:function(t){this.set("id",t.dataset_id);var v=this.get("genome_wide_data");if(v){var u=(this.get("track_type")==="LineTrack"?b:m);this.set("genome_wide_data",new u(v))}}});var o=Backbone.RelationalModel.extend({defaults:{id:"",title:"",type:"",dbkey:"",tracks:null},relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:s}],url:function(){return galaxy_paths.get("visualization_url")},save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:_.extend({},o.prototype.defaults,{bookmarks:null,viewport:null})});var a=Backbone.Model.extend({});var i=Backbone.Router.extend({initialize:function(u){this.view=u.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var t=this;t.view.on("navigate",function(v){t.navigate(v)})},change_location:function(t){this.view.go_to(t)}});var j=function(t,v,u){$.ajax({url:t,data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(w){show_modal("Select datasets for new tracks",w,{Cancel:function(){hide_modal()},Add:function(){var x=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var y={data_type:"track_config",hda_ldda:"hda"},z=$(this).val();if($(this).attr("name")!=="id"){y.hda_ldda="ldda"}x[x.length]=$.ajax({url:v+"/"+z,data:y,dataType:"json"})});$.when.apply($,x).then(function(){var y=(arguments[0] instanceof Array?$.map(arguments,function(z){return z[0]}):[arguments[0]]);u(y)});hide_modal()}})}})};var r=(function(){if(typeof module!=="undefined"&&module.exports){return module.exports}else{if(typeof define==="function"&&define.amd){r={};define(function(){return r});return r}else{return window}}})();r.BrowserBookmark=e;r.BrowserBookmarkCollection=q;r.Cache=p;r.CanvasManager=g;r.Genome=c;r.GenomeDataManager=d;r.GenomeRegion=h;r.GenomeRegionCollection=l;r.GenomeVisualization=k;r.GenomeWideBigWigData=b;r.GenomeWideSummaryTreeData=m;r.ReferenceTrackDataManager=n;r.ServerStateDeferred=f;r.TrackBrowserRouter=i;r.TrackConfig=a;r.Visualization=o;r.add_datasets=j}).call(this);
\ No newline at end of file
+(function(){var k=function(u){return("isResolved" in u)};var f=Backbone.Model.extend({defaults:{ajax_settings:{},interval:1000,success_fn:function(u){return true}},go:function(){var x=$.Deferred(),w=this,z=w.get("ajax_settings"),y=w.get("success_fn"),v=w.get("interval"),u=function(){$.ajax(z).success(function(A){if(y(A)){x.resolve(A)}else{setTimeout(u,v)}})};u();return x}});var g=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};_.extend(g.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=q.extend({defaults:_.extend({},q.prototype.defaults,{dataset:null,filters_manager:null,data_type:"data",genome_wide_summary_data:null,data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),data_is_ready:function(){var w=this.get("dataset"),v=$.Deferred(),u=new f({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:w.get("hda_ldda"),data_type:"state"},dataType:"json"},interval:5000,success_fn:function(x){return x!=="pending"}});$.when(u.go()).then(function(x){v.resolve(x==="ok"||x==="data")});return v},search_features:function(u){var v=this.get("dataset"),w={query:u,dataset_id:v.id,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v},y=this.get("dataset");if(y){x.dataset_id=y.id;x.hda_ldda=y.get("hda_ldda")}$.extend(x,A);var D=this.get("filters_manager");if(D){var E=[];var u=D.filters;for(var z=0;z<u.length;z++){E.push(u[z].name)}x.filter_cols=JSON.stringify(E)}var w=this;return $.getJSON(y.url(),x,function(F){w.set_data(C,F)})},get_data:function(A,z,w,y){var B=this.get_elt(A);if(B&&(k(B)||this.get("data_mode_compatible")(B,z))){return B}var C=this.get("key_ary"),v=this.get("obj_cache"),D,u;for(var x=0;x<C.length;x++){D=C[x];u=new h({from_str:D});if(u.contains(A)){B=v[D];if(k(B)||(this.get("data_mode_compatible")(B,z)&&this.get("can_subset")(B))){this.move_key_to_end(D,x);return B}}}B=this.load_data(A,z,w,y);this.set_data(A,B);return B},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this.get_elt(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: no current data for: ",dataset,C.toString(),B,x,A);return}E.stale=true;var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var o=d.extend({load_data:function(u,x,y,v,w){if(v>1){return{data:null}}return d.prototype.load_data.call(this,u,x,y,v,w)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info}});var h=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new h({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return this.get("DIF_CHROMS")}if(z<x){if(y<x){u=this.get("BEFORE")}else{if(y<=w){u=this.get("OVERLAP_START")}else{u=this.get("CONTAINS")}}}else{if(z>w){u=this.get("AFTER")}else{if(y<=w){u=this.get("CONTAINED_BY")}else{u=this.get("OVERLAP_END")}}}return u},contains:function(u){return this.compute_overlap(u)===this.get("CONTAINS")},overlaps:function(u){return _.intersection([this.compute_overlap(u)],[this.get("DIF_CHROMS"),this.get("BEFORE"),this.get("AFTER")]).length===0}});var m=Backbone.Collection.extend({model:h});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:h}]});var r=Backbone.Collection.extend({model:e});var b=Backbone.Model.extend({defaults:{data:null,min:0,max:0},initialize:function(v){var u=_.flatten(_.map(this.get("data"),function(w){if(w.data.length!==0){return _.map(w.data,function(x){return x[1]})}else{return 0}}));this.set("max",_.max(u));this.set("min",_.min(u))}});var n=Backbone.RelationalModel.extend({defaults:{data:null,min:0,max:0},initialize:function(v){var u=_.max(this.get("data"),function(w){if(!w||typeof w==="string"){return 0}return w[1]});this.attributes.max=(u&&typeof u!=="string"?u[1]:0)}});var t=Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);var w=this.get("genome_wide_data");if(w){var v=(this.get("track_type")==="LineTrack"?b:n);this.set("genome_wide_data",new v(w))}}});var p=Backbone.RelationalModel.extend({defaults:{id:"",title:"",type:"",dbkey:"",tracks:null},relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],url:function(){return galaxy_paths.get("visualization_url")},save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var l=p.extend({defaults:_.extend({},p.prototype.defaults,{bookmarks:null,viewport:null})});var a=Backbone.Model.extend({});var i=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});var j=function(u,w,v){$.ajax({url:u,data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(x){show_modal("Select datasets for new tracks",x,{Cancel:function(){hide_modal()},Add:function(){var y=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var z={data_type:"track_config",hda_ldda:"hda"},A=$(this).val();if($(this).attr("name")!=="id"){z.hda_ldda="ldda"}y[y.length]=$.ajax({url:w+"/"+A,data:z,dataType:"json"})});$.when.apply($,y).then(function(){var z=(arguments[0] instanceof Array?$.map(arguments,function(A){return A[0]}):[arguments[0]]);v(z)});hide_modal()}})}})};var s=(function(){if(typeof module!=="undefined"&&module.exports){return module.exports}else{if(typeof define==="function"&&define.amd){s={};define(function(){return s});return s}else{return window}}})();s.BrowserBookmark=e;s.BrowserBookmarkCollection=r;s.Cache=q;s.CanvasManager=g;s.Genome=c;s.GenomeDataManager=d;s.GenomeRegion=h;s.GenomeRegionCollection=m;s.GenomeVisualization=l;s.GenomeWideBigWigData=b;s.GenomeWideSummaryTreeData=n;s.ReferenceTrackDataManager=o;s.ServerStateDeferred=f;s.TrackBrowserRouter=i;s.TrackConfig=a;s.Visualization=p;s.add_datasets=j}).call(this);
\ 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
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/4809c1f1265d/
changeset: 4809c1f1265d
user: natefoo
date: 2012-09-17 20:23:00
summary: I missed some missing indexes...
affected #: 1 file
diff -r 8c5b336f17620cf5e32c42f6a9443351edc41b78 -r 4809c1f1265d27420472b230fce282995aae02d8 lib/galaxy/model/migrate/versions/0106_add_missing_indexes.py
--- a/lib/galaxy/model/migrate/versions/0106_add_missing_indexes.py
+++ b/lib/galaxy/model/migrate/versions/0106_add_missing_indexes.py
@@ -20,21 +20,40 @@
db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
indexes = (
- ( "ix_metadata_file_lda_id", 'metadata_file', 'lda_id' ), # 0003
- ( "ix_history_importable", 'history', 'importable' ), # 0007
- ( "ix_sample_bar_code", 'sample', 'bar_code' ), # 0009
- ( "ix_request_type_deleted", 'request_type', 'deleted' ), # 0012
- ( "ix_galaxy_user_username", 'galaxy_user', 'username' ), # 0014
- ( "ix_form_definition_type", 'form_definition', 'type' ), # 0019
- ( "ix_form_definition_layout", 'form_definition', 'layout' ), # 0019
- ( "ix_job_library_folder_id", 'job', 'library_folder_id' ), # 0020
- ( "ix_galaxy_user_form_values_id", 'galaxy_user', 'form_values_id' ), # 0025
- ( "ix_sample_library_id", 'sample', 'library_id' ), # 0037
- ( "ix_sample_folder_id", 'sample', 'folder_id' ), # 0037
- ( "ix_request_notification", 'request', 'notification' ), # 0057
- ( "ix_sd_external_service_id", 'sample_dataset', 'external_service_id' ), # 0068
- ( "ix_job_handler", 'job', 'handler' ), # 0094
- ( "ix_galaxy_user_email", 'galaxy_user', 'email' ) # 0106
+ ( "ix_metadata_file_lda_id", 'metadata_file', 'lda_id' ), # 0003
+ ( "ix_history_importable", 'history', 'importable' ), # 0007
+ ( "ix_sample_bar_code", 'sample', 'bar_code' ), # 0009
+ ( "ix_request_type_deleted", 'request_type', 'deleted' ), # 0012
+ ( "ix_galaxy_user_username", 'galaxy_user', 'username' ), # 0014
+ ( "ix_form_definition_type", 'form_definition', 'type' ), # 0019
+ ( "ix_form_definition_layout", 'form_definition', 'layout' ), # 0019
+ ( "ix_job_library_folder_id", 'job', 'library_folder_id' ), # 0020
+ ( "ix_page_published", 'page', 'published' ), # 0023
+ ( "ix_page_deleted", 'page', 'deleted' ), # 0023
+ ( "ix_galaxy_user_form_values_id", 'galaxy_user', 'form_values_id' ), # 0025
+ ( "ix_lia_deleted", 'library_info_association', 'deleted' ), # 0036
+ ( "ix_lfia_deleted", 'library_folder_info_association', 'deleted' ), # 0036
+ ( "ix_lddia_deleted", 'library_dataset_dataset_info_association', 'deleted' ), # 0036
+ ( "ix_sample_library_id", 'sample', 'library_id' ), # 0037
+ ( "ix_sample_folder_id", 'sample', 'folder_id' ), # 0037
+ ( "ix_lia_inheritable", 'library_info_association', 'inheritable' ), # 0038
+ ( "ix_lfia_inheritable", 'library_folder_info_association', 'inheritable' ), # 0038
+ ( "ix_job_imported", 'job', 'imported' ), # 0051
+ ( "ix_request_notification", 'request', 'notification' ), # 0057
+ ( "ix_sd_external_service_id", 'sample_dataset', 'external_service_id' ), # 0068
+ ( "ix_icda_ldda_parent_id", 'implicitly_converted_dataset_association', 'ldda_parent_id' ), # 0073
+ ( "ix_library_dataset_purged", 'library_dataset', 'purged' ), # 0074
+ ( "ix_run_subindex", 'run', 'subindex' ), # 0075
+ ( "ix_history_dataset_association_purged", 'history_dataset_association', 'purged' ), # 0078
+ ( "ix_galaxy_user_disk_usage", 'galaxy_user', 'disk_usage' ), # 0078
+ ( "ix_galaxy_session_disk_usage", 'galaxy_session', 'disk_usage' ), # 0078
+ ( "ix_icda_ldda_id", 'implicitly_converted_dataset_association', 'ldda_id' ), # 0084
+ ( "ix_tsr_includes_datatypes", 'tool_shed_repository', 'includes_datatypes' ), # 0086
+ ( "ix_dataset_object_store_id", 'dataset', 'object_store_id' ), # 0089
+ ( "ix_job_object_store_id", 'job', 'object_store_id' ), # 0089
+ ( "ix_metadata_file_object_store_id", 'metadata_file', 'object_store_id' ), # 0089
+ ( "ix_job_handler", 'job', 'handler' ), # 0094
+ ( "ix_galaxy_user_email", 'galaxy_user', 'email' ) # 0106
)
def upgrade():
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: Index galaxy_user.email and add a bunch of indexes for columns added to existing tables that were supposed to be indexed.
by Bitbucket 17 Sep '12
by Bitbucket 17 Sep '12
17 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/8c5b336f1762/
changeset: 8c5b336f1762
user: natefoo
date: 2012-09-17 19:54:28
summary: Index galaxy_user.email and add a bunch of indexes for columns added to existing tables that were supposed to be indexed.
affected #: 2 files
diff -r 9afd6804c8be7f4360f41c1b71e3c77e8f71b756 -r 8c5b336f17620cf5e32c42f6a9443351edc41b78 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -43,7 +43,7 @@
Column( "id", Integer, primary_key=True),
Column( "create_time", DateTime, default=now ),
Column( "update_time", DateTime, default=now, onupdate=now ),
- Column( "email", TrimmedString( 255 ), nullable=False ),
+ Column( "email", TrimmedString( 255 ), index=True, nullable=False ),
Column( "username", TrimmedString( 255 ), index=True, unique=True ),
Column( "password", TrimmedString( 40 ), nullable=False ),
Column( "external", Boolean, default=False ),
diff -r 9afd6804c8be7f4360f41c1b71e3c77e8f71b756 -r 8c5b336f17620cf5e32c42f6a9443351edc41b78 lib/galaxy/model/migrate/versions/0106_add_missing_indexes.py
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0106_add_missing_indexes.py
@@ -0,0 +1,62 @@
+"""
+Migration script to create missing indexes. Adding new columns to existing tables via SQLAlchemy does not create the index, even if the column definition includes index=True.
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+
+import sys, logging
+log = logging.getLogger( __name__ )
+log.setLevel(logging.DEBUG)
+handler = logging.StreamHandler( sys.stdout )
+format = "%(name)s %(levelname)s %(asctime)s %(message)s"
+formatter = logging.Formatter( format )
+handler.setFormatter( formatter )
+log.addHandler( handler )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+indexes = (
+ ( "ix_metadata_file_lda_id", 'metadata_file', 'lda_id' ), # 0003
+ ( "ix_history_importable", 'history', 'importable' ), # 0007
+ ( "ix_sample_bar_code", 'sample', 'bar_code' ), # 0009
+ ( "ix_request_type_deleted", 'request_type', 'deleted' ), # 0012
+ ( "ix_galaxy_user_username", 'galaxy_user', 'username' ), # 0014
+ ( "ix_form_definition_type", 'form_definition', 'type' ), # 0019
+ ( "ix_form_definition_layout", 'form_definition', 'layout' ), # 0019
+ ( "ix_job_library_folder_id", 'job', 'library_folder_id' ), # 0020
+ ( "ix_galaxy_user_form_values_id", 'galaxy_user', 'form_values_id' ), # 0025
+ ( "ix_sample_library_id", 'sample', 'library_id' ), # 0037
+ ( "ix_sample_folder_id", 'sample', 'folder_id' ), # 0037
+ ( "ix_request_notification", 'request', 'notification' ), # 0057
+ ( "ix_sd_external_service_id", 'sample_dataset', 'external_service_id' ), # 0068
+ ( "ix_job_handler", 'job', 'handler' ), # 0094
+ ( "ix_galaxy_user_email", 'galaxy_user', 'email' ) # 0106
+)
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+
+ # Create missing indexes
+ for ix, table, col in indexes:
+ try:
+ log.debug("Creating index '%s' on column '%s' in table '%s'" % (ix, col, table))
+ t = Table( table, metadata, autoload=True )
+ Index( ix, t.c[col] ).create()
+ except Exception, e:
+ log.error("Unable to create index '%s': %s" % (ix, str(e)))
+
+def downgrade():
+ metadata.reflect()
+
+ # Drop indexes
+ for ix, table, col in indexes:
+ try:
+ t = Table( table, metadata, autoload=True )
+ Index( ix, t.c[col] ).drop()
+ except Exception, e:
+ log.error("Unable to drop index '%s': %s" % (ix, str(e)))
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: dannon: Set header 'X-Content-Type-Options: nosniff' for dataset display. This will prevent IE8 from trying to render as html datasets served as text/plain.
by Bitbucket 17 Sep '12
by Bitbucket 17 Sep '12
17 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/9afd6804c8be/
changeset: 9afd6804c8be
user: dannon
date: 2012-09-17 19:19:32
summary: Set header 'X-Content-Type-Options: nosniff' for dataset display. This will prevent IE8 from trying to render as html datasets served as text/plain.
affected #: 1 file
diff -r 81b2a6d001dcf2121bf38244775419596fa669bd -r 9afd6804c8be7f4360f41c1b71e3c77e8f71b756 lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -288,6 +288,9 @@
#Relocate all composite datatype display to a common location.
composite_extensions = trans.app.datatypes_registry.get_composite_extensions( )
composite_extensions.append('html') # for archiving composite datatypes
+ #Prevent IE8 from sniffing content type since we're explicit about it. This prevents intentionally text/plain
+ #content from being rendered in the browser
+ trans.response.headers['X-Content-Type-Options'] = 'nosniff'
if isinstance( data, basestring ):
return data
if filename and filename != "index":
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: More pgcleanup.py fixes and addition of cleanup event tables for library items.
by Bitbucket 17 Sep '12
by Bitbucket 17 Sep '12
17 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/81b2a6d001dc/
changeset: 81b2a6d001dc
user: natefoo
date: 2012-09-17 18:51:17
summary: More pgcleanup.py fixes and addition of cleanup event tables for library items.
affected #: 2 files
diff -r 80bd52837f23ba3873c8ed3d029086f739926874 -r 81b2a6d001dcf2121bf38244775419596fa669bd lib/galaxy/model/migrate/versions/0105_add_cleanup_event_table.py
--- a/lib/galaxy/model/migrate/versions/0105_add_cleanup_event_table.py
+++ b/lib/galaxy/model/migrate/versions/0105_add_cleanup_event_table.py
@@ -51,6 +51,30 @@
Column( "cleanup_event_id", Integer, ForeignKey( "cleanup_event.id" ), index=True, nullable=True ),
Column( "hda_id", Integer, ForeignKey( "history_dataset_association.id" ), index=True ) )
+CleanupEventLibraryAssociation_table = Table( "cleanup_event_library_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "cleanup_event_id", Integer, ForeignKey( "cleanup_event.id" ), index=True, nullable=True ),
+ Column( "library_id", Integer, ForeignKey( "library.id" ), index=True ) )
+
+CleanupEventLibraryFolderAssociation_table = Table( "cleanup_event_library_folder_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "cleanup_event_id", Integer, ForeignKey( "cleanup_event.id" ), index=True, nullable=True ),
+ Column( "library_folder_id", Integer, ForeignKey( "library_folder.id" ), index=True ) )
+
+CleanupEventLibraryDatasetAssociation_table = Table( "cleanup_event_library_dataset_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "cleanup_event_id", Integer, ForeignKey( "cleanup_event.id" ), index=True, nullable=True ),
+ Column( "library_dataset_id", Integer, ForeignKey( "library_dataset.id" ), index=True ) )
+
+CleanupEventLibraryDatasetDatasetAssociationAssociation_table = Table( "cleanup_event_ldda_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "cleanup_event_id", Integer, ForeignKey( "cleanup_event.id" ), index=True, nullable=True ),
+ Column( "ldda_id", Integer, ForeignKey( "library_dataset_dataset_association.id" ), index=True ) )
+
CleanupEventImplicitlyConvertedDatasetAssociationAssociation_table = Table( "cleanup_event_icda_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "create_time", DateTime, default=now ),
@@ -66,6 +90,10 @@
CleanupEventMetadataFileAssociation_table.create()
CleanupEventHistoryAssociation_table.create()
CleanupEventHistoryDatasetAssociationAssociation_table.create()
+ CleanupEventLibraryAssociation_table.create()
+ CleanupEventLibraryFolderAssociation_table.create()
+ CleanupEventLibraryDatasetAssociation_table.create()
+ CleanupEventLibraryDatasetDatasetAssociationAssociation_table.create()
CleanupEventImplicitlyConvertedDatasetAssociationAssociation_table.create()
except Exception, e:
log.debug( "Creating table failed: %s" % str( e ) )
@@ -74,6 +102,10 @@
metadata.reflect()
try:
CleanupEventImplicitlyConvertedDatasetAssociationAssociation_table.drop()
+ CleanupEventLibraryDatasetDatasetAssociationAssociation_table.drop()
+ CleanupEventLibraryDatasetAssociation_table.drop()
+ CleanupEventLibraryFolderAssociation_table.drop()
+ CleanupEventLibraryAssociation_table.drop()
CleanupEventHistoryDatasetAssociationAssociation_table.drop()
CleanupEventHistoryAssociation_table.drop()
CleanupEventMetadataFileAssociation_table.drop()
diff -r 80bd52837f23ba3873c8ed3d029086f739926874 -r 81b2a6d001dcf2121bf38244775419596fa669bd scripts/cleanup_datasets/pgcleanup.py
--- a/scripts/cleanup_datasets/pgcleanup.py
+++ b/scripts/cleanup_datasets/pgcleanup.py
@@ -71,6 +71,7 @@
parser.add_option('-o', '--older-than', type='int', dest='days', help='Only perform action(s) on objects that have not been updated since the specified number of days', default=14)
parser.add_option('-U', '--no-update-time', action='store_false', dest='update_time', help="Don't set update_time on updated objects", default=True)
parser.add_option('-s', '--sequence', dest='sequence', help='Comma-separated sequence of actions, chosen from: %s' % self.action_names, default='')
+ parser.add_option('-w', '--work-mem', dest='work_mem', help='Set PostgreSQL work_mem for this connection', default=None)
( self.options, self.args ) = parser.parse_args()
self.options.sequence = [ x.strip() for x in self.options.sequence.split(',') ]
@@ -160,11 +161,14 @@
self.__getattribute__(name)()
log.info('Finished %s' % name)
- def _create_event(self, message):
+ def _create_event(self, message=None):
"""
Create a new event in the cleanup_event table.
"""
+ if message is None:
+ message = inspect.stack()[1][3]
+
sql = """
INSERT INTO cleanup_event
(create_time, message)
@@ -177,6 +181,22 @@
args = (message,)
cur = self.conn.cursor()
+
+ if self.options.dry_run:
+ sql = "SELECT MAX(id) FROM cleanup_event;"
+ cur.execute(sql)
+ max_id = cur.fetchone()[0]
+ if max_id is None:
+ # there has to be at least one event in the table, if there are none just create a fake one.
+ sql = "INSERT INTO cleanup_event (create_time, message) VALUES (NOW(), 'dry_run_event') RETURNING id;"
+ cur.execute(sql)
+ max_id = cur.fetchone()[0]
+ self.conn.commit()
+ log.info("An event must exist for the subsequent query to succeed, so a dummy event has been created")
+ else:
+ log.info("Not executing event creation (increments sequence even when rolling back), using an old event ID (%i) for dry run" % max_id)
+ return max_id
+
log.info("Executing SQL")
cur.execute(sql, args)
log.info('Database status: %s' % cur.statusmessage)
@@ -190,6 +210,11 @@
log.debug('SQL is: %s' % sql)
cur = self.conn.cursor()
+
+ if self.options.work_mem is not None:
+ log.info('Setting work_mem to %s' % self.options.work_mem)
+ cur.execute('SET work_mem TO %s', (self.options.work_mem,))
+
log.info('Executing SQL')
cur.execute(sql, args)
log.info('Database status: %s' % cur.statusmessage)
@@ -275,7 +300,7 @@
"""
log.info('Marking purged all HistoryDatasetAssociations associated with purged Datasets')
- event_id = self._create_event(inspect.stack()[0][3])
+ event_id = self._create_event()
# update_time is intentionally left unmodified.
sql = """
@@ -312,7 +337,7 @@
"""
log.info('Marking deleted all userless Histories older than %i days' % self.options.days)
- event_id = self._create_event(inspect.stack()[0][3])
+ event_id = self._create_event()
sql = """
WITH deleted_history_ids
@@ -356,7 +381,7 @@
"""
log.info('Marking purged all deleted HistoryDatasetAssociations older than %i days' % self.options.days)
- event_id = self._create_event(inspect.stack()[0][3])
+ event_id = self._create_event()
sql = """
WITH purged_hda_ids
@@ -385,7 +410,8 @@
deleted_icda_purged_child_hda_ids
AS ( UPDATE history_dataset_association
SET purged = true%s
- FROM deleted_icda_ids where deleted_icda_ids.hda_id = history_dataset_association.id),
+ FROM deleted_icda_ids
+ WHERE deleted_icda_ids.hda_id = history_dataset_association.id),
hda_events
AS (INSERT INTO cleanup_event_hda_association
(create_time, cleanup_event_id, hda_id)
@@ -445,7 +471,7 @@
self.disk_accounting_user_ids.append(int(tup[1]))
if tup[2] is not None:
self._log('Purge of HDA %s caused deletion of MetadataFile: %s in Object Store: %s' % (tup[0], tup[2], tup[3]))
- self._remove_metadata_file(tup[2], tup[3], 'purge_deleted_hdas')
+ self._remove_metadata_file(tup[2], tup[3], inspect.stack()[0][3])
if tup[4] is not None:
self._log('Purge of HDA %s caused deletion of ImplicitlyConvertedDatasetAssociation: %s and converted HistoryDatasetAssociation: %s' % (tup[0], tup[4], tup[5]))
self._close_logfile()
@@ -457,7 +483,7 @@
"""
log.info('Marking purged all deleted histories that are older than the specified number of days.')
- event_id = self._create_event(inspect.stack()[0][3])
+ event_id = self._create_event()
sql = """
WITH purged_history_ids
@@ -494,7 +520,8 @@
deleted_icda_purged_child_hda_ids
AS ( UPDATE history_dataset_association
SET purged = true%s
- FROM deleted_icda_ids where deleted_icda_ids.hda_id = history_dataset_association.id),
+ FROM deleted_icda_ids
+ WHERE deleted_icda_ids.hda_id = history_dataset_association.id),
history_events
AS (INSERT INTO cleanup_event_history_association
(create_time, cleanup_event_id, history_id)
@@ -545,7 +572,7 @@
else:
if self.options.update_time:
update_time_sql += """,
- update_time = NOW()"""
+ update_time = NOW()"""
sql = sql % (update_time_sql, force_retry_sql, '%s', update_time_sql, update_time_sql, update_time_sql, update_time_sql, '%s', '%s', '%s', '%s', '%s')
args = (self.options.days, event_id, event_id, event_id, event_id, event_id)
@@ -561,7 +588,7 @@
self._log('Purge of History %s caused deletion of HistoryDatasetAssociation: %s' % (tup[0], tup[2]))
if tup[3] is not None:
self._log('Purge of HDA %s caused deletion of MetadataFile: %s in Object Store: %s' % (tup[1], tup[3], tup[4]))
- self._remove_metadata_file(tup[3], tup[4], 'purge_deleted_histories')
+ self._remove_metadata_file(tup[3], tup[4], inspect.stack()[0][3])
if tup[5] is not None:
self._log('Purge of HDA %s caused deletion of ImplicitlyConvertedDatasetAssociation: %s and converted HistoryDatasetAssociation: %s' % (tup[1], tup[5], tup[6]))
self._close_logfile()
@@ -572,7 +599,7 @@
"""
log.info('Marking deleted all Datasets that are derivative of JobExportHistoryArchives that are older than the specified number of days.')
- event_id = self._create_event(inspect.stack()[0][3])
+ event_id = self._create_event()
sql = """
WITH deleted_dataset_ids
@@ -596,7 +623,7 @@
update_time_sql = ""
if self.options.update_time:
update_time_sql += """,
- update_time = NOW()"""
+ update_time = NOW()"""
sql = sql % (update_time_sql, '%s', '%s')
args = (self.options.days, event_id)
@@ -614,7 +641,7 @@
"""
log.info('Marking deleted all Datasets whose associations are all marked as deleted/purged that are older than the specified number of days.')
- event_id = self._create_event(inspect.stack()[0][3])
+ event_id = self._create_event()
sql = """
WITH deleted_dataset_ids
@@ -663,7 +690,7 @@
"""
log.info('Marking purged all Datasets marked deleted that are older than the specified number of days.')
- event_id = self._create_event(inspect.stack()[0][3])
+ event_id = self._create_event()
sql = """
WITH purged_dataset_ids
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

17 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/80bd52837f23/
changeset: 80bd52837f23
user: natefoo
date: 2012-09-17 18:47:13
summary: Fix a typo in library permissions check.
affected #: 1 file
diff -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 -r 80bd52837f23ba3873c8ed3d029086f739926874 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -232,7 +232,7 @@
raise ItemOwnershipException( "%s is not owned by the current user" % item.__class__.__name__, type='error' )
if check_accessible:
if type( item ) in ( trans.app.model.LibraryFolder, trans.app.model.LibraryDatasetDatasetAssociation, trans.app.model.LibraryDataset ):
- if not ( trans.user_is_admin() or trans.app.security_agent.can_access_library_i9tem( trans.get_current_user_roles(), item, trans.user ) ):
+ if not ( trans.user_is_admin() or trans.app.security_agent.can_access_library_item( trans.get_current_user_roles(), item, trans.user ) ):
raise ItemAccessibilityException( "%s is not accessible to the current user" % item.__class__.__name__, type='error' )
else:
# Verify accessible.
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: Data providers framework enhancements: (a) add registry object; (b) move all provider lookup code into registry; and (c) integrate ColumnDataProvider into raw_data requests.
by Bitbucket 17 Sep '12
by Bitbucket 17 Sep '12
17 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/08f1d09a65a9/
changeset: 08f1d09a65a9
user: jgoecks
date: 2012-09-17 18:29:48
summary: Data providers framework enhancements: (a) add registry object; (b) move all provider lookup code into registry; and (c) integrate ColumnDataProvider into raw_data requests.
affected #: 12 files
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -13,6 +13,7 @@
import galaxy.quota
from galaxy.tags.tag_handler import GalaxyTagHandler
from galaxy.visualization.genomes import Genomes
+from galaxy.visualization.data_providers.registry import DataProviderRegistry
from galaxy.tools.imp_exp import load_history_imp_exp_tools
from galaxy.tools.genome_index import load_genome_index_tools
from galaxy.sample_tracking import external_service_types
@@ -73,6 +74,8 @@
self.tag_handler = GalaxyTagHandler()
# Genomes
self.genomes = Genomes( self )
+ # Data providers registry.
+ self.data_provider_registry = DataProviderRegistry()
# Tool data tables
self.tool_data_tables = galaxy.tools.data.ToolDataTableManager( self.config.tool_data_path, self.config.tool_data_table_config_path )
# Initialize the tools, making sure the list of tool configs includes the reserved migrated_tools_conf.xml file.
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/visualization/data_providers.py
--- a/lib/galaxy/visualization/data_providers.py
+++ /dev/null
@@ -1,93 +0,0 @@
-import sys
-
-class BaseDataProvider( object ):
- """
- Base class for data providers. Data providers (a) read and package data from datasets;
- and (b) write subsets of data to new datasets.
- """
-
- def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None,
- error_max_vals="Only the first %i values are returned." ):
- """ Create basic data provider. """
- self.converted_dataset = converted_dataset
- self.original_dataset = original_dataset
- self.dependencies = dependencies
- self.error_max_vals = error_max_vals
-
- def has_data( self, **kwargs ):
- """
- Returns true if dataset has data in the specified genome window, false
- otherwise.
- """
- raise Exception( "Unimplemented Function" )
-
- def get_iterator( self, **kwargs ):
- """
- Returns an iterator that provides data in the region chrom:start-end
- """
- raise Exception( "Unimplemented Function" )
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Process data from an iterator to a format that can be provided to client.
- """
- raise Exception( "Unimplemented Function" )
-
- def get_data( self, start_val=0, max_vals=sys.maxint, **kwargs ):
- """
- Returns data as specified by kwargs. start_val is the first element to
- return and max_vals indicates the number of values to return.
-
- Return value must be a dictionary with the following attributes:
- dataset_type, data
- """
- iterator = self.get_iterator( chrom, start, end )
- return self.process_data( iterator, start_val, max_vals, **kwargs )
- def write_data_to_file( self, filename, **kwargs ):
- """
- Write data in region defined by chrom, start, and end to a file.
- """
- raise Exception( "Unimplemented Function" )
-
-class ColumnDataProvider( BaseDataProvider ):
- """ Data provider for columnar data """
-
- def __init__( self, original_dataset ):
- # Compatibility check.
- if not isinstance( original_dataset.datatype, Tabular ):
- raise Exception( "Data provider can only be used with tabular data" )
-
- # Attribute init.
- self.original_dataset = original_dataset
-
- def get_data( self, cols, start_val=0, max_vals=sys.maxint ):
- """
- Returns data from specified columns in dataset. Format is list of lists
- where each list is a line of data.
- """
-
- def cast_val( val, type ):
- """ Cast value based on type. """
- if type == 'int':
- try: val = int( val )
- except: pass
- elif type == 'float':
- try: val = float( val )
- except: pass
- return val
-
- data = []
- f = open( self.original_dataset.file_name )
- for count, line in enumerate( f ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
-
- fields = line.split()
- data.append( [ cast_val( fields[c], self.original_dataset.metadata.column_types[c] ) for c in cols ] )
-
- f.close()
-
- return data
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/visualization/data_providers/__init__.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers/__init__.py
@@ -0,0 +1,3 @@
+"""
+Galaxy visualization/visual analysis data providers.
+"""
\ No newline at end of file
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/visualization/data_providers/basic.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers/basic.py
@@ -0,0 +1,156 @@
+import sys
+from galaxy.datatypes.tabular import Tabular
+from galaxy.util.json import from_json_string
+
+class BaseDataProvider( object ):
+ """
+ Base class for data providers. Data providers (a) read and package data from datasets;
+ and (b) write subsets of data to new datasets.
+ """
+
+ def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None,
+ error_max_vals="Only the first %i values are returned." ):
+ """ Create basic data provider. """
+ self.converted_dataset = converted_dataset
+ self.original_dataset = original_dataset
+ self.dependencies = dependencies
+ self.error_max_vals = error_max_vals
+
+ def has_data( self, **kwargs ):
+ """
+ Returns true if dataset has data in the specified genome window, false
+ otherwise.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def get_iterator( self, **kwargs ):
+ """
+ Returns an iterator that provides data in the region chrom:start-end
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Process data from an iterator to a format that can be provided to client.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def get_data( self, start_val=0, max_vals=sys.maxint, **kwargs ):
+ """
+ Returns data as specified by kwargs. start_val is the first element to
+ return and max_vals indicates the number of values to return.
+
+ Return value must be a dictionary with the following attributes:
+ dataset_type, data
+ """
+ iterator = self.get_iterator( chrom, start, end )
+ return self.process_data( iterator, start_val, max_vals, **kwargs )
+ def write_data_to_file( self, filename, **kwargs ):
+ """
+ Write data in region defined by chrom, start, and end to a file.
+ """
+ raise Exception( "Unimplemented Function" )
+
+class ColumnDataProvider( BaseDataProvider ):
+ """ Data provider for columnar data """
+
+ def __init__( self, original_dataset ):
+ # Compatibility check.
+ if not isinstance( original_dataset.datatype, Tabular ):
+ raise Exception( "Data provider can only be used with tabular data" )
+
+ # Attribute init.
+ self.original_dataset = original_dataset
+
+ def get_data( self, cols, start_val=0, max_vals=sys.maxint, **kwargs ):
+ """
+ Returns data from specified columns in dataset. Format is list of lists
+ where each list is a line of data.
+ """
+
+ cols = from_json_string( cols )
+
+ def cast_val( val, type ):
+ """ Cast value based on type. """
+ if type == 'int':
+ try: val = int( val )
+ except: pass
+ elif type == 'float':
+ try: val = float( val )
+ except: pass
+ return val
+
+ data = []
+ f = open( self.original_dataset.file_name )
+ for count, line in enumerate( f ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+
+ fields = line.split()
+ data.append( [ cast_val( fields[c], self.original_dataset.metadata.column_types[c] ) for c in cols ] )
+
+ f.close()
+
+ return data
+
+class DataProviderRegistry( object ):
+ """
+ Registry for data providers that enables listing and lookup.
+ """
+
+ def __init__( self ):
+ # Mapping from dataset type name to a class that can fetch data from a file of that
+ # type. First key is converted dataset type; if result is another dict, second key
+ # is original dataset type. TODO: This needs to be more flexible.
+ self.dataset_type_name_to_data_provider = {
+ "tabix": {
+ Vcf: VcfTabixDataProvider,
+ Bed: BedTabixDataProvider,
+ Gtf: GtfTabixDataProvider,
+ ENCODEPeak: ENCODEPeakTabixDataProvider,
+ Interval: IntervalTabixDataProvider,
+ ChromatinInteractions: ChromatinInteractionsTabixDataProvider,
+ "default" : TabixDataProvider
+ },
+ "interval_index": IntervalIndexDataProvider,
+ "bai": BamDataProvider,
+ "bam": SamDataProvider,
+ "summary_tree": SummaryTreeDataProvider,
+ "bigwig": BigWigDataProvider,
+ "bigbed": BigBedDataProvider
+ }
+
+ def get_data_provider( name=None, original_dataset=None ):
+ """
+ Returns data provider class by name and/or original dataset.
+ """
+ data_provider = None
+ if name:
+ value = dataset_type_name_to_data_provider[ name ]
+ if isinstance( value, dict ):
+ # Get converter by dataset extension; if there is no data provider,
+ # get the default.
+ data_provider = value.get( original_dataset.datatype.__class__, value.get( "default" ) )
+ else:
+ data_provider = value
+ elif original_dataset:
+ # Look up data provider from datatype's informaton.
+ try:
+ # Get data provider mapping and data provider for 'data'. If
+ # provider available, use it; otherwise use generic provider.
+ _ , data_provider_mapping = original_dataset.datatype.get_track_type()
+ if 'data_standalone' in data_provider_mapping:
+ data_provider_name = data_provider_mapping[ 'data_standalone' ]
+ else:
+ data_provider_name = data_provider_mapping[ 'data' ]
+ if data_provider_name:
+ data_provider = self.get_data_provider( name=data_provider_name, original_dataset=original_dataset )
+ else:
+ data_provider = GenomeDataProvider
+ except:
+ pass
+ return data_provider
+
\ No newline at end of file
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/visualization/data_providers/genome.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers/genome.py
@@ -0,0 +1,1512 @@
+"""
+Data providers for genome visualizations.
+"""
+
+import os, sys
+from math import ceil, log
+import pkg_resources
+pkg_resources.require( "bx-python" )
+if sys.version_info[:2] == (2, 4):
+ pkg_resources.require( "ctypes" )
+pkg_resources.require( "pysam" )
+pkg_resources.require( "numpy" )
+import numpy
+from galaxy.datatypes.util.gff_util import *
+from galaxy.util.json import from_json_string
+from bx.interval_index_file import Indexes
+from bx.bbi.bigwig_file import BigWigFile
+from galaxy.util.lrucache import LRUCache
+from galaxy.visualization.tracks.summary import *
+from galaxy.visualization.data_providers.basic import BaseDataProvider
+import galaxy_utils.sequence.vcf
+from galaxy.datatypes.tabular import Tabular, Vcf
+from galaxy.datatypes.interval import Interval, Bed, Gff, Gtf, ENCODEPeak, ChromatinInteractions
+
+from pysam import csamtools, ctabix
+
+#
+# Utility functions.
+#
+
+def float_nan(n):
+ '''
+ Return None instead of NaN to pass jQuery 1.4's strict JSON
+ '''
+ if n != n: # NaN != NaN
+ return None
+ else:
+ return float(n)
+
+def get_bounds( reads, start_pos_index, end_pos_index ):
+ '''
+ Returns the minimum and maximum position for a set of reads.
+ '''
+ max_low = sys.maxint
+ max_high = -sys.maxint
+ for read in reads:
+ if read[ start_pos_index ] < max_low:
+ max_low = read[ start_pos_index ]
+ if read[ end_pos_index ] > max_high:
+ max_high = read[ end_pos_index ]
+ return max_low, max_high
+
+def _convert_between_ucsc_and_ensemble_naming( chrom ):
+ '''
+ Convert between UCSC chromosome ('chr1') naming conventions and Ensembl
+ naming conventions ('1')
+ '''
+ if chrom.startswith( 'chr' ):
+ # Convert from UCSC to Ensembl
+ return chrom[ 3: ]
+ else:
+ # Convert from Ensembl to UCSC
+ return 'chr' + chrom
+
+def _chrom_naming_matches( chrom1, chrom2 ):
+ return ( chrom1.startswith( 'chr' ) and chrom2.startswith( 'chr' ) ) or ( not chrom1.startswith( 'chr' ) and not chrom2.startswith( 'chr' ) )
+
+class FeatureLocationIndexDataProvider( BaseDataProvider ):
+ """
+ Reads/writes/queries feature location index (FLI) datasets.
+ """
+
+ def __init__( self, converted_dataset ):
+ self.converted_dataset = converted_dataset
+
+ def get_data( self, query ):
+ # Init.
+ textloc_file = open( self.converted_dataset.file_name, 'r' )
+ line_len = int( textloc_file.readline() )
+ file_len = os.path.getsize( self.converted_dataset.file_name )
+ query = query.lower()
+
+ # Find query in file using binary search.
+ low = 0
+ high = file_len / line_len
+ while low < high:
+ mid = ( low + high ) // 2
+ position = mid * line_len
+ textloc_file.seek( position )
+
+ # Compare line with query and update low, high.
+ line = textloc_file.readline()
+ if line < query:
+ low = mid + 1
+ else:
+ high = mid
+
+ position = low * line_len
+
+ # At right point in file, generate hits.
+ result = []
+ while True:
+ line = textloc_file.readline()
+ if not line.startswith( query ):
+ break
+ if line[ -1: ] == '\n':
+ line = line[ :-1 ]
+ result.append( line.split()[1:] )
+
+ textloc_file.close()
+ return result
+
+class GenomeDataProvider( BaseDataProvider ):
+ """ Base class for genome data providers. """
+
+ """
+ Mapping from column name to payload data; this mapping is used to create
+ filters. Key is column name, value is a dict with mandatory key 'index' and
+ optional key 'name'. E.g. this defines column 4
+
+ col_name_data_attr_mapping = {4 : { index: 5, name: 'Score' } }
+ """
+ col_name_data_attr_mapping = {}
+
+ def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None,
+ error_max_vals="Only the first %i %s in this region are displayed." ):
+ super( GenomeDataProvider, self ).__init__( converted_dataset=converted_dataset,
+ original_dataset=original_dataset,
+ dependencies=dependencies,
+ error_max_vals=error_max_vals )
+
+ def write_data_to_file( self, regions, filename ):
+ """
+ Write data in region defined by chrom, start, and end to a file.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def valid_chroms( self ):
+ """
+ Returns chroms/contigs that the dataset contains
+ """
+ return None # by default
+
+ def has_data( self, chrom, start, end, **kwargs ):
+ """
+ Returns true if dataset has data in the specified genome window, false
+ otherwise.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def get_iterator( self, chrom, start, end ):
+ """
+ Returns an iterator that provides data in the region chrom:start-end
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Process data from an iterator to a format that can be provided to client.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def get_data( self, chrom=None, low=None, high=None, start_val=0, max_vals=sys.maxint, **kwargs ):
+ """
+ Returns data in region defined by chrom, start, and end. start_val and
+ max_vals are used to denote the data to return: start_val is the first element to
+ return and max_vals indicates the number of values to return.
+
+ Return value must be a dictionary with the following attributes:
+ dataset_type, data
+ """
+ start, end = int( low ), int( high )
+ iterator = self.get_iterator( chrom, start, end )
+ return self.process_data( iterator, start_val, max_vals, **kwargs )
+
+ def get_genome_data( self, chroms_info, **kwargs ):
+ """
+ Returns data for complete genome.
+ """
+ dataset_summary = []
+ for chrom_info in chroms_info[ 'chrom_info' ]:
+ summary = self.get_data( chrom_info[ 'chrom' ], 0, chrom_info[ 'len' ], **kwargs )
+ dataset_summary.append( summary )
+
+ return dataset_summary
+
+ def get_filters( self ):
+ """
+ Returns filters for provider's data. Return value is a list of
+ filters; each filter is a dictionary with the keys 'name', 'index', 'type'.
+ NOTE: This method uses the original dataset's datatype and metadata to
+ create the filters.
+ """
+ # Get column names.
+ try:
+ column_names = self.original_dataset.datatype.column_names
+ except AttributeError:
+ try:
+ column_names = range( self.original_dataset.metadata.columns )
+ except: # Give up
+ return []
+
+ # Dataset must have column types; if not, cannot create filters.
+ try:
+ column_types = self.original_dataset.metadata.column_types
+ except AttributeError:
+ return []
+
+ # Create and return filters.
+ filters = []
+ if self.original_dataset.metadata.viz_filter_cols:
+ for viz_col_index in self.original_dataset.metadata.viz_filter_cols:
+ # Some columns are optional, so can't assume that a filter
+ # column is in dataset.
+ if viz_col_index >= len( column_names ):
+ continue;
+ col_name = column_names[ viz_col_index ]
+ # Make sure that column has a mapped index. If not, do not add filter.
+ try:
+ attrs = self.col_name_data_attr_mapping[ col_name ]
+ except KeyError:
+ continue
+ filters.append(
+ { 'name' : attrs[ 'name' ], 'type' : column_types[viz_col_index], \
+ 'index' : attrs[ 'index' ] } )
+ return filters
+
+ def get_default_max_vals( self ):
+ return 5000
+
+#
+# -- Base mixins and providers --
+#
+
+class FilterableMixin:
+ def get_filters( self ):
+ """ Returns a dataset's filters. """
+
+ # is_ functions taken from Tabular.set_meta
+ def is_int( column_text ):
+ try:
+ int( column_text )
+ return True
+ except:
+ return False
+ def is_float( column_text ):
+ try:
+ float( column_text )
+ return True
+ except:
+ if column_text.strip().lower() == 'na':
+ return True #na is special cased to be a float
+ return False
+
+ #
+ # Get filters.
+ # TODOs:
+ # (a) might be useful to move this into each datatype's set_meta method;
+ # (b) could look at first N lines to ensure GTF attribute types are consistent.
+ #
+ filters = []
+ # HACK: first 8 fields are for drawing, so start filter column index at 9.
+ filter_col = 8
+ if isinstance( self.original_dataset.datatype, Gff ):
+ # Can filter by score and GTF attributes.
+ filters = [ { 'name': 'Score',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c6' } ]
+ filter_col += 1
+ if isinstance( self.original_dataset.datatype, Gtf ):
+ # Create filters based on dataset metadata.
+ for name, a_type in self.original_dataset.metadata.attribute_types.items():
+ if a_type in [ 'int', 'float' ]:
+ filters.append(
+ { 'name': name,
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'gff_filter_by_attribute',
+ 'tool_exp_name': name } )
+ filter_col += 1
+
+ '''
+ # Old code: use first line in dataset to find attributes.
+ for i, line in enumerate( open(self.original_dataset.file_name) ):
+ if not line.startswith('#'):
+ # Look at first line for attributes and types.
+ attributes = parse_gff_attributes( line.split('\t')[8] )
+ for attr, value in attributes.items():
+ # Get attribute type.
+ if is_int( value ):
+ attr_type = 'int'
+ elif is_float( value ):
+ attr_type = 'float'
+ else:
+ attr_type = 'str'
+ # Add to filters.
+ if attr_type is not 'str':
+ filters.append( { 'name': attr, 'type': attr_type, 'index': filter_col } )
+ filter_col += 1
+ break
+ '''
+ elif isinstance( self.original_dataset.datatype, Bed ):
+ # Can filter by score column only.
+ filters = [ { 'name': 'Score',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c5'
+ } ]
+
+ return filters
+
+
+class TabixDataProvider( FilterableMixin, GenomeDataProvider ):
+ """
+ Tabix index data provider for the Galaxy track browser.
+ """
+
+ col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } }
+
+ def get_iterator( self, chrom, start, end ):
+ start, end = int(start), int(end)
+ if end >= (2<<29):
+ end = (2<<29 - 1) # Tabix-enforced maximum
+
+ bgzip_fname = self.dependencies['bgzip'].file_name
+
+ tabix = ctabix.Tabixfile(bgzip_fname, index_filename=self.converted_dataset.file_name)
+
+ # If chrom not in data, try alternative.
+ if chrom not in tabix.contigs:
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+
+ return tabix.fetch(reference=chrom, start=start, end=end)
+
+ def write_data_to_file( self, regions, filename ):
+ out = open( filename, "w" )
+
+ for region in regions:
+ # Write data in region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+ iterator = self.get_iterator( chrom, start, end )
+ for line in iterator:
+ out.write( "%s\n" % line )
+
+ out.close()
+
+#
+# -- Interval data providers --
+#
+
+class IntervalDataProvider( GenomeDataProvider ):
+ """
+ Processes BED data from native format to payload format.
+
+ Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ raise Exception( "Unimplemented Function" )
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Provides
+ """
+ # Build data to return. Payload format is:
+ # [ <guid/offset>, <start>, <end>, <name>, <strand> ]
+ #
+ # First three entries are mandatory, others are optional.
+ #
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ rval = []
+ message = None
+ # Subtract one b/c columns are 1-based but indices are 0-based.
+ col_fn = lambda col: None if col is None else col - 1
+ start_col = self.original_dataset.metadata.startCol - 1
+ end_col = self.original_dataset.metadata.endCol - 1
+ strand_col = col_fn( self.original_dataset.metadata.strandCol )
+ name_col = col_fn( self.original_dataset.metadata.nameCol )
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+
+ feature = line.split()
+ length = len(feature)
+ # Unique id is just a hash of the line
+ payload = [ hash(line), int( feature[start_col] ), int( feature [end_col] ) ]
+
+ if no_detail:
+ rval.append( payload )
+ continue
+
+ # Name, strand.
+ if name_col:
+ payload.append( feature[name_col] )
+ if strand_col:
+ # Put empty name as placeholder.
+ if not name_col: payload.append( "" )
+ payload.append( feature[strand_col] )
+
+ # Score (filter data)
+ if length >= 5 and filter_cols and filter_cols[0] == "Score":
+ try:
+ payload.append( float( feature[4] ) )
+ except:
+ payload.append( feature[4] )
+
+ rval.append( payload )
+
+ return { 'data': rval, 'message': message }
+
+ def write_data_to_file( self, regions, filename ):
+ raise Exception( "Unimplemented Function" )
+
+class IntervalTabixDataProvider( TabixDataProvider, IntervalDataProvider ):
+ """
+ Provides data from a BED file indexed via tabix.
+ """
+ pass
+
+
+#
+# -- BED data providers --
+#
+
+class BedDataProvider( GenomeDataProvider ):
+ """
+ Processes BED data from native format to payload format.
+
+ Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ raise Exception( "Unimplemented Method" )
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Provides
+ """
+ # Build data to return. Payload format is:
+ # [ <guid/offset>, <start>, <end>, <name>, <strand>, <thick_start>,
+ # <thick_end>, <blocks> ]
+ #
+ # First three entries are mandatory, others are optional.
+ #
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ rval = []
+ message = None
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+ # TODO: can we use column metadata to fill out payload?
+ # TODO: use function to set payload data
+
+ feature = line.split()
+ length = len(feature)
+ # Unique id is just a hash of the line
+ payload = [ hash(line), int(feature[1]), int(feature[2]) ]
+
+ if no_detail:
+ rval.append( payload )
+ continue
+
+ # Name, strand, thick start, thick end.
+ if length >= 4:
+ payload.append(feature[3])
+ if length >= 6:
+ payload.append(feature[5])
+ if length >= 8:
+ payload.append(int(feature[6]))
+ payload.append(int(feature[7]))
+
+ # Blocks.
+ if length >= 12:
+ block_sizes = [ int(n) for n in feature[10].split(',') if n != '']
+ block_starts = [ int(n) for n in feature[11].split(',') if n != '' ]
+ blocks = zip( block_sizes, block_starts )
+ payload.append( [ ( int(feature[1]) + block[1], int(feature[1]) + block[1] + block[0] ) for block in blocks ] )
+
+ # Score (filter data)
+ if length >= 5 and filter_cols and filter_cols[0] == "Score":
+ # If dataset doesn't have name/strand/thick start/thick end/blocks,
+ # add placeholders. There should be 8 entries if all attributes
+ # are present.
+ payload.extend( [ None for i in range( 8 - len( payload ) ) ] )
+
+ try:
+ payload.append( float( feature[4] ) )
+ except:
+ payload.append( feature[4] )
+
+ rval.append( payload )
+
+ return { 'data': rval, 'message': message }
+
+ def write_data_to_file( self, regions, filename ):
+ out = open( filename, "w" )
+
+ for region in regions:
+ # Write data in region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+ iterator = self.get_iterator( chrom, start, end )
+ for line in iterator:
+ out.write( "%s\n" % line )
+
+ out.close()
+
+class BedTabixDataProvider( TabixDataProvider, BedDataProvider ):
+ """
+ Provides data from a BED file indexed via tabix.
+ """
+ pass
+
+class RawBedDataProvider( BedDataProvider ):
+ """
+ Provide data from BED file.
+
+ NOTE: this data provider does not use indices, and hence will be very slow
+ for large datasets.
+ """
+
+ def get_iterator( self, chrom=None, start=None, end=None ):
+ # Read first line in order to match chrom naming format.
+ line = source.readline()
+ dataset_chrom = line.split()[0]
+ if not _chrom_naming_matches( chrom, dataset_chrom ):
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ # Undo read.
+ source.seek( 0 )
+
+ def line_filter_iter():
+ for line in open( self.original_dataset.file_name ):
+ if line.startswith( "track" ) or line.startswith( "browser" ):
+ continue
+ feature = line.split()
+ feature_chrom = feature[0]
+ feature_start = int( feature[1] )
+ feature_end = int( feature[2] )
+ if ( chrom is not None and feature_chrom != chrom ) \
+ or ( start is not None and feature_start > end ) \
+ or ( end is not None and feature_end < start ):
+ continue
+ yield line
+
+ return line_filter_iter()
+
+#
+# -- VCF data providers --
+#
+
+class VcfDataProvider( GenomeDataProvider ):
+ """
+ Abstract class that processes VCF data from native format to payload format.
+
+ Payload format: TODO
+ """
+
+ col_name_data_attr_mapping = { 'Qual' : { 'index': 6 , 'name' : 'Qual' } }
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Returns a dict with the following attributes:
+ data - a list of variants with the format
+ [<guid>, <start>, <end>, <name>, cigar, seq]
+
+ message - error/informative message
+ """
+ rval = []
+ message = None
+
+ def get_mapping( ref, alt ):
+ """
+ Returns ( offset, new_seq, cigar ) tuple that defines mapping of
+ alt to ref. Cigar format is an array of [ op_index, length ] pairs
+ where op_index is the 0-based index into the string "MIDNSHP=X"
+ """
+
+ cig_ops = "MIDNSHP=X"
+
+ ref_len = len( ref )
+ alt_len = len( alt )
+
+ # Substitutions?
+ if ref_len == alt_len:
+ return 0, alt, [ [ cig_ops.find( "M" ), ref_len ] ]
+
+ # Deletions?
+ alt_in_ref_index = ref.find( alt )
+ if alt_in_ref_index != -1:
+ return alt_in_ref_index, ref[ alt_in_ref_index + 1: ], [ [ cig_ops.find( "D" ), ref_len - alt_len ] ]
+
+ # Insertions?
+ ref_in_alt_index = alt.find( ref )
+ if ref_in_alt_index != -1:
+ return ref_in_alt_index, alt[ ref_in_alt_index + 1: ], [ [ cig_ops.find( "I" ), alt_len - ref_len ] ]
+
+ # Pack data.
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+
+ feature = line.split()
+ start = int( feature[1] ) - 1
+ ref = feature[3]
+ alts = feature[4]
+
+ # HACK? alts == '.' --> monomorphism.
+ if alts == '.':
+ alts = ref
+
+ # Pack variants.
+ for alt in alts.split(","):
+ offset, new_seq, cigar = get_mapping( ref, alt )
+ start += offset
+ end = start + len( new_seq )
+
+ # Pack line.
+ payload = [
+ hash( line ),
+ start,
+ end,
+ # ID:
+ feature[2],
+ cigar,
+ # TODO? VCF does not have strand, so default to positive.
+ "+",
+ new_seq,
+ None if feature[5] == '.' else float( feature[5] )
+ ]
+ rval.append(payload)
+
+ return { 'data': rval, 'message': message }
+
+ def write_data_to_file( self, regions, filename ):
+ out = open( filename, "w" )
+
+ for region in regions:
+ # Write data in region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+ iterator = self.get_iterator( chrom, start, end )
+ for line in iterator:
+ out.write( "%s\n" % line )
+ out.close()
+
+class VcfTabixDataProvider( TabixDataProvider, VcfDataProvider ):
+ """
+ Provides data from a VCF file indexed via tabix.
+ """
+ pass
+
+class RawVcfDataProvider( VcfDataProvider ):
+ """
+ Provide data from VCF file.
+
+ NOTE: this data provider does not use indices, and hence will be very slow
+ for large datasets.
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ # Read first line in order to match chrom naming format.
+ line = source.readline()
+ dataset_chrom = line.split()[0]
+ if not _chrom_naming_matches( chrom, dataset_chrom ):
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ # Undo read.
+ source.seek( 0 )
+
+ def line_filter_iter():
+ for line in open( self.original_dataset.file_name ):
+ if line.startswith("#"):
+ continue
+ variant = line.split()
+ variant_chrom, variant_start, id, ref, alts = variant[ 0:5 ]
+ variant_start = int( variant_start )
+ longest_alt = -1
+ for alt in alts:
+ if len( alt ) > longest_alt:
+ longest_alt = len( alt )
+ variant_end = variant_start + abs( len( ref ) - longest_alt )
+ if variant_chrom != chrom or variant_start > end or variant_end < start:
+ continue
+ yield line
+
+ return line_filter_iter()
+
+class SummaryTreeDataProvider( GenomeDataProvider ):
+ """
+ Summary tree data provider for the Galaxy track browser.
+ """
+
+ CACHE = LRUCache( 20 ) # Store 20 recently accessed indices for performance
+
+ def valid_chroms( self ):
+ st = summary_tree_from_file( self.converted_dataset.file_name )
+ return st.chrom_blocks.keys()
+
+ def get_data( self, chrom, start, end, level=None, resolution=None, detail_cutoff=None, draw_cutoff=None ):
+ """
+ Returns summary tree data for a given genomic region.
+ """
+ filename = self.converted_dataset.file_name
+ st = self.CACHE[filename]
+ if st is None:
+ st = summary_tree_from_file( self.converted_dataset.file_name )
+ self.CACHE[filename] = st
+
+ # Look for chrom in tree using both naming conventions.
+ if chrom not in st.chrom_blocks:
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ if chrom not in st.chrom_blocks:
+ return None
+
+ # Get or compute level.
+ if level:
+ level = int( level )
+ elif resolution:
+ resolution = max( 1, ceil( float( resolution ) ) )
+ level = ceil( log( resolution, st.block_size ) ) - 1
+ level = int( max( level, 0 ) )
+ else:
+ # Either level or resolution is required.
+ return None
+
+ if level <= 1:
+ return "detail"
+
+ # Use level to get results.
+ stats = st.chrom_stats[ chrom ]
+ results = st.query( chrom, int(start), int(end), level, detail_cutoff=detail_cutoff, draw_cutoff=draw_cutoff )
+ if results == "detail" or results == "draw":
+ return results
+ else:
+ return results, stats[ level ][ "max" ], stats[ level ]["avg" ], stats[ level ][ "delta" ]
+
+ def has_data( self, chrom ):
+ """
+ Returns true if dataset has data for this chrom
+ """
+
+ # Get summary tree.
+ filename = self.converted_dataset.file_name
+ st = self.CACHE[filename]
+ if st is None:
+ st = summary_tree_from_file( self.converted_dataset.file_name )
+ self.CACHE[filename] = st
+
+ # Check for data.
+ return st.chrom_blocks.get(chrom, None) or st.chrom_blocks.get(_convert_between_ucsc_and_ensemble_naming(chrom), None)
+
+class BamDataProvider( GenomeDataProvider, FilterableMixin ):
+ """
+ Provides access to intervals from a sorted indexed BAM file. Position data
+ is reported in 1-based, closed format, i.e. SAM/BAM format.
+ """
+
+ def get_filters( self ):
+ """
+ Returns filters for dataset.
+ """
+ # HACK: first 7 fields are for drawing, so start filter column index at 7.
+ filter_col = 7
+ filters = []
+ filters.append( { 'name': 'Mapping Quality',
+ 'type': 'number',
+ 'index': filter_col
+ } )
+ return filters
+
+
+ def write_data_to_file( self, regions, filename ):
+ """
+ Write reads in regions to file.
+ """
+
+ # Open current BAM file using index.
+ bamfile = csamtools.Samfile( filename=self.original_dataset.file_name, mode='rb', \
+ index_filename=self.converted_dataset.file_name )
+
+ # TODO: write headers as well?
+ new_bamfile = csamtools.Samfile( template=bamfile, filename=filename, mode='wb' )
+
+ for region in regions:
+ # Write data from region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+
+ try:
+ data = bamfile.fetch(start=start, end=end, reference=chrom)
+ except ValueError, e:
+ # Try alternative chrom naming.
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ try:
+ data = bamfile.fetch( start=start, end=end, reference=chrom )
+ except ValueError:
+ return None
+
+ # Write reads in region.
+ for i, read in enumerate( data ):
+ new_bamfile.write( read )
+
+ # Cleanup.
+ new_bamfile.close()
+ bamfile.close()
+
+ def get_iterator( self, chrom, start, end ):
+ """
+ Returns an iterator that provides data in the region chrom:start-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)
+ except ValueError, e:
+ # Try alternative chrom naming.
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ try:
+ data = bamfile.fetch( start=start, end=end, reference=chrom )
+ except ValueError:
+ return None
+ return data
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Returns a dict with the following attributes:
+ data - a list of reads with the format
+ [<guid>, <start>, <end>, <name>, <read_1>, <read_2>, [empty], <mapq_scores>]
+ where <read_1> has the format
+ [<start>, <end>, <cigar>, <strand>, <read_seq>]
+ and <read_2> has the format
+ [<start>, <end>, <cigar>, <strand>, <read_seq>]
+ Field 7 is empty so that mapq scores' location matches that in single-end reads.
+ For single-end reads, read has format:
+ [<guid>, <start>, <end>, <name>, <cigar>, <strand>, <seq>, <mapq_score>]
+
+ NOTE: read end and sequence data are not valid for reads outside of
+ requested region and should not be used.
+
+ max_low - lowest coordinate for the returned reads
+ max_high - highest coordinate for the returned reads
+ message - error/informative message
+ """
+ # No iterator indicates no reads.
+ if iterator is None:
+ return { 'data': [], 'message': None }
+
+ # Decode strand from read flag.
+ def decode_strand( read_flag, mask ):
+ strand_flag = ( read_flag & mask == 0 )
+ if strand_flag:
+ return "+"
+ else:
+ return "-"
+
+ # Encode reads as list of lists.
+ results = []
+ paired_pending = {}
+ unmapped = 0
+ message = None
+ for count, read in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if ( count - start_val - unmapped ) >= max_vals:
+ message = self.error_max_vals % ( max_vals, "reads" )
+ break
+
+ # If not mapped, skip read.
+ is_mapped = ( read.flag & 0x0004 == 0 )
+ if not is_mapped:
+ unmapped += 1
+ continue
+
+ qname = read.qname
+ seq = read.seq
+ strand = decode_strand( read.flag, 0x0010 )
+ if read.cigar is not None:
+ read_len = sum( [cig[1] for cig in read.cigar] ) # Use cigar to determine length
+ else:
+ read_len = len(seq) # If no cigar, just use sequence length
+
+ if read.is_proper_pair:
+ if qname in paired_pending: # one in dict is always first
+ pair = paired_pending[qname]
+ results.append( [ "%i_%s" % ( pair['start'], qname ),
+ pair['start'],
+ read.pos + read_len,
+ qname,
+ [ pair['start'], pair['end'], pair['cigar'], pair['strand'], pair['seq'] ],
+ [ read.pos, read.pos + read_len, read.cigar, strand, seq ],
+ None, [ pair['mapq'], read.mapq ]
+ ] )
+ del paired_pending[qname]
+ else:
+ paired_pending[qname] = { 'start': read.pos, 'end': read.pos + read_len, 'seq': seq, 'mate_start': read.mpos,
+ 'rlen': read_len, 'strand': strand, 'cigar': read.cigar, 'mapq': read.mapq }
+ else:
+ results.append( [ "%i_%s" % ( read.pos, qname ),
+ read.pos, read.pos + read_len, qname,
+ read.cigar, strand, read.seq, read.mapq ] )
+
+ # Take care of reads whose mates are out of range.
+ # TODO: count paired reads when adhering to max_vals?
+ for qname, read in paired_pending.iteritems():
+ if read['mate_start'] < read['start']:
+ # Mate is before read.
+ read_start = read['mate_start']
+ read_end = read['end']
+ # Make read_1 start=end so that length is 0 b/c we don't know
+ # read length.
+ r1 = [ read['mate_start'], read['mate_start'] ]
+ r2 = [ read['start'], read['end'], read['cigar'], read['strand'], read['seq'] ]
+ else:
+ # Mate is after read.
+ read_start = read['start']
+ # Make read_2 start=end so that length is 0 b/c we don't know
+ # read length. Hence, end of read is start of read_2.
+ read_end = read['mate_start']
+ r1 = [ read['start'], read['end'], read['cigar'], read['strand'], read['seq'] ]
+ r2 = [ read['mate_start'], read['mate_start'] ]
+
+ results.append( [ "%i_%s" % ( read_start, qname ), read_start, read_end, qname, r1, r2, [read[ 'mapq' ], 125] ] )
+
+ # Clean up. TODO: is this needed? If so, we'll need a cleanup function after processing the data.
+ # bamfile.close()
+
+ max_low, max_high = get_bounds( results, 1, 2 )
+
+ return { 'data': results, 'message': message, 'max_low': max_low, 'max_high': max_high }
+
+class SamDataProvider( BamDataProvider ):
+
+ def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None ):
+ """ Create SamDataProvider. """
+
+ # HACK: to use BamDataProvider, original dataset must be BAM and
+ # converted dataset must be BAI. Use BAI from BAM metadata.
+ if converted_dataset:
+ self.converted_dataset = converted_dataset.metadata.bam_index
+ self.original_dataset = converted_dataset
+ self.dependencies = dependencies
+
+class BBIDataProvider( GenomeDataProvider ):
+ """
+ BBI data provider for the Galaxy track browser.
+ """
+ def valid_chroms( self ):
+ # No way to return this info as of now
+ return None
+
+ def has_data( self, chrom ):
+ f, bbi = self._get_dataset()
+ all_dat = bbi.query(chrom, 0, 2147483647, 1)
+ f.close()
+ return all_dat is not None
+
+ def get_data( self, chrom, start, end, start_val=0, max_vals=None, **kwargs ):
+ # Bigwig can be a standalone bigwig file, in which case we use
+ # original_dataset, or coming from wig->bigwig conversion in
+ # which we use converted_dataset
+ f, bbi = self._get_dataset()
+
+ # If stats requested, compute overall summary data for the range
+ # start:endbut no reduced data. This is currently used by client
+ # to determine the default range.
+ if 'stats' in kwargs:
+ summary = bbi.summarize( chrom, start, end, 1 )
+ f.close()
+
+ min = 0
+ max = 0
+ mean = 0
+ sd = 0
+ if summary is not None:
+ # Does the summary contain any defined values?
+ valid_count = summary.valid_count[0]
+ if summary.valid_count > 0:
+ # Compute $\mu \pm 2\sigma$ to provide an estimate for upper and lower
+ # bounds that contain ~95% of the data.
+ mean = summary.sum_data[0] / valid_count
+ var = summary.sum_squares[0] - mean
+ if valid_count > 1:
+ var /= valid_count - 1
+ sd = numpy.sqrt( var )
+ min = summary.min_val[0]
+ max = summary.max_val[0]
+
+ return dict( data=dict( min=min, max=max, mean=mean, sd=sd ) )
+
+ # Sample from region using approximately this many samples.
+ N = 1000
+
+ def summarize_region( bbi, chrom, start, end, num_points ):
+ '''
+ Returns results from summarizing a region using num_points.
+ NOTE: num_points cannot be greater than end - start or BBI
+ will return None for all positions.s
+ '''
+ result = []
+
+ # Get summary; this samples at intervals of length
+ # (end - start)/num_points -- i.e. drops any fractional component
+ # of interval length.
+ summary = bbi.summarize( chrom, start, end, num_points )
+ if summary:
+ #mean = summary.sum_data / summary.valid_count
+
+ ## Standard deviation by bin, not yet used
+ ## var = summary.sum_squares - mean
+ ## var /= minimum( valid_count - 1, 1 )
+ ## sd = sqrt( var )
+
+ pos = start
+ step_size = (end - start) / num_points
+
+ for i in range( num_points ):
+ result.append( (pos, float_nan( summary.sum_data[i] / summary.valid_count[i] ) ) )
+ pos += step_size
+
+ return result
+
+ # Approach is different depending on region size.
+ if end - start < N:
+ # Get values for individual bases in region, including start and end.
+ # To do this, need to increase end to next base and request number of points.
+ num_points = end - start + 1
+ end += 1
+ else:
+ #
+ # The goal is to sample the region between start and end uniformly
+ # using ~N data points. The challenge is that the size of sampled
+ # intervals rarely is full bases, so sampling using N points will
+ # leave the end of the region unsampled due to remainders for each
+ # interval. To recitify this, a new N is calculated based on the
+ # step size that covers as much of the region as possible.
+ #
+ # However, this still leaves some of the region unsampled. This
+ # could be addressed by repeatedly sampling remainder using a
+ # smaller and smaller step_size, but that would require iteratively
+ # going to BBI, which could be time consuming.
+ #
+
+ # Start with N samples.
+ num_points = N
+ step_size = ( end - start ) / num_points
+ # Add additional points to sample in the remainder not covered by
+ # the initial N samples.
+ remainder_start = start + step_size * num_points
+ additional_points = ( end - remainder_start ) / step_size
+ num_points += additional_points
+
+ result = summarize_region( bbi, chrom, start, end, num_points )
+
+ # Cleanup and return.
+ f.close()
+ return { 'data': result }
+
+class BigBedDataProvider( BBIDataProvider ):
+ def _get_dataset( self ):
+ # Nothing converts to bigBed so we don't consider converted dataset
+ f = open( self.original_dataset.file_name )
+ return f, BigBedFile(file=f)
+
+class BigWigDataProvider ( BBIDataProvider ):
+ """
+ Provides data from BigWig files; position data is reported in 1-based
+ coordinate system, i.e. wiggle format.
+ """
+ def _get_dataset( self ):
+ if self.converted_dataset is not None:
+ f = open( self.converted_dataset.file_name )
+ else:
+ f = open( self.original_dataset.file_name )
+ return f, BigWigFile(file=f)
+
+class IntervalIndexDataProvider( FilterableMixin, GenomeDataProvider ):
+ """
+ Interval index files used only for GFF files.
+ """
+ col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } }
+
+ def write_data_to_file( self, regions, filename ):
+ source = open( self.original_dataset.file_name )
+ index = Indexes( self.converted_dataset.file_name )
+ out = open( filename, 'w' )
+
+ for region in regions:
+ # Write data from region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+ for start, end, offset in index.find(chrom, start, end):
+ source.seek( offset )
+
+ reader = GFFReaderWrapper( source, fix_strand=True )
+ feature = reader.next()
+ for interval in feature.intervals:
+ out.write( '\t'.join( interval.fields ) + '\n' )
+
+ out.close()
+
+ def get_iterator( self, chrom, start, end ):
+ """
+ Returns an array with values: (a) source file and (b) an iterator that
+ provides data in the region chrom:start-end
+ """
+ start, end = int(start), int(end)
+ source = open( self.original_dataset.file_name )
+ index = Indexes( self.converted_dataset.file_name )
+
+ if chrom not in index.indexes:
+ # Try alternative naming.
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+
+ return index.find(chrom, start, end)
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ results = []
+ message = None
+ source = open( self.original_dataset.file_name )
+
+ #
+ # Build data to return. Payload format is:
+ # [ <guid/offset>, <start>, <end>, <name>, <score>, <strand>, <thick_start>,
+ # <thick_end>, <blocks> ]
+ #
+ # First three entries are mandatory, others are optional.
+ #
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ for count, val in enumerate( iterator ):
+ start, end, offset = val[0], val[1], val[2]
+ if count < start_val:
+ continue
+ if count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+ source.seek( offset )
+ # TODO: can we use column metadata to fill out payload?
+
+ # GFF dataset.
+ reader = GFFReaderWrapper( source, fix_strand=True )
+ feature = reader.next()
+ payload = package_gff_feature( feature, no_detail, filter_cols )
+ payload.insert( 0, offset )
+
+ results.append( payload )
+
+ return { 'data': results, 'message': message }
+
+class RawGFFDataProvider( GenomeDataProvider ):
+ """
+ Provide data from GFF file that has not been indexed.
+
+ NOTE: this data provider does not use indices, and hence will be very slow
+ for large datasets.
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ """
+ Returns an iterator that provides data in the region chrom:start-end as well as
+ a file offset.
+ """
+ source = open( self.original_dataset.file_name )
+
+ # Read first line in order to match chrom naming format.
+ line = source.readline()
+
+ # If line empty, assume file is empty and return empty iterator.
+ if len( line ) == 0:
+ return iter([])
+
+ # Determine chromosome naming format.
+ dataset_chrom = line.split()[0]
+ if not _chrom_naming_matches( chrom, dataset_chrom ):
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ # Undo read.
+ source.seek( 0 )
+
+ def features_in_region_iter():
+ offset = 0
+ for feature in GFFReaderWrapper( source, fix_strand=True ):
+ # Only provide features that are in region.
+ feature_start, feature_end = convert_gff_coords_to_bed( [ feature.start, feature.end ] )
+ if feature.chrom == chrom and feature_end > start and feature_start < end:
+ yield feature, offset
+ offset += feature.raw_size
+
+ return features_in_region_iter()
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Process data from an iterator to a format that can be provided to client.
+ """
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ results = []
+ message = None
+
+ for count, ( feature, offset ) in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "reads" )
+ break
+
+ payload = package_gff_feature( feature, no_detail=no_detail, filter_cols=filter_cols )
+ payload.insert( 0, offset )
+ results.append( payload )
+
+
+ return { 'data': results, 'message': message }
+
+class GtfTabixDataProvider( TabixDataProvider ):
+ """
+ Returns data from GTF datasets that are indexed via tabix.
+ """
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ # Loop through lines and group by transcript_id; each group is a feature.
+
+ # TODO: extend this code or use code in gff_util to process GFF/3 as well
+ # and then create a generic GFFDataProvider that can be used with both
+ # raw and tabix datasets.
+ features = {}
+ for count, line in enumerate( iterator ):
+ line_attrs = parse_gff_attributes( line.split('\t')[8] )
+ transcript_id = line_attrs[ 'transcript_id' ]
+ if transcript_id in features:
+ feature = features[ transcript_id ]
+ else:
+ feature = []
+ features[ transcript_id ] = feature
+ feature.append( GFFInterval( None, line.split( '\t') ) )
+
+ # Process data.
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ results = []
+ message = None
+
+ for count, intervals in enumerate( features.values() ):
+ if count < start_val:
+ continue
+ if count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "reads" )
+ break
+
+ feature = GFFFeature( None, intervals=intervals )
+ payload = package_gff_feature( feature, no_detail=no_detail, filter_cols=filter_cols )
+ payload.insert( 0, feature.intervals[ 0 ].attributes[ 'transcript_id' ] )
+ results.append( payload )
+
+ return { 'data': results, 'message': message }
+
+#
+# -- ENCODE Peak data providers.
+#
+
+class ENCODEPeakDataProvider( GenomeDataProvider ):
+ """
+ Abstract class that processes ENCODEPeak data from native format to payload format.
+
+ Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ raise "Unimplemented Method"
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Provides
+ """
+
+ ## FIXMEs:
+ # (1) should be able to unify some of this code with BedDataProvider.process_data
+ # (2) are optional number of parameters supported?
+
+ # Build data to return. Payload format is:
+ # [ <guid/offset>, <start>, <end>, <name>, <strand>, <thick_start>,
+ # <thick_end>, <blocks> ]
+ #
+ # First three entries are mandatory, others are optional.
+ #
+ no_detail = ( "no_detail" in kwargs )
+ rval = []
+ message = None
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+
+ feature = line.split()
+ length = len( feature )
+
+ # Feature initialization.
+ payload = [
+ # GUID is just a hash of the line
+ hash( line ),
+ # Add start, end.
+ int( feature[1] ),
+ int( feature[2] )
+ ]
+
+ if no_detail:
+ rval.append( payload )
+ continue
+
+ # Extend with additional data.
+ payload.extend( [
+ # Add name, strand.
+ feature[3],
+ feature[5],
+ # Thick start, end are feature start, end for now.
+ int( feature[1] ),
+ int( feature[2] ),
+ # No blocks.
+ None,
+ # Filtering data: Score, signalValue, pValue, qValue.
+ float( feature[4] ),
+ float( feature[6] ),
+ float( feature[7] ),
+ float( feature[8] )
+ ] )
+
+ rval.append( payload )
+
+ return { 'data': rval, 'message': message }
+
+class ENCODEPeakTabixDataProvider( TabixDataProvider, ENCODEPeakDataProvider ):
+ """
+ Provides data from an ENCODEPeak dataset indexed via tabix.
+ """
+
+ def get_filters( self ):
+ """
+ Returns filters for dataset.
+ """
+ # HACK: first 8 fields are for drawing, so start filter column index at 9.
+ filter_col = 8
+ filters = []
+ filters.append( { 'name': 'Score',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c6' } )
+ filter_col += 1
+ filters.append( { 'name': 'Signal Value',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c7' } )
+ filter_col += 1
+ filters.append( { 'name': 'pValue',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c8' } )
+ filter_col += 1
+ filters.append( { 'name': 'qValue',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c9' } )
+ return filters
+
+#
+# -- ChromatinInteraction data providers --
+#
+class ChromatinInteractionsDataProvider( GenomeDataProvider ):
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Provides
+ """
+
+ rval = []
+ message = None
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "interactions" )
+ break
+
+ feature = line.split()
+ length = len( feature )
+
+ s1 = int( feature[1] ),
+ e1 = int( feature[2] ),
+ c = feature[3],
+ s2 = int( feature[4] ),
+ e2 = int( feature[5] ),
+ v = float( feature[6] )
+
+ # Feature initialization.
+ payload = [
+ # GUID is just a hash of the line
+ hash( line ),
+ # Add start1, end1, chr2, start2, end2, value.
+ s1, e1, c, s2, e2, v
+ ]
+
+ rval.append( payload )
+
+ return { 'data': rval, 'message': message }
+
+ def get_default_max_vals( self ):
+ return 50000;
+
+class ChromatinInteractionsTabixDataProvider( TabixDataProvider, ChromatinInteractionsDataProvider ):
+ def get_iterator( self, chrom, start, end ):
+ """
+ """
+ # Modify start as needed to get earlier interactions with start region.
+ start = max( 0, int( start) - 1000000 )
+ def filter( iter ):
+ for line in iter:
+ feature = line.split()
+ s1 = int( feature[1] ),
+ e1 = int( feature[2] ),
+ c = feature[3]
+ s2 = int( feature[4] ),
+ e2 = int( feature[5] ),
+ if ( ( c == chrom ) and ( s1 < end and e1 > start ) and ( s2 < end and e2 > start ) ):
+ yield line
+ return filter( TabixDataProvider.get_iterator( self, chrom, start, end ) )
+
+#
+# -- Helper methods. --
+#
+
+def package_gff_feature( feature, no_detail=False, filter_cols=[] ):
+ """ Package a GFF feature in an array for data providers. """
+ feature = convert_gff_coords_to_bed( feature )
+
+ # No detail means only start, end.
+ if no_detail:
+ return [ feature.start, feature.end ]
+
+ # Return full feature.
+ payload = [ feature.start,
+ feature.end,
+ feature.name(),
+ feature.strand,
+ # No notion of thick start, end in GFF, so make everything
+ # thick.
+ feature.start,
+ feature.end
+ ]
+
+ # HACK: ignore interval with name 'transcript' from feature.
+ # Cufflinks puts this interval in each of its transcripts,
+ # and they mess up trackster by covering the feature's blocks.
+ # This interval will always be a feature's first interval,
+ # and the GFF's third column is its feature name.
+ feature_intervals = feature.intervals
+ if feature.intervals[0].fields[2] == 'transcript':
+ feature_intervals = feature.intervals[1:]
+ # Add blocks.
+ block_sizes = [ (interval.end - interval.start ) for interval in feature_intervals ]
+ block_starts = [ ( interval.start - feature.start ) for interval in feature_intervals ]
+ blocks = zip( block_sizes, block_starts )
+ payload.append( [ ( feature.start + block[1], feature.start + block[1] + block[0] ) for block in blocks ] )
+
+ # Add filter data to payload.
+ for col in filter_cols:
+ if col == "Score":
+ if feature.score == 'nan':
+ payload.append( feature.score )
+ else:
+ try:
+ f = float( feature.score )
+ payload.append( f )
+ except:
+ payload.append( feature.score )
+ elif col in feature.attributes:
+ if feature.attributes[col] == 'nan':
+ payload.append( feature.attributes[col] )
+ else:
+ try:
+ f = float( feature.attributes[col] )
+ payload.append( f )
+ except:
+ payload.append( feature.attributes[col] )
+ else:
+ # Dummy value.
+ payload.append( 0 )
+ return payload
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/visualization/data_providers/registry.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers/registry.py
@@ -0,0 +1,73 @@
+from galaxy.visualization.data_providers.basic import ColumnDataProvider
+from galaxy.visualization.data_providers.genome import *
+
+class DataProviderRegistry( object ):
+ """
+ Registry for data providers that enables listing and lookup.
+ """
+
+ def __init__( self ):
+ # Mapping from dataset type name to a class that can fetch data from a file of that
+ # type. First key is converted dataset type; if result is another dict, second key
+ # is original dataset type.
+ self.dataset_type_name_to_data_provider = {
+ "tabix": {
+ Vcf: VcfTabixDataProvider,
+ Bed: BedTabixDataProvider,
+ Gtf: GtfTabixDataProvider,
+ ENCODEPeak: ENCODEPeakTabixDataProvider,
+ Interval: IntervalTabixDataProvider,
+ ChromatinInteractions: ChromatinInteractionsTabixDataProvider,
+ "default" : TabixDataProvider
+ },
+ "interval_index": IntervalIndexDataProvider,
+ "bai": BamDataProvider,
+ "bam": SamDataProvider,
+ "summary_tree": SummaryTreeDataProvider,
+ "bigwig": BigWigDataProvider,
+ "bigbed": BigBedDataProvider
+ }
+
+ def get_data_provider( self, name=None, raw=False, original_dataset=None ):
+ """
+ Returns data provider class by name and/or original dataset.
+ """
+
+ # If getting raw data, use original dataset type to get data provider.
+ if raw:
+ if isinstance( original_dataset.datatype, Gff ):
+ return RawGFFDataProvider
+ elif isinstance( original_dataset.datatype, Bed ):
+ return RawBedDataProvider
+ elif isinstance( original_dataset.datatype, Vcf ):
+ return RawVcfDataProvider
+ elif isinstance( original_dataset.datatype, Tabular ):
+ return ColumnDataProvider
+
+ # Using converted dataset, so get corrsponding data provider.
+ data_provider = None
+ if name:
+ value = self.dataset_type_name_to_data_provider[ name ]
+ if isinstance( value, dict ):
+ # Get converter by dataset extension; if there is no data provider,
+ # get the default.
+ data_provider = value.get( original_dataset.datatype.__class__, value.get( "default" ) )
+ else:
+ data_provider = value
+ elif original_dataset:
+ # Look up data provider from datatype's informaton.
+ try:
+ # Get data provider mapping and data provider for 'data'. If
+ # provider available, use it; otherwise use generic provider.
+ _ , data_provider_mapping = original_dataset.datatype.get_track_type()
+ if 'data_standalone' in data_provider_mapping:
+ data_provider_name = data_provider_mapping[ 'data_standalone' ]
+ else:
+ data_provider_name = data_provider_mapping[ 'data' ]
+ if data_provider_name:
+ data_provider = self.get_data_provider( name=data_provider_name, original_dataset=original_dataset )
+ else:
+ data_provider = GenomeDataProvider
+ except:
+ pass
+ return data_provider
\ No newline at end of file
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/visualization/genome/data_providers.py
--- a/lib/galaxy/visualization/genome/data_providers.py
+++ /dev/null
@@ -1,1563 +0,0 @@
-"""
-Data providers for genome visualizations.
-"""
-
-import os, sys
-from math import ceil, log
-import pkg_resources
-pkg_resources.require( "bx-python" )
-if sys.version_info[:2] == (2, 4):
- pkg_resources.require( "ctypes" )
-pkg_resources.require( "pysam" )
-pkg_resources.require( "numpy" )
-import numpy
-from galaxy.datatypes.util.gff_util import *
-from galaxy.util.json import from_json_string
-from bx.interval_index_file import Indexes
-from bx.bbi.bigwig_file import BigWigFile
-from galaxy.util.lrucache import LRUCache
-from galaxy.visualization.tracks.summary import *
-from galaxy.visualization.data_providers import BaseDataProvider
-import galaxy_utils.sequence.vcf
-from galaxy.datatypes.tabular import Tabular, Vcf
-from galaxy.datatypes.interval import Interval, Bed, Gff, Gtf, ENCODEPeak, ChromatinInteractions
-
-from pysam import csamtools, ctabix
-
-#
-# Utility functions.
-#
-
-def float_nan(n):
- '''
- Return None instead of NaN to pass jQuery 1.4's strict JSON
- '''
- if n != n: # NaN != NaN
- return None
- else:
- return float(n)
-
-def get_bounds( reads, start_pos_index, end_pos_index ):
- '''
- Returns the minimum and maximum position for a set of reads.
- '''
- max_low = sys.maxint
- max_high = -sys.maxint
- for read in reads:
- if read[ start_pos_index ] < max_low:
- max_low = read[ start_pos_index ]
- if read[ end_pos_index ] > max_high:
- max_high = read[ end_pos_index ]
- return max_low, max_high
-
-def _convert_between_ucsc_and_ensemble_naming( chrom ):
- '''
- Convert between UCSC chromosome ('chr1') naming conventions and Ensembl
- naming conventions ('1')
- '''
- if chrom.startswith( 'chr' ):
- # Convert from UCSC to Ensembl
- return chrom[ 3: ]
- else:
- # Convert from Ensembl to UCSC
- return 'chr' + chrom
-
-def _chrom_naming_matches( chrom1, chrom2 ):
- return ( chrom1.startswith( 'chr' ) and chrom2.startswith( 'chr' ) ) or ( not chrom1.startswith( 'chr' ) and not chrom2.startswith( 'chr' ) )
-
-class FeatureLocationIndexDataProvider( BaseDataProvider ):
- """
- Reads/writes/queries feature location index (FLI) datasets.
- """
-
- def __init__( self, converted_dataset ):
- self.converted_dataset = converted_dataset
-
- def get_data( self, query ):
- # Init.
- textloc_file = open( self.converted_dataset.file_name, 'r' )
- line_len = int( textloc_file.readline() )
- file_len = os.path.getsize( self.converted_dataset.file_name )
- query = query.lower()
-
- # Find query in file using binary search.
- low = 0
- high = file_len / line_len
- while low < high:
- mid = ( low + high ) // 2
- position = mid * line_len
- textloc_file.seek( position )
-
- # Compare line with query and update low, high.
- line = textloc_file.readline()
- if line < query:
- low = mid + 1
- else:
- high = mid
-
- position = low * line_len
-
- # At right point in file, generate hits.
- result = []
- while True:
- line = textloc_file.readline()
- if not line.startswith( query ):
- break
- if line[ -1: ] == '\n':
- line = line[ :-1 ]
- result.append( line.split()[1:] )
-
- textloc_file.close()
- return result
-
-class GenomeDataProvider( BaseDataProvider ):
- """ Base class for genome data providers. """
-
- """
- Mapping from column name to payload data; this mapping is used to create
- filters. Key is column name, value is a dict with mandatory key 'index' and
- optional key 'name'. E.g. this defines column 4
-
- col_name_data_attr_mapping = {4 : { index: 5, name: 'Score' } }
- """
- col_name_data_attr_mapping = {}
-
- def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None,
- error_max_vals="Only the first %i %s in this region are displayed." ):
- super( GenomeDataProvider, self ).__init__( converted_dataset=converted_dataset,
- original_dataset=original_dataset,
- dependencies=dependencies,
- error_max_vals=error_max_vals )
-
- def write_data_to_file( self, regions, filename ):
- """
- Write data in region defined by chrom, start, and end to a file.
- """
- raise Exception( "Unimplemented Function" )
-
- def valid_chroms( self ):
- """
- Returns chroms/contigs that the dataset contains
- """
- return None # by default
-
- def has_data( self, chrom, start, end, **kwargs ):
- """
- Returns true if dataset has data in the specified genome window, false
- otherwise.
- """
- raise Exception( "Unimplemented Function" )
-
- def get_iterator( self, chrom, start, end ):
- """
- Returns an iterator that provides data in the region chrom:start-end
- """
- raise Exception( "Unimplemented Function" )
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Process data from an iterator to a format that can be provided to client.
- """
- raise Exception( "Unimplemented Function" )
-
- def get_data( self, chrom, start, end, start_val=0, max_vals=sys.maxint, **kwargs ):
- """
- Returns data in region defined by chrom, start, and end. start_val and
- max_vals are used to denote the data to return: start_val is the first element to
- return and max_vals indicates the number of values to return.
-
- Return value must be a dictionary with the following attributes:
- dataset_type, data
- """
- iterator = self.get_iterator( chrom, start, end )
- return self.process_data( iterator, start_val, max_vals, **kwargs )
-
- def get_genome_data( self, chroms_info, **kwargs ):
- """
- Returns data for complete genome.
- """
- dataset_summary = []
- for chrom_info in chroms_info[ 'chrom_info' ]:
- summary = self.get_data( chrom_info[ 'chrom' ], 0, chrom_info[ 'len' ], **kwargs )
- dataset_summary.append( summary )
-
- return dataset_summary
-
- def get_filters( self ):
- """
- Returns filters for provider's data. Return value is a list of
- filters; each filter is a dictionary with the keys 'name', 'index', 'type'.
- NOTE: This method uses the original dataset's datatype and metadata to
- create the filters.
- """
- # Get column names.
- try:
- column_names = self.original_dataset.datatype.column_names
- except AttributeError:
- try:
- column_names = range( self.original_dataset.metadata.columns )
- except: # Give up
- return []
-
- # Dataset must have column types; if not, cannot create filters.
- try:
- column_types = self.original_dataset.metadata.column_types
- except AttributeError:
- return []
-
- # Create and return filters.
- filters = []
- if self.original_dataset.metadata.viz_filter_cols:
- for viz_col_index in self.original_dataset.metadata.viz_filter_cols:
- # Some columns are optional, so can't assume that a filter
- # column is in dataset.
- if viz_col_index >= len( column_names ):
- continue;
- col_name = column_names[ viz_col_index ]
- # Make sure that column has a mapped index. If not, do not add filter.
- try:
- attrs = self.col_name_data_attr_mapping[ col_name ]
- except KeyError:
- continue
- filters.append(
- { 'name' : attrs[ 'name' ], 'type' : column_types[viz_col_index], \
- 'index' : attrs[ 'index' ] } )
- return filters
-
- def get_default_max_vals( self ):
- return 5000
-
-#
-# -- Base mixins and providers --
-#
-
-class FilterableMixin:
- def get_filters( self ):
- """ Returns a dataset's filters. """
-
- # is_ functions taken from Tabular.set_meta
- def is_int( column_text ):
- try:
- int( column_text )
- return True
- except:
- return False
- def is_float( column_text ):
- try:
- float( column_text )
- return True
- except:
- if column_text.strip().lower() == 'na':
- return True #na is special cased to be a float
- return False
-
- #
- # Get filters.
- # TODOs:
- # (a) might be useful to move this into each datatype's set_meta method;
- # (b) could look at first N lines to ensure GTF attribute types are consistent.
- #
- filters = []
- # HACK: first 8 fields are for drawing, so start filter column index at 9.
- filter_col = 8
- if isinstance( self.original_dataset.datatype, Gff ):
- # Can filter by score and GTF attributes.
- filters = [ { 'name': 'Score',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c6' } ]
- filter_col += 1
- if isinstance( self.original_dataset.datatype, Gtf ):
- # Create filters based on dataset metadata.
- for name, a_type in self.original_dataset.metadata.attribute_types.items():
- if a_type in [ 'int', 'float' ]:
- filters.append(
- { 'name': name,
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'gff_filter_by_attribute',
- 'tool_exp_name': name } )
- filter_col += 1
-
- '''
- # Old code: use first line in dataset to find attributes.
- for i, line in enumerate( open(self.original_dataset.file_name) ):
- if not line.startswith('#'):
- # Look at first line for attributes and types.
- attributes = parse_gff_attributes( line.split('\t')[8] )
- for attr, value in attributes.items():
- # Get attribute type.
- if is_int( value ):
- attr_type = 'int'
- elif is_float( value ):
- attr_type = 'float'
- else:
- attr_type = 'str'
- # Add to filters.
- if attr_type is not 'str':
- filters.append( { 'name': attr, 'type': attr_type, 'index': filter_col } )
- filter_col += 1
- break
- '''
- elif isinstance( self.original_dataset.datatype, Bed ):
- # Can filter by score column only.
- filters = [ { 'name': 'Score',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c5'
- } ]
-
- return filters
-
-
-class TabixDataProvider( FilterableMixin, GenomeDataProvider ):
- """
- Tabix index data provider for the Galaxy track browser.
- """
-
- col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } }
-
- def get_iterator( self, chrom, start, end ):
- start, end = int(start), int(end)
- if end >= (2<<29):
- end = (2<<29 - 1) # Tabix-enforced maximum
-
- bgzip_fname = self.dependencies['bgzip'].file_name
-
- tabix = ctabix.Tabixfile(bgzip_fname, index_filename=self.converted_dataset.file_name)
-
- # If chrom not in data, try alternative.
- if chrom not in tabix.contigs:
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
-
- return tabix.fetch(reference=chrom, start=start, end=end)
-
- def write_data_to_file( self, regions, filename ):
- out = open( filename, "w" )
-
- for region in regions:
- # Write data in region.
- chrom = region.chrom
- start = region.start
- end = region.end
- iterator = self.get_iterator( chrom, start, end )
- for line in iterator:
- out.write( "%s\n" % line )
-
- out.close()
-
-#
-# -- Interval data providers --
-#
-
-class IntervalDataProvider( GenomeDataProvider ):
- """
- Processes BED data from native format to payload format.
-
- Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
- """
-
- def get_iterator( self, chrom, start, end ):
- raise Exception( "Unimplemented Function" )
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Provides
- """
- # Build data to return. Payload format is:
- # [ <guid/offset>, <start>, <end>, <name>, <strand> ]
- #
- # First three entries are mandatory, others are optional.
- #
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- rval = []
- message = None
- # Subtract one b/c columns are 1-based but indices are 0-based.
- col_fn = lambda col: None if col is None else col - 1
- start_col = self.original_dataset.metadata.startCol - 1
- end_col = self.original_dataset.metadata.endCol - 1
- strand_col = col_fn( self.original_dataset.metadata.strandCol )
- name_col = col_fn( self.original_dataset.metadata.nameCol )
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
-
- feature = line.split()
- length = len(feature)
- # Unique id is just a hash of the line
- payload = [ hash(line), int( feature[start_col] ), int( feature [end_col] ) ]
-
- if no_detail:
- rval.append( payload )
- continue
-
- # Name, strand.
- if name_col:
- payload.append( feature[name_col] )
- if strand_col:
- # Put empty name as placeholder.
- if not name_col: payload.append( "" )
- payload.append( feature[strand_col] )
-
- # Score (filter data)
- if length >= 5 and filter_cols and filter_cols[0] == "Score":
- try:
- payload.append( float( feature[4] ) )
- except:
- payload.append( feature[4] )
-
- rval.append( payload )
-
- return { 'data': rval, 'message': message }
-
- def write_data_to_file( self, regions, filename ):
- raise Exception( "Unimplemented Function" )
-
-class IntervalTabixDataProvider( TabixDataProvider, IntervalDataProvider ):
- """
- Provides data from a BED file indexed via tabix.
- """
- pass
-
-
-#
-# -- BED data providers --
-#
-
-class BedDataProvider( GenomeDataProvider ):
- """
- Processes BED data from native format to payload format.
-
- Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
- """
-
- def get_iterator( self, chrom, start, end ):
- raise Exception( "Unimplemented Method" )
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Provides
- """
- # Build data to return. Payload format is:
- # [ <guid/offset>, <start>, <end>, <name>, <strand>, <thick_start>,
- # <thick_end>, <blocks> ]
- #
- # First three entries are mandatory, others are optional.
- #
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- rval = []
- message = None
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
- # TODO: can we use column metadata to fill out payload?
- # TODO: use function to set payload data
-
- feature = line.split()
- length = len(feature)
- # Unique id is just a hash of the line
- payload = [ hash(line), int(feature[1]), int(feature[2]) ]
-
- if no_detail:
- rval.append( payload )
- continue
-
- # Name, strand, thick start, thick end.
- if length >= 4:
- payload.append(feature[3])
- if length >= 6:
- payload.append(feature[5])
- if length >= 8:
- payload.append(int(feature[6]))
- payload.append(int(feature[7]))
-
- # Blocks.
- if length >= 12:
- block_sizes = [ int(n) for n in feature[10].split(',') if n != '']
- block_starts = [ int(n) for n in feature[11].split(',') if n != '' ]
- blocks = zip( block_sizes, block_starts )
- payload.append( [ ( int(feature[1]) + block[1], int(feature[1]) + block[1] + block[0] ) for block in blocks ] )
-
- # Score (filter data)
- if length >= 5 and filter_cols and filter_cols[0] == "Score":
- # If dataset doesn't have name/strand/thick start/thick end/blocks,
- # add placeholders. There should be 8 entries if all attributes
- # are present.
- payload.extend( [ None for i in range( 8 - len( payload ) ) ] )
-
- try:
- payload.append( float( feature[4] ) )
- except:
- payload.append( feature[4] )
-
- rval.append( payload )
-
- return { 'data': rval, 'message': message }
-
- def write_data_to_file( self, regions, filename ):
- out = open( filename, "w" )
-
- for region in regions:
- # Write data in region.
- chrom = region.chrom
- start = region.start
- end = region.end
- iterator = self.get_iterator( chrom, start, end )
- for line in iterator:
- out.write( "%s\n" % line )
-
- out.close()
-
-class BedTabixDataProvider( TabixDataProvider, BedDataProvider ):
- """
- Provides data from a BED file indexed via tabix.
- """
- pass
-
-class RawBedDataProvider( BedDataProvider ):
- """
- Provide data from BED file.
-
- NOTE: this data provider does not use indices, and hence will be very slow
- for large datasets.
- """
-
- def get_iterator( self, chrom=None, start=None, end=None ):
- # Read first line in order to match chrom naming format.
- line = source.readline()
- dataset_chrom = line.split()[0]
- if not _chrom_naming_matches( chrom, dataset_chrom ):
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- # Undo read.
- source.seek( 0 )
-
- def line_filter_iter():
- for line in open( self.original_dataset.file_name ):
- if line.startswith( "track" ) or line.startswith( "browser" ):
- continue
- feature = line.split()
- feature_chrom = feature[0]
- feature_start = int( feature[1] )
- feature_end = int( feature[2] )
- if ( chrom is not None and feature_chrom != chrom ) \
- or ( start is not None and feature_start > end ) \
- or ( end is not None and feature_end < start ):
- continue
- yield line
-
- return line_filter_iter()
-
-#
-# -- VCF data providers --
-#
-
-class VcfDataProvider( GenomeDataProvider ):
- """
- Abstract class that processes VCF data from native format to payload format.
-
- Payload format: TODO
- """
-
- col_name_data_attr_mapping = { 'Qual' : { 'index': 6 , 'name' : 'Qual' } }
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Returns a dict with the following attributes:
- data - a list of variants with the format
- [<guid>, <start>, <end>, <name>, cigar, seq]
-
- message - error/informative message
- """
- rval = []
- message = None
-
- def get_mapping( ref, alt ):
- """
- Returns ( offset, new_seq, cigar ) tuple that defines mapping of
- alt to ref. Cigar format is an array of [ op_index, length ] pairs
- where op_index is the 0-based index into the string "MIDNSHP=X"
- """
-
- cig_ops = "MIDNSHP=X"
-
- ref_len = len( ref )
- alt_len = len( alt )
-
- # Substitutions?
- if ref_len == alt_len:
- return 0, alt, [ [ cig_ops.find( "M" ), ref_len ] ]
-
- # Deletions?
- alt_in_ref_index = ref.find( alt )
- if alt_in_ref_index != -1:
- return alt_in_ref_index, ref[ alt_in_ref_index + 1: ], [ [ cig_ops.find( "D" ), ref_len - alt_len ] ]
-
- # Insertions?
- ref_in_alt_index = alt.find( ref )
- if ref_in_alt_index != -1:
- return ref_in_alt_index, alt[ ref_in_alt_index + 1: ], [ [ cig_ops.find( "I" ), alt_len - ref_len ] ]
-
- # Pack data.
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
-
- feature = line.split()
- start = int( feature[1] ) - 1
- ref = feature[3]
- alts = feature[4]
-
- # HACK? alts == '.' --> monomorphism.
- if alts == '.':
- alts = ref
-
- # Pack variants.
- for alt in alts.split(","):
- offset, new_seq, cigar = get_mapping( ref, alt )
- start += offset
- end = start + len( new_seq )
-
- # Pack line.
- payload = [
- hash( line ),
- start,
- end,
- # ID:
- feature[2],
- cigar,
- # TODO? VCF does not have strand, so default to positive.
- "+",
- new_seq,
- None if feature[5] == '.' else float( feature[5] )
- ]
- rval.append(payload)
-
- return { 'data': rval, 'message': message }
-
- def write_data_to_file( self, regions, filename ):
- out = open( filename, "w" )
-
- for region in regions:
- # Write data in region.
- chrom = region.chrom
- start = region.start
- end = region.end
- iterator = self.get_iterator( chrom, start, end )
- for line in iterator:
- out.write( "%s\n" % line )
- out.close()
-
-class VcfTabixDataProvider( TabixDataProvider, VcfDataProvider ):
- """
- Provides data from a VCF file indexed via tabix.
- """
- pass
-
-class RawVcfDataProvider( VcfDataProvider ):
- """
- Provide data from VCF file.
-
- NOTE: this data provider does not use indices, and hence will be very slow
- for large datasets.
- """
-
- def get_iterator( self, chrom, start, end ):
- # Read first line in order to match chrom naming format.
- line = source.readline()
- dataset_chrom = line.split()[0]
- if not _chrom_naming_matches( chrom, dataset_chrom ):
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- # Undo read.
- source.seek( 0 )
-
- def line_filter_iter():
- for line in open( self.original_dataset.file_name ):
- if line.startswith("#"):
- continue
- variant = line.split()
- variant_chrom, variant_start, id, ref, alts = variant[ 0:5 ]
- variant_start = int( variant_start )
- longest_alt = -1
- for alt in alts:
- if len( alt ) > longest_alt:
- longest_alt = len( alt )
- variant_end = variant_start + abs( len( ref ) - longest_alt )
- if variant_chrom != chrom or variant_start > end or variant_end < start:
- continue
- yield line
-
- return line_filter_iter()
-
-class SummaryTreeDataProvider( GenomeDataProvider ):
- """
- Summary tree data provider for the Galaxy track browser.
- """
-
- CACHE = LRUCache( 20 ) # Store 20 recently accessed indices for performance
-
- def valid_chroms( self ):
- st = summary_tree_from_file( self.converted_dataset.file_name )
- return st.chrom_blocks.keys()
-
- def get_data( self, chrom, start, end, level=None, resolution=None, detail_cutoff=None, draw_cutoff=None ):
- """
- Returns summary tree data for a given genomic region.
- """
- filename = self.converted_dataset.file_name
- st = self.CACHE[filename]
- if st is None:
- st = summary_tree_from_file( self.converted_dataset.file_name )
- self.CACHE[filename] = st
-
- # Look for chrom in tree using both naming conventions.
- if chrom not in st.chrom_blocks:
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- if chrom not in st.chrom_blocks:
- return None
-
- # Get or compute level.
- if level:
- level = int( level )
- elif resolution:
- resolution = max( 1, ceil( float( resolution ) ) )
- level = ceil( log( resolution, st.block_size ) ) - 1
- level = int( max( level, 0 ) )
- else:
- # Either level or resolution is required.
- return None
-
- if level <= 1:
- return "detail"
-
- # Use level to get results.
- stats = st.chrom_stats[ chrom ]
- results = st.query( chrom, int(start), int(end), level, detail_cutoff=detail_cutoff, draw_cutoff=draw_cutoff )
- if results == "detail" or results == "draw":
- return results
- else:
- return results, stats[ level ][ "max" ], stats[ level ]["avg" ], stats[ level ][ "delta" ]
-
- def has_data( self, chrom ):
- """
- Returns true if dataset has data for this chrom
- """
-
- # Get summary tree.
- filename = self.converted_dataset.file_name
- st = self.CACHE[filename]
- if st is None:
- st = summary_tree_from_file( self.converted_dataset.file_name )
- self.CACHE[filename] = st
-
- # Check for data.
- return st.chrom_blocks.get(chrom, None) or st.chrom_blocks.get(_convert_between_ucsc_and_ensemble_naming(chrom), None)
-
-class BamDataProvider( GenomeDataProvider, FilterableMixin ):
- """
- Provides access to intervals from a sorted indexed BAM file. Position data
- is reported in 1-based, closed format, i.e. SAM/BAM format.
- """
-
- def get_filters( self ):
- """
- Returns filters for dataset.
- """
- # HACK: first 7 fields are for drawing, so start filter column index at 7.
- filter_col = 7
- filters = []
- filters.append( { 'name': 'Mapping Quality',
- 'type': 'number',
- 'index': filter_col
- } )
- return filters
-
-
- def write_data_to_file( self, regions, filename ):
- """
- Write reads in regions to file.
- """
-
- # Open current BAM file using index.
- bamfile = csamtools.Samfile( filename=self.original_dataset.file_name, mode='rb', \
- index_filename=self.converted_dataset.file_name )
-
- # TODO: write headers as well?
- new_bamfile = csamtools.Samfile( template=bamfile, filename=filename, mode='wb' )
-
- for region in regions:
- # Write data from region.
- chrom = region.chrom
- start = region.start
- end = region.end
-
- try:
- data = bamfile.fetch(start=start, end=end, reference=chrom)
- except ValueError, e:
- # Try alternative chrom naming.
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- try:
- data = bamfile.fetch( start=start, end=end, reference=chrom )
- except ValueError:
- return None
-
- # Write reads in region.
- for i, read in enumerate( data ):
- new_bamfile.write( read )
-
- # Cleanup.
- new_bamfile.close()
- bamfile.close()
-
- def get_iterator( self, chrom, start, end ):
- """
- Returns an iterator that provides data in the region chrom:start-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)
- except ValueError, e:
- # Try alternative chrom naming.
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- try:
- data = bamfile.fetch( start=start, end=end, reference=chrom )
- except ValueError:
- return None
- return data
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Returns a dict with the following attributes:
- data - a list of reads with the format
- [<guid>, <start>, <end>, <name>, <read_1>, <read_2>, [empty], <mapq_scores>]
- where <read_1> has the format
- [<start>, <end>, <cigar>, <strand>, <read_seq>]
- and <read_2> has the format
- [<start>, <end>, <cigar>, <strand>, <read_seq>]
- Field 7 is empty so that mapq scores' location matches that in single-end reads.
- For single-end reads, read has format:
- [<guid>, <start>, <end>, <name>, <cigar>, <strand>, <seq>, <mapq_score>]
-
- NOTE: read end and sequence data are not valid for reads outside of
- requested region and should not be used.
-
- max_low - lowest coordinate for the returned reads
- max_high - highest coordinate for the returned reads
- message - error/informative message
- """
- # No iterator indicates no reads.
- if iterator is None:
- return { 'data': [], 'message': None }
-
- # Decode strand from read flag.
- def decode_strand( read_flag, mask ):
- strand_flag = ( read_flag & mask == 0 )
- if strand_flag:
- return "+"
- else:
- return "-"
-
- # Encode reads as list of lists.
- results = []
- paired_pending = {}
- unmapped = 0
- message = None
- for count, read in enumerate( iterator ):
- if count < start_val:
- continue
- if ( count - start_val - unmapped ) >= max_vals:
- message = self.error_max_vals % ( max_vals, "reads" )
- break
-
- # If not mapped, skip read.
- is_mapped = ( read.flag & 0x0004 == 0 )
- if not is_mapped:
- unmapped += 1
- continue
-
- qname = read.qname
- seq = read.seq
- strand = decode_strand( read.flag, 0x0010 )
- if read.cigar is not None:
- read_len = sum( [cig[1] for cig in read.cigar] ) # Use cigar to determine length
- else:
- read_len = len(seq) # If no cigar, just use sequence length
-
- if read.is_proper_pair:
- if qname in paired_pending: # one in dict is always first
- pair = paired_pending[qname]
- results.append( [ "%i_%s" % ( pair['start'], qname ),
- pair['start'],
- read.pos + read_len,
- qname,
- [ pair['start'], pair['end'], pair['cigar'], pair['strand'], pair['seq'] ],
- [ read.pos, read.pos + read_len, read.cigar, strand, seq ],
- None, [ pair['mapq'], read.mapq ]
- ] )
- del paired_pending[qname]
- else:
- paired_pending[qname] = { 'start': read.pos, 'end': read.pos + read_len, 'seq': seq, 'mate_start': read.mpos,
- 'rlen': read_len, 'strand': strand, 'cigar': read.cigar, 'mapq': read.mapq }
- else:
- results.append( [ "%i_%s" % ( read.pos, qname ),
- read.pos, read.pos + read_len, qname,
- read.cigar, strand, read.seq, read.mapq ] )
-
- # Take care of reads whose mates are out of range.
- # TODO: count paired reads when adhering to max_vals?
- for qname, read in paired_pending.iteritems():
- if read['mate_start'] < read['start']:
- # Mate is before read.
- read_start = read['mate_start']
- read_end = read['end']
- # Make read_1 start=end so that length is 0 b/c we don't know
- # read length.
- r1 = [ read['mate_start'], read['mate_start'] ]
- r2 = [ read['start'], read['end'], read['cigar'], read['strand'], read['seq'] ]
- else:
- # Mate is after read.
- read_start = read['start']
- # Make read_2 start=end so that length is 0 b/c we don't know
- # read length. Hence, end of read is start of read_2.
- read_end = read['mate_start']
- r1 = [ read['start'], read['end'], read['cigar'], read['strand'], read['seq'] ]
- r2 = [ read['mate_start'], read['mate_start'] ]
-
- results.append( [ "%i_%s" % ( read_start, qname ), read_start, read_end, qname, r1, r2, [read[ 'mapq' ], 125] ] )
-
- # Clean up. TODO: is this needed? If so, we'll need a cleanup function after processing the data.
- # bamfile.close()
-
- max_low, max_high = get_bounds( results, 1, 2 )
-
- return { 'data': results, 'message': message, 'max_low': max_low, 'max_high': max_high }
-
-class SamDataProvider( BamDataProvider ):
-
- def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None ):
- """ Create SamDataProvider. """
-
- # HACK: to use BamDataProvider, original dataset must be BAM and
- # converted dataset must be BAI. Use BAI from BAM metadata.
- if converted_dataset:
- self.converted_dataset = converted_dataset.metadata.bam_index
- self.original_dataset = converted_dataset
- self.dependencies = dependencies
-
-class BBIDataProvider( GenomeDataProvider ):
- """
- BBI data provider for the Galaxy track browser.
- """
- def valid_chroms( self ):
- # No way to return this info as of now
- return None
-
- def has_data( self, chrom ):
- f, bbi = self._get_dataset()
- all_dat = bbi.query(chrom, 0, 2147483647, 1)
- f.close()
- return all_dat is not None
-
- def get_data( self, chrom, start, end, start_val=0, max_vals=None, **kwargs ):
- # Bigwig can be a standalone bigwig file, in which case we use
- # original_dataset, or coming from wig->bigwig conversion in
- # which we use converted_dataset
- f, bbi = self._get_dataset()
-
- # If stats requested, compute overall summary data for the range
- # start:endbut no reduced data. This is currently used by client
- # to determine the default range.
- if 'stats' in kwargs:
- summary = bbi.summarize( chrom, start, end, 1 )
- f.close()
-
- min = 0
- max = 0
- mean = 0
- sd = 0
- if summary is not None:
- # Does the summary contain any defined values?
- valid_count = summary.valid_count[0]
- if summary.valid_count > 0:
- # Compute $\mu \pm 2\sigma$ to provide an estimate for upper and lower
- # bounds that contain ~95% of the data.
- mean = summary.sum_data[0] / valid_count
- var = summary.sum_squares[0] - mean
- if valid_count > 1:
- var /= valid_count - 1
- sd = numpy.sqrt( var )
- min = summary.min_val[0]
- max = summary.max_val[0]
-
- return dict( data=dict( min=min, max=max, mean=mean, sd=sd ) )
-
- # Sample from region using approximately this many samples.
- N = 1000
-
- def summarize_region( bbi, chrom, start, end, num_points ):
- '''
- Returns results from summarizing a region using num_points.
- NOTE: num_points cannot be greater than end - start or BBI
- will return None for all positions.s
- '''
- result = []
-
- # Get summary; this samples at intervals of length
- # (end - start)/num_points -- i.e. drops any fractional component
- # of interval length.
- summary = bbi.summarize( chrom, start, end, num_points )
- if summary:
- #mean = summary.sum_data / summary.valid_count
-
- ## Standard deviation by bin, not yet used
- ## var = summary.sum_squares - mean
- ## var /= minimum( valid_count - 1, 1 )
- ## sd = sqrt( var )
-
- pos = start
- step_size = (end - start) / num_points
-
- for i in range( num_points ):
- result.append( (pos, float_nan( summary.sum_data[i] / summary.valid_count[i] ) ) )
- pos += step_size
-
- return result
-
- # Approach is different depending on region size.
- if end - start < N:
- # Get values for individual bases in region, including start and end.
- # To do this, need to increase end to next base and request number of points.
- num_points = end - start + 1
- end += 1
- else:
- #
- # The goal is to sample the region between start and end uniformly
- # using ~N data points. The challenge is that the size of sampled
- # intervals rarely is full bases, so sampling using N points will
- # leave the end of the region unsampled due to remainders for each
- # interval. To recitify this, a new N is calculated based on the
- # step size that covers as much of the region as possible.
- #
- # However, this still leaves some of the region unsampled. This
- # could be addressed by repeatedly sampling remainder using a
- # smaller and smaller step_size, but that would require iteratively
- # going to BBI, which could be time consuming.
- #
-
- # Start with N samples.
- num_points = N
- step_size = ( end - start ) / num_points
- # Add additional points to sample in the remainder not covered by
- # the initial N samples.
- remainder_start = start + step_size * num_points
- additional_points = ( end - remainder_start ) / step_size
- num_points += additional_points
-
- result = summarize_region( bbi, chrom, start, end, num_points )
-
- # Cleanup and return.
- f.close()
- return { 'data': result }
-
-class BigBedDataProvider( BBIDataProvider ):
- def _get_dataset( self ):
- # Nothing converts to bigBed so we don't consider converted dataset
- f = open( self.original_dataset.file_name )
- return f, BigBedFile(file=f)
-
-class BigWigDataProvider ( BBIDataProvider ):
- """
- Provides data from BigWig files; position data is reported in 1-based
- coordinate system, i.e. wiggle format.
- """
- def _get_dataset( self ):
- if self.converted_dataset is not None:
- f = open( self.converted_dataset.file_name )
- else:
- f = open( self.original_dataset.file_name )
- return f, BigWigFile(file=f)
-
-class IntervalIndexDataProvider( FilterableMixin, GenomeDataProvider ):
- """
- Interval index files used only for GFF files.
- """
- col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } }
-
- def write_data_to_file( self, regions, filename ):
- source = open( self.original_dataset.file_name )
- index = Indexes( self.converted_dataset.file_name )
- out = open( filename, 'w' )
-
- for region in regions:
- # Write data from region.
- chrom = region.chrom
- start = region.start
- end = region.end
- for start, end, offset in index.find(chrom, start, end):
- source.seek( offset )
-
- reader = GFFReaderWrapper( source, fix_strand=True )
- feature = reader.next()
- for interval in feature.intervals:
- out.write( '\t'.join( interval.fields ) + '\n' )
-
- out.close()
-
- def get_iterator( self, chrom, start, end ):
- """
- Returns an array with values: (a) source file and (b) an iterator that
- provides data in the region chrom:start-end
- """
- start, end = int(start), int(end)
- source = open( self.original_dataset.file_name )
- index = Indexes( self.converted_dataset.file_name )
-
- if chrom not in index.indexes:
- # Try alternative naming.
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
-
- return index.find(chrom, start, end)
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- results = []
- message = None
- source = open( self.original_dataset.file_name )
-
- #
- # Build data to return. Payload format is:
- # [ <guid/offset>, <start>, <end>, <name>, <score>, <strand>, <thick_start>,
- # <thick_end>, <blocks> ]
- #
- # First three entries are mandatory, others are optional.
- #
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- for count, val in enumerate( iterator ):
- start, end, offset = val[0], val[1], val[2]
- if count < start_val:
- continue
- if count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
- source.seek( offset )
- # TODO: can we use column metadata to fill out payload?
-
- # GFF dataset.
- reader = GFFReaderWrapper( source, fix_strand=True )
- feature = reader.next()
- payload = package_gff_feature( feature, no_detail, filter_cols )
- payload.insert( 0, offset )
-
- results.append( payload )
-
- return { 'data': results, 'message': message }
-
-class RawGFFDataProvider( GenomeDataProvider ):
- """
- Provide data from GFF file that has not been indexed.
-
- NOTE: this data provider does not use indices, and hence will be very slow
- for large datasets.
- """
-
- def get_iterator( self, chrom, start, end ):
- """
- Returns an iterator that provides data in the region chrom:start-end as well as
- a file offset.
- """
- source = open( self.original_dataset.file_name )
-
- # Read first line in order to match chrom naming format.
- line = source.readline()
-
- # If line empty, assume file is empty and return empty iterator.
- if len( line ) == 0:
- return iter([])
-
- # Determine chromosome naming format.
- dataset_chrom = line.split()[0]
- if not _chrom_naming_matches( chrom, dataset_chrom ):
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- # Undo read.
- source.seek( 0 )
-
- def features_in_region_iter():
- offset = 0
- for feature in GFFReaderWrapper( source, fix_strand=True ):
- # Only provide features that are in region.
- feature_start, feature_end = convert_gff_coords_to_bed( [ feature.start, feature.end ] )
- if feature.chrom == chrom and feature_end > start and feature_start < end:
- yield feature, offset
- offset += feature.raw_size
-
- return features_in_region_iter()
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Process data from an iterator to a format that can be provided to client.
- """
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- results = []
- message = None
-
- for count, ( feature, offset ) in enumerate( iterator ):
- if count < start_val:
- continue
- if count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "reads" )
- break
-
- payload = package_gff_feature( feature, no_detail=no_detail, filter_cols=filter_cols )
- payload.insert( 0, offset )
- results.append( payload )
-
-
- return { 'data': results, 'message': message }
-
-class GtfTabixDataProvider( TabixDataProvider ):
- """
- Returns data from GTF datasets that are indexed via tabix.
- """
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- # Loop through lines and group by transcript_id; each group is a feature.
-
- # TODO: extend this code or use code in gff_util to process GFF/3 as well
- # and then create a generic GFFDataProvider that can be used with both
- # raw and tabix datasets.
- features = {}
- for count, line in enumerate( iterator ):
- line_attrs = parse_gff_attributes( line.split('\t')[8] )
- transcript_id = line_attrs[ 'transcript_id' ]
- if transcript_id in features:
- feature = features[ transcript_id ]
- else:
- feature = []
- features[ transcript_id ] = feature
- feature.append( GFFInterval( None, line.split( '\t') ) )
-
- # Process data.
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- results = []
- message = None
-
- for count, intervals in enumerate( features.values() ):
- if count < start_val:
- continue
- if count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "reads" )
- break
-
- feature = GFFFeature( None, intervals=intervals )
- payload = package_gff_feature( feature, no_detail=no_detail, filter_cols=filter_cols )
- payload.insert( 0, feature.intervals[ 0 ].attributes[ 'transcript_id' ] )
- results.append( payload )
-
- return { 'data': results, 'message': message }
-
-#
-# -- ENCODE Peak data providers.
-#
-
-class ENCODEPeakDataProvider( GenomeDataProvider ):
- """
- Abstract class that processes ENCODEPeak data from native format to payload format.
-
- Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
- """
-
- def get_iterator( self, chrom, start, end ):
- raise "Unimplemented Method"
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Provides
- """
-
- ## FIXMEs:
- # (1) should be able to unify some of this code with BedDataProvider.process_data
- # (2) are optional number of parameters supported?
-
- # Build data to return. Payload format is:
- # [ <guid/offset>, <start>, <end>, <name>, <strand>, <thick_start>,
- # <thick_end>, <blocks> ]
- #
- # First three entries are mandatory, others are optional.
- #
- no_detail = ( "no_detail" in kwargs )
- rval = []
- message = None
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
-
- feature = line.split()
- length = len( feature )
-
- # Feature initialization.
- payload = [
- # GUID is just a hash of the line
- hash( line ),
- # Add start, end.
- int( feature[1] ),
- int( feature[2] )
- ]
-
- if no_detail:
- rval.append( payload )
- continue
-
- # Extend with additional data.
- payload.extend( [
- # Add name, strand.
- feature[3],
- feature[5],
- # Thick start, end are feature start, end for now.
- int( feature[1] ),
- int( feature[2] ),
- # No blocks.
- None,
- # Filtering data: Score, signalValue, pValue, qValue.
- float( feature[4] ),
- float( feature[6] ),
- float( feature[7] ),
- float( feature[8] )
- ] )
-
- rval.append( payload )
-
- return { 'data': rval, 'message': message }
-
-class ENCODEPeakTabixDataProvider( TabixDataProvider, ENCODEPeakDataProvider ):
- """
- Provides data from an ENCODEPeak dataset indexed via tabix.
- """
-
- def get_filters( self ):
- """
- Returns filters for dataset.
- """
- # HACK: first 8 fields are for drawing, so start filter column index at 9.
- filter_col = 8
- filters = []
- filters.append( { 'name': 'Score',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c6' } )
- filter_col += 1
- filters.append( { 'name': 'Signal Value',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c7' } )
- filter_col += 1
- filters.append( { 'name': 'pValue',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c8' } )
- filter_col += 1
- filters.append( { 'name': 'qValue',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c9' } )
- return filters
-
-#
-# -- ChromatinInteraction data providers --
-#
-class ChromatinInteractionsDataProvider( GenomeDataProvider ):
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Provides
- """
-
- rval = []
- message = None
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "interactions" )
- break
-
- feature = line.split()
- length = len( feature )
-
- s1 = int( feature[1] ),
- e1 = int( feature[2] ),
- c = feature[3],
- s2 = int( feature[4] ),
- e2 = int( feature[5] ),
- v = float( feature[6] )
-
- # Feature initialization.
- payload = [
- # GUID is just a hash of the line
- hash( line ),
- # Add start1, end1, chr2, start2, end2, value.
- s1, e1, c, s2, e2, v
- ]
-
- rval.append( payload )
-
- return { 'data': rval, 'message': message }
-
- def get_default_max_vals( self ):
- return 50000;
-
-class ChromatinInteractionsTabixDataProvider( TabixDataProvider, ChromatinInteractionsDataProvider ):
- def get_iterator( self, chrom, start, end ):
- """
- """
- # Modify start as needed to get earlier interactions with start region.
- start = max( 0, int( start) - 1000000 )
- def filter( iter ):
- for line in iter:
- feature = line.split()
- s1 = int( feature[1] ),
- e1 = int( feature[2] ),
- c = feature[3]
- s2 = int( feature[4] ),
- e2 = int( feature[5] ),
- if ( ( c == chrom ) and ( s1 < end and e1 > start ) and ( s2 < end and e2 > start ) ):
- yield line
- return filter( TabixDataProvider.get_iterator( self, chrom, start, end ) )
-
-#
-# -- Helper methods. --
-#
-
-# Mapping from dataset type name to a class that can fetch data from a file of that
-# type. First key is converted dataset type; if result is another dict, second key
-# is original dataset type. TODO: This needs to be more flexible.
-dataset_type_name_to_data_provider = {
- "tabix": {
- Vcf: VcfTabixDataProvider,
- Bed: BedTabixDataProvider,
- Gtf: GtfTabixDataProvider,
- ENCODEPeak: ENCODEPeakTabixDataProvider,
- Interval: IntervalTabixDataProvider,
- ChromatinInteractions: ChromatinInteractionsTabixDataProvider,
- "default" : TabixDataProvider
- },
- "interval_index": IntervalIndexDataProvider,
- "bai": BamDataProvider,
- "bam": SamDataProvider,
- "summary_tree": SummaryTreeDataProvider,
- "bigwig": BigWigDataProvider,
- "bigbed": BigBedDataProvider
-}
-
-def get_data_provider( name=None, original_dataset=None ):
- """
- Returns data provider class by name and/or original dataset.
- """
- data_provider = None
- if name:
- value = dataset_type_name_to_data_provider[ name ]
- if isinstance( value, dict ):
- # Get converter by dataset extension; if there is no data provider,
- # get the default.
- data_provider = value.get( original_dataset.datatype.__class__, value.get( "default" ) )
- else:
- data_provider = value
- elif original_dataset:
- # Look up data provider from datatype's informaton.
- try:
- # Get data provider mapping and data provider for 'data'. If
- # provider available, use it; otherwise use generic provider.
- _ , data_provider_mapping = original_dataset.datatype.get_track_type()
- if 'data_standalone' in data_provider_mapping:
- data_provider_name = data_provider_mapping[ 'data_standalone' ]
- else:
- data_provider_name = data_provider_mapping[ 'data' ]
- if data_provider_name:
- data_provider = get_data_provider( name=data_provider_name, original_dataset=original_dataset )
- else:
- data_provider = GenomeDataProvider
- except:
- pass
- return data_provider
-
-def package_gff_feature( feature, no_detail=False, filter_cols=[] ):
- """ Package a GFF feature in an array for data providers. """
- feature = convert_gff_coords_to_bed( feature )
-
- # No detail means only start, end.
- if no_detail:
- return [ feature.start, feature.end ]
-
- # Return full feature.
- payload = [ feature.start,
- feature.end,
- feature.name(),
- feature.strand,
- # No notion of thick start, end in GFF, so make everything
- # thick.
- feature.start,
- feature.end
- ]
-
- # HACK: ignore interval with name 'transcript' from feature.
- # Cufflinks puts this interval in each of its transcripts,
- # and they mess up trackster by covering the feature's blocks.
- # This interval will always be a feature's first interval,
- # and the GFF's third column is its feature name.
- feature_intervals = feature.intervals
- if feature.intervals[0].fields[2] == 'transcript':
- feature_intervals = feature.intervals[1:]
- # Add blocks.
- block_sizes = [ (interval.end - interval.start ) for interval in feature_intervals ]
- block_starts = [ ( interval.start - feature.start ) for interval in feature_intervals ]
- blocks = zip( block_sizes, block_starts )
- payload.append( [ ( feature.start + block[1], feature.start + block[1] + block[0] ) for block in blocks ] )
-
- # Add filter data to payload.
- for col in filter_cols:
- if col == "Score":
- if feature.score == 'nan':
- payload.append( feature.score )
- else:
- try:
- f = float( feature.score )
- payload.append( f )
- except:
- payload.append( feature.score )
- elif col in feature.attributes:
- if feature.attributes[col] == 'nan':
- payload.append( feature.attributes[col] )
- else:
- try:
- f = float( feature.attributes[col] )
- payload.append( f )
- except:
- payload.append( feature.attributes[col] )
- else:
- # Dummy value.
- payload.append( 0 )
- return payload
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
--- a/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
+++ b/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
@@ -1,7 +1,7 @@
from newickparser import Newick_Parser
from nexusparser import Nexus_Parser
from phyloxmlparser import Phyloxml_Parser
-from galaxy.visualization.data_providers import BaseDataProvider
+from galaxy.visualization.data_providers.basic import BaseDataProvider
# TODO: bring this class into line with BaseDataProvider by
# using BaseDataProvider.init() and providing original dataset
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/web/api/datasets.py
--- a/lib/galaxy/web/api/datasets.py
+++ b/lib/galaxy/web/api/datasets.py
@@ -7,9 +7,9 @@
from galaxy.web.base.controller import *
from galaxy.util.sanitize_html import sanitize_html
from galaxy.model.orm import *
-from galaxy.datatypes.interval import Gff, Bed
+from galaxy.visualization.data_providers.genome import *
+from galaxy.visualization.data_providers.basic import ColumnDataProvider
from galaxy.datatypes.tabular import Vcf
-from galaxy.visualization.genome.data_providers import *
from galaxy.model import NoConverterException, ConverterDependencyException
log = logging.getLogger( __name__ )
@@ -90,16 +90,17 @@
# the client.
valid_chroms = None
# Check for data in the genome window.
+ data_provider_registry = trans.app.data_provider_registry
if data_sources.get( 'index' ):
tracks_dataset_type = data_sources['index']['name']
converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
- indexer = get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
+ indexer = data_provider_registry.get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
if not indexer.has_data( chrom ):
return messages.NO_DATA
#valid_chroms = indexer.valid_chroms()
else:
# Standalone data provider
- standalone_provider = get_data_provider( data_sources['data_standalone']['name'] )( dataset )
+ standalone_provider = data_provider_registry.get_data_provider( data_sources['data_standalone']['name'] )( dataset )
kwargs = {"stats": True}
if not standalone_provider.has_data( chrom ):
return messages.NO_DATA
@@ -147,11 +148,12 @@
extra_info = None
mode = kwargs.get( "mode", "Auto" )
# Handle histogram mode uniquely for now:
+ data_provider_registry = trans.app.data_provider_registry
if mode == "Coverage":
# Get summary using minimal cutoffs.
tracks_dataset_type = data_sources['index']['name']
converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
- indexer = get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
+ indexer = data_provider_registry.get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ], detail_cutoff=0, draw_cutoff=0 )
if summary == "detail":
# Use maximum level of detail--2--to get summary data no matter the resolution.
@@ -165,7 +167,7 @@
# Have to choose between indexer and data provider
tracks_dataset_type = data_sources['index']['name']
converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
- indexer = get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
+ indexer = data_provider_registry.get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ] )
if summary is None:
return { 'dataset_type': tracks_dataset_type, 'data': None }
@@ -180,11 +182,11 @@
# Get data provider.
if "data_standalone" in data_sources:
tracks_dataset_type = data_sources['data_standalone']['name']
- data_provider_class = get_data_provider( name=tracks_dataset_type, original_dataset=dataset )
+ data_provider_class = data_provider_registry.get_data_provider( name=tracks_dataset_type, original_dataset=dataset )
data_provider = data_provider_class( original_dataset=dataset )
else:
tracks_dataset_type = data_sources['data']['name']
- data_provider_class = get_data_provider( name=tracks_dataset_type, original_dataset=dataset )
+ data_provider_class = data_provider_registry.get_data_provider( name=tracks_dataset_type, original_dataset=dataset )
converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
deps = dataset.get_converted_dataset_deps( trans, tracks_dataset_type )
data_provider = data_provider_class( converted_dataset=converted_dataset, original_dataset=dataset, dependencies=deps )
@@ -198,7 +200,7 @@
result.update( { 'dataset_type': tracks_dataset_type, 'extra_info': extra_info } )
return result
- def _raw_data( self, trans, dataset, chrom, low, high, **kwargs ):
+ def _raw_data( self, trans, dataset, **kwargs ):
"""
Uses original (raw) dataset to return data. This method is useful
when the dataset is not yet indexed and hence using data would
@@ -209,22 +211,19 @@
msg = self.check_dataset_state( trans, dataset )
if msg:
return msg
-
- low, high = int( low ), int( high )
-
+
# Return data.
data = None
- # TODO: for raw data requests, map dataset type to provider using dict in data_providers.py
- if isinstance( dataset.datatype, Gff ):
- data = RawGFFDataProvider( original_dataset=dataset ).get_data( chrom, low, high, **kwargs )
+ data_provider = trans.app.data_provider_registry.get_data_provider( raw=True, original_dataset=dataset )
+ if data_provider == ColumnDataProvider:
+ data = data_provider( original_dataset=dataset ).get_data( **kwargs )
+ else:
+ # Default to genomic data.
+ # FIXME: need better way to set dataset_type.
+ low, high = int( kwargs.get( 'low' ) ), int( kwargs.get( 'high' ) )
+ data = data_provider( original_dataset=dataset ).get_data( start=low, end=high, **kwargs )
data[ 'dataset_type' ] = 'interval_index'
data[ 'extra_info' ] = None
- elif isinstance( dataset.datatype, Bed ):
- data = RawBedDataProvider( original_dataset=dataset ).get_data( chrom, low, high, **kwargs )
- data[ 'dataset_type' ] = 'interval_index'
- data[ 'extra_info' ] = None
- elif isinstance( dataset.datatype, Vcf ):
- data = RawVcfDataProvider( original_dataset=dataset ).get_data( chrom, low, high, **kwargs )
- data[ 'dataset_type' ] = 'tabix'
- data[ 'extra_info' ] = None
+ if isinstance( dataset.datatype, Vcf ):
+ data[ 'dataset_type' ] = 'tabix'
return data
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/web/api/tools.py
--- a/lib/galaxy/web/api/tools.py
+++ b/lib/galaxy/web/api/tools.py
@@ -3,7 +3,7 @@
from galaxy.visualization.genome.visual_analytics import get_dataset_job
from galaxy.visualization.genomes import GenomeRegion
from galaxy.util.json import to_json_string, from_json_string
-from galaxy.visualization.genome.data_providers import *
+from galaxy.visualization.data_providers.genome import *
class ToolsController( BaseAPIController, UsesVisualizationMixin ):
"""
@@ -199,11 +199,12 @@
# If running tool on region, convert input datasets (create indices) so
# that can regions of data can be quickly extracted.
#
+ data_provider_registry = trans.app.data_provider_registry
messages_list = []
if run_on_regions:
for jida in original_job.input_datasets:
input_dataset = jida.dataset
- if get_data_provider( original_dataset=input_dataset ):
+ if data_provider_registry.get_data_provider( original_dataset=input_dataset ):
# Can index dataset.
track_type, data_sources = input_dataset.datatype.get_track_type()
# Convert to datasource that provides 'data' because we need to
@@ -325,7 +326,7 @@
trans.app.security_agent.set_all_dataset_permissions( new_dataset.dataset, hda_permissions )
# Write subset of data to new dataset
- data_provider_class = get_data_provider( original_dataset=input_dataset )
+ data_provider_class = data_provider_registry.get_data_provider( original_dataset=input_dataset )
data_provider = data_provider_class( original_dataset=input_dataset,
converted_dataset=converted_dataset,
dependencies=deps )
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -14,7 +14,6 @@
from galaxy.web.framework import simplejson
from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea, TextField
from galaxy.web.form_builder import WorkflowField, WorkflowMappingField, HistoryField, PasswordField, build_select_field
-from galaxy.visualization.genome.data_providers import get_data_provider
from galaxy.visualization.genome.visual_analytics import get_tool_def
from galaxy.security.validate_user_input import validate_publicname
from paste.httpexceptions import *
@@ -488,7 +487,7 @@
prefs = {}
track_type, _ = dataset.datatype.get_track_type()
- track_data_provider_class = get_data_provider( original_dataset=dataset )
+ track_data_provider_class = trans.app.data_provider_registry.get_data_provider( original_dataset=dataset )
track_data_provider = track_data_provider_class( original_dataset=dataset )
return {
@@ -564,7 +563,7 @@
"""
# Get data provider.
track_type, _ = dataset.datatype.get_track_type()
- track_data_provider_class = get_data_provider( original_dataset=dataset )
+ track_data_provider_class = trans.app.data_provider_registry.get_data_provider( original_dataset=dataset )
track_data_provider = track_data_provider_class( original_dataset=dataset )
if isinstance( dataset, trans.app.model.HistoryDatasetAssociation ):
diff -r dc749983abdf243d6ff9a8295d917a2cec475771 -r 08f1d09a65a98977817ca1f1bd34fc266d61aa24 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py
+++ b/lib/galaxy/web/controllers/visualization.py
@@ -752,14 +752,15 @@
# Get dataset and indexed datatype.
dataset = self.get_hda_or_ldda( trans, track[ 'hda_ldda'], track[ 'dataset_id' ] )
data_sources = self._get_datasources( trans, dataset )
+ data_provider_registry = trans.app.data_provider_registry
if 'data_standalone' in data_sources:
indexed_type = data_sources['data_standalone']['name']
- data_provider = get_data_provider( indexed_type )( dataset )
+ data_provider = data_provider_registry.get_data_provider( indexed_type )( dataset )
else:
indexed_type = data_sources['index']['name']
# Get converted dataset and append track's genome data.
converted_dataset = dataset.get_converted_dataset( trans, indexed_type )
- data_provider = get_data_provider( indexed_type )( converted_dataset, dataset )
+ data_provider = data_provider_registry.get_data_provider( indexed_type )( converted_dataset, dataset )
# HACK: pass in additional params, which are only used for summary tree data, not BBI data.
track[ 'genome_wide_data' ] = { 'data': data_provider.get_genome_data( chroms_info, level=4, detail_cutoff=0, draw_cutoff=0 ) }
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: dannon: Prevent galaxy session cookie from being accessed via script. We don't use it via js anywhere, only other cookies specifically set for dynatree/genetrack.
by Bitbucket 17 Sep '12
by Bitbucket 17 Sep '12
17 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/dc749983abdf/
changeset: dc749983abdf
user: dannon
date: 2012-09-17 18:27:03
summary: Prevent galaxy session cookie from being accessed via script. We don't use it via js anywhere, only other cookies specifically set for dynatree/genetrack.
affected #: 1 file
diff -r 38015598badbfe47112bda3d6894a5a2c9bc9200 -r dc749983abdf243d6ff9a8295d917a2cec475771 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -347,6 +347,7 @@
tstamp = time.localtime ( time.time() + 3600 * 24 * age )
self.response.cookies[name]['expires'] = time.strftime( '%a, %d-%b-%Y %H:%M:%S GMT', tstamp )
self.response.cookies[name]['version'] = version
+ self.response.cookies[name]['httponly'] = True
def _ensure_valid_session( self, session_cookie, create=True):
"""
Ensure that a valid Galaxy session exists and is available as
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/changeset/c79b1228673a/
changeset: c79b1228673a
user: james_taylor
date: 2012-09-17 17:49:31
summary: trackster: starting to split tackster up and load using require.js
affected #: 11 files
Diff too large to display.
https://bitbucket.org/galaxy/galaxy-central/changeset/38015598badb/
changeset: 38015598badb
user: james_taylor
date: 2012-09-17 18:06:02
summary: trackster: merge
affected #: 11 files
Diff too large to display.
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: Trackster and sweepster fixes for vis framework refactoring.
by Bitbucket 16 Sep '12
by Bitbucket 16 Sep '12
16 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/fe12d92febf9/
changeset: fe12d92febf9
user: jgoecks
date: 2012-09-16 16:57:30
summary: Trackster and sweepster fixes for vis framework refactoring.
affected #: 5 files
diff -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 -r fe12d92febf99c19708ab5cb65a527366a2bece5 lib/galaxy/visualization/genome/data_providers.py
--- a/lib/galaxy/visualization/genome/data_providers.py
+++ b/lib/galaxy/visualization/genome/data_providers.py
@@ -1186,6 +1186,12 @@
# Read first line in order to match chrom naming format.
line = source.readline()
+
+ # If line empty, assume file is empty and return empty iterator.
+ if len( line ) == 0:
+ return iter([])
+
+ # Determine chromosome naming format.
dataset_chrom = line.split()[0]
if not _chrom_naming_matches( chrom, dataset_chrom ):
chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
diff -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 -r fe12d92febf99c19708ab5cb65a527366a2bece5 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py
+++ b/lib/galaxy/web/controllers/visualization.py
@@ -5,6 +5,7 @@
from galaxy.util.sanitize_html import sanitize_html
from galaxy.web.controllers.library import LibraryListGrid
from galaxy.visualization.genomes import decode_dbkey
+from galaxy.visualization.genome.visual_analytics import get_dataset_job
#
# -- Grids --
diff -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 -r fe12d92febf99c19708ab5cb65a527366a2bece5 static/scripts/viz/sweepster.js
--- a/static/scripts/viz/sweepster.js
+++ b/static/scripts/viz/sweepster.js
@@ -925,6 +925,9 @@
}, output.first().get('track_config')),
track_obj = object_from_template(track_config, self, null);
+ // Track uses only raw data.
+ track_obj.data_manager.set('data_type', 'raw_data');
+
// Set track block colors.
track_obj.prefs.block_color = self.block_color;
track_obj.prefs.reverse_strand_color = self.reverse_strand_color;
diff -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 -r fe12d92febf99c19708ab5cb65a527366a2bece5 static/scripts/viz/trackster.js
--- a/static/scripts/viz/trackster.js
+++ b/static/scripts/viz/trackster.js
@@ -3843,8 +3843,8 @@
// Tool-execution specific post-draw init:
- // Reset dataset state, wait time.
- self.dataset_state_url = converted_datasets_state_url;
+ // Reset dataset check, wait time.
+ self.dataset_check_type = 'converted_datasets_state';
self.data_query_wait = DEFAULT_DATA_QUERY_WAIT;
// Reset data URL when dataset indexing has completed/when not pending.
@@ -3858,8 +3858,6 @@
$.when(ss_deferred.go()).then(function() {
// Dataset is indexed, so use converted data.
self.data_manager.set('data_type', 'data');
- self.dataset_check_type = 'converted_datasets_state';
- this.data_query_wait = 5000;
});
// Reset post-draw actions function.
diff -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 -r fe12d92febf99c19708ab5cb65a527366a2bece5 templates/visualization/sweepster.mako
--- a/templates/visualization/sweepster.mako
+++ b/templates/visualization/sweepster.mako
@@ -108,7 +108,7 @@
${h.templates( "tool_link", "panel_section", "tool_search", "tool_form" )}
${h.js( "libs/d3", "mvc/data", "mvc/tools", "viz/visualization", "viz/sweepster",
- "viz/trackster", "viz/trackster_ui", "libs/jquery/jquery.ui.sortable.slider" )}
+ "viz/trackster", "viz/trackster_ui", "libs/jquery/jquery-ui-1.8.23.custom.min" )}
<script type="text/javascript">
var viz;
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/changeset/6243b992762c/
changeset: 6243b992762c
user: jgoecks
date: 2012-09-15 22:08:41
summary: Viz framework refactoring: remove tracks controller, moving code that handles data requests to the API and code that manages track browsers to visualization controller.
affected #: 13 files
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 lib/galaxy/web/api/datasets.py
--- a/lib/galaxy/web/api/datasets.py
+++ b/lib/galaxy/web/api/datasets.py
@@ -10,9 +10,6 @@
log = logging.getLogger( __name__ )
-def is_true ( a_str ):
- return is_true == True or a_str in [ 'True', 'true', 'T', 't' ]
-
class DatasetsController( BaseAPIController, UsesVisualizationMixin ):
@web.expose_api
@@ -24,14 +21,11 @@
pass
@web.expose_api
- def show( self, trans, id, hda_ldda='hda', deleted='False', **kwd ):
+ def show( self, trans, id, hda_ldda='hda', data_type=None, **kwd ):
"""
GET /api/datasets/{encoded_dataset_id}
Displays information about and/or content of a dataset.
"""
-
- # Process arguments.
- track_config = is_true( kwd.get( 'track_config', False ) )
# Get dataset.
try:
@@ -39,9 +33,18 @@
except Exception, e:
return str( e )
- # Return info.
- rval = None
- if track_config:
+ # Use data type to return particular type of data.
+ if data_type == 'state':
+ rval = self._dataset_state( self, trans, dataset )
+ elif data_type == 'converted_datasets_state':
+ rval = self._converted_datasets_state( trans, dataset, kwd.get( 'chrom', None ) )
+ elif data_type == 'data':
+ rval = self._data( trans, dataset, **kwd )
+ elif data_type == 'features':
+ rval = self._search_features( trans, dataset, kwd.get( 'query ' ) )
+ elif data_type == 'raw_data':
+ rval = self._raw_data( trans, dataset, **kwd )
+ elif data_type == 'track_config':
rval = self.get_new_track_config( trans, dataset )
else:
# Default: return dataset as API value.
@@ -52,3 +55,172 @@
log.error( rval + ": %s" % str(e) )
trans.response.status = 500
return rval
+
+ def _dataset_state( self, trans, dataset, **kwargs ):
+ """ Returns state of dataset. """
+
+ msg = self.check_dataset_state( trans, dataset )
+ if not msg:
+ msg = messages.DATA
+
+ return msg
+
+ def _converted_datasets_state( self, trans, dataset, chrom=None ):
+ """
+ Init-like method that returns state of dataset's converted datasets. Returns valid chroms
+ for that dataset as well.
+ """
+
+ msg = self.check_dataset_state( trans, dataset )
+ if msg:
+ return msg
+
+ # Get datasources and check for messages.
+ data_sources = self._get_datasources( trans, dataset )
+ messages_list = [ data_source_dict[ 'message' ] for data_source_dict in data_sources.values() ]
+ msg = get_highest_priority_msg( messages_list )
+ if msg:
+ return msg
+
+ # NOTE: finding valid chroms is prohibitive for large summary trees and is not currently used by
+ # the client.
+ valid_chroms = None
+ # Check for data in the genome window.
+ if data_sources.get( 'index' ):
+ tracks_dataset_type = data_sources['index']['name']
+ converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
+ indexer = get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
+ if not indexer.has_data( chrom ):
+ return messages.NO_DATA
+ #valid_chroms = indexer.valid_chroms()
+ else:
+ # Standalone data provider
+ standalone_provider = get_data_provider( data_sources['data_standalone']['name'] )( dataset )
+ kwargs = {"stats": True}
+ if not standalone_provider.has_data( chrom ):
+ return messages.NO_DATA
+ #valid_chroms = standalone_provider.valid_chroms()
+
+ # Have data if we get here
+ return { "status": messages.DATA, "valid_chroms": valid_chroms }
+
+ def _search_features( self, trans, dataset, query ):
+ """
+ Returns features, locations in dataset that match query. Format is a
+ list of features; each feature is a list itself: [name, location]
+ """
+ if dataset.can_convert_to( "fli" ):
+ converted_dataset = dataset.get_converted_dataset( trans, "fli" )
+ if converted_dataset:
+ data_provider = FeatureLocationIndexDataProvider( converted_dataset=converted_dataset )
+ if data_provider:
+ return data_provider.get_data( query )
+
+ return []
+
+
+ def _data( self, trans, dataset, chrom, low, high, start_val=0, max_vals=None, **kwargs ):
+ """
+ Provides a block of data from a dataset.
+ """
+
+ # Parameter check.
+ if not chrom:
+ return messages.NO_DATA
+
+ # Dataset check.
+ msg = self.check_dataset_state( trans, dataset )
+ if msg:
+ return msg
+
+ # Get datasources and check for messages.
+ data_sources = self._get_datasources( trans, dataset )
+ messages_list = [ data_source_dict[ 'message' ] for data_source_dict in data_sources.values() ]
+ return_message = get_highest_priority_msg( messages_list )
+ if return_message:
+ return return_message
+
+ extra_info = None
+ mode = kwargs.get( "mode", "Auto" )
+ # Handle histogram mode uniquely for now:
+ if mode == "Coverage":
+ # Get summary using minimal cutoffs.
+ tracks_dataset_type = data_sources['index']['name']
+ converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
+ indexer = get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
+ summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ], detail_cutoff=0, draw_cutoff=0 )
+ if summary == "detail":
+ # Use maximum level of detail--2--to get summary data no matter the resolution.
+ summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ], level=2, detail_cutoff=0, draw_cutoff=0 )
+ frequencies, max_v, avg_v, delta = summary
+ return { 'dataset_type': tracks_dataset_type, 'data': frequencies, 'max': max_v, 'avg': avg_v, 'delta': delta }
+
+ if 'index' in data_sources and data_sources['index']['name'] == "summary_tree" and mode == "Auto":
+ # Only check for summary_tree if it's Auto mode (which is the default)
+ #
+ # Have to choose between indexer and data provider
+ tracks_dataset_type = data_sources['index']['name']
+ converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
+ indexer = get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
+ summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ] )
+ if summary is None:
+ return { 'dataset_type': tracks_dataset_type, 'data': None }
+
+ if summary == "draw":
+ kwargs["no_detail"] = True # meh
+ extra_info = "no_detail"
+ elif summary != "detail":
+ frequencies, max_v, avg_v, delta = summary
+ return { 'dataset_type': tracks_dataset_type, 'data': frequencies, 'max': max_v, 'avg': avg_v, 'delta': delta }
+
+ # Get data provider.
+ if "data_standalone" in data_sources:
+ tracks_dataset_type = data_sources['data_standalone']['name']
+ data_provider_class = get_data_provider( name=tracks_dataset_type, original_dataset=dataset )
+ data_provider = data_provider_class( original_dataset=dataset )
+ else:
+ tracks_dataset_type = data_sources['data']['name']
+ data_provider_class = get_data_provider( name=tracks_dataset_type, original_dataset=dataset )
+ converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
+ deps = dataset.get_converted_dataset_deps( trans, tracks_dataset_type )
+ data_provider = data_provider_class( converted_dataset=converted_dataset, original_dataset=dataset, dependencies=deps )
+
+ # Allow max_vals top be data provider set if not passed
+ if max_vals is None:
+ max_vals = data_provider.get_default_max_vals()
+
+ # Get and return data from data_provider.
+ result = data_provider.get_data( chrom, int( low ), int( high ), int( start_val ), int( max_vals ), **kwargs )
+ result.update( { 'dataset_type': tracks_dataset_type, 'extra_info': extra_info } )
+ return result
+
+ def _raw_data( self, trans, dataset, chrom, low, high, **kwargs ):
+ """
+ Uses original (raw) dataset to return data. This method is useful
+ when the dataset is not yet indexed and hence using data would
+ be slow because indexes need to be created.
+ """
+
+ # Dataset check.
+ msg = self.check_dataset_state( trans, dataset )
+ if msg:
+ return msg
+
+ low, high = int( low ), int( high )
+
+ # Return data.
+ data = None
+ # TODO: for raw data requests, map dataset type to provider using dict in data_providers.py
+ if isinstance( dataset.datatype, Gff ):
+ data = RawGFFDataProvider( original_dataset=dataset ).get_data( chrom, low, high, **kwargs )
+ data[ 'dataset_type' ] = 'interval_index'
+ data[ 'extra_info' ] = None
+ elif isinstance( dataset.datatype, Bed ):
+ data = RawBedDataProvider( original_dataset=dataset ).get_data( chrom, low, high, **kwargs )
+ data[ 'dataset_type' ] = 'interval_index'
+ data[ 'extra_info' ] = None
+ elif isinstance( dataset.datatype, Vcf ):
+ data = RawVcfDataProvider( original_dataset=dataset ).get_data( chrom, low, high, **kwargs )
+ data[ 'dataset_type' ] = 'tabix'
+ data[ 'extra_info' ] = None
+ return data
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -450,7 +450,7 @@
session.add( vis_rev )
session.flush()
encoded_id = trans.security.encode_id( vis.id )
- return { "vis_id": encoded_id, "url": url_for( action='browser', id=encoded_id ) }
+ return { "vis_id": encoded_id, "url": url_for( action=vis.type, id=encoded_id ) }
def get_visualization( self, trans, id, check_ownership=True, check_accessible=False ):
""" Get a Visualization from the database by id, verifying ownership. """
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py
+++ /dev/null
@@ -1,258 +0,0 @@
-"""
-Support for constructing and viewing custom "track" browsers within Galaxy.
-"""
-
-import re, pkg_resources
-pkg_resources.require( "bx-python" )
-
-from galaxy import model
-from galaxy.util.json import to_json_string, from_json_string
-from galaxy.web.base.controller import *
-from galaxy.web.framework import simplejson
-from galaxy.web.framework.helpers import time_ago, grids
-from galaxy.util.bunch import Bunch
-from galaxy.datatypes.interval import Gff, Bed
-from galaxy.model import NoConverterException, ConverterDependencyException
-from galaxy.visualization.genome.data_providers import *
-from galaxy.visualization.genomes import decode_dbkey, Genomes
-from galaxy.visualization.genome.visual_analytics import get_dataset_job
-
-class TracksController( BaseUIController, UsesVisualizationMixin, SharableMixin ):
- """
- Controller for track browser interface. Handles building a new browser from
- datasets in the current history, and display of the resulting browser.
- """
-
- @web.expose
- @web.require_login()
- def index( self, trans, **kwargs ):
- config = {}
- return trans.fill_template( "tracks/browser.mako", config=config, add_dataset=kwargs.get("dataset_id", None), \
- default_dbkey=kwargs.get("default_dbkey", None) )
-
- @web.expose
- @web.require_login()
- def new_browser( self, trans, **kwargs ):
- return trans.fill_template( "tracks/new_browser.mako", dbkeys=trans.app.genomes.get_dbkeys_with_chrom_info( trans ), default_dbkey=kwargs.get("default_dbkey", None) )
-
- @web.json
- def save( self, trans, vis_json ):
- """
- Save a visualization; if visualization does not have an ID, a new
- visualization is created. Returns JSON of visualization.
- """
-
- # TODO: Need from_dict to convert json to Visualization object.
- vis_config = from_json_string( vis_json )
- config = {
- 'view': vis_config[ 'datasets' ],
- 'bookmarks': vis_config[ 'bookmarks' ],
- 'viewport': vis_config[ 'viewport' ]
- }
- type = vis_config[ 'type' ]
- id = vis_config.get( 'id', None )
- title = vis_config[ 'title' ]
- dbkey = vis_config[ 'dbkey' ]
- annotation = vis_config.get( 'annotation', None )
- return self.save_visualization( trans, config, type, id, title, dbkey, annotation )
-
- @web.expose
- @web.require_login()
- def browser(self, trans, id, **kwargs):
- """
- Display browser for the visualization denoted by id and add the datasets listed in `dataset_ids`.
- """
- vis = self.get_visualization( trans, id, check_ownership=False, check_accessible=True )
- viz_config = self.get_visualization_config( trans, vis )
-
- new_dataset = kwargs.get("dataset_id", None)
- if new_dataset is not None:
- if trans.security.decode_id(new_dataset) in [ d["dataset_id"] for d in viz_config.get("tracks") ]:
- new_dataset = None # Already in browser, so don't add
- return trans.fill_template( 'tracks/browser.mako', config=viz_config, add_dataset=new_dataset )
-
- @web.json
- def raw_data( self, trans, dataset_id, chrom, low, high, **kwargs ):
- """
- Uses original (raw) dataset to return data. This method is useful
- when the dataset is not yet indexed and hence using data would
- be slow because indexes need to be created.
- """
-
- # Dataset check.
- dataset = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True )
- msg = self.check_dataset_state( trans, dataset )
- if msg:
- return msg
-
- low, high = int( low ), int( high )
-
- # Return data.
- data = None
- # TODO: for raw data requests, map dataset type to provider using dict in data_providers.py
- if isinstance( dataset.datatype, Gff ):
- data = RawGFFDataProvider( original_dataset=dataset ).get_data( chrom, low, high, **kwargs )
- data[ 'dataset_type' ] = 'interval_index'
- data[ 'extra_info' ] = None
- elif isinstance( dataset.datatype, Bed ):
- data = RawBedDataProvider( original_dataset=dataset ).get_data( chrom, low, high, **kwargs )
- data[ 'dataset_type' ] = 'interval_index'
- data[ 'extra_info' ] = None
- elif isinstance( dataset.datatype, Vcf ):
- data = RawVcfDataProvider( original_dataset=dataset ).get_data( chrom, low, high, **kwargs )
- data[ 'dataset_type' ] = 'tabix'
- data[ 'extra_info' ] = None
- return data
-
- @web.json
- def dataset_state( self, trans, dataset_id, **kwargs ):
- """ Returns state of dataset. """
-
- dataset = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True )
- msg = self.check_dataset_state( trans, dataset )
- if not msg:
- msg = messages.DATA
-
- return msg
-
- @web.json
- def converted_datasets_state( self, trans, hda_ldda, dataset_id, chrom=None ):
- """
- Init-like method that returns state of dataset's converted datasets. Returns valid chroms
- for that dataset as well.
- """
- # TODO: this code is copied from data() -- should refactor.
-
- # Dataset check.
- if hda_ldda == "hda":
- dataset = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True )
- else:
- dataset = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
- msg = self.check_dataset_state( trans, dataset )
- if msg:
- return msg
-
- # Get datasources and check for messages.
- data_sources = self._get_datasources( trans, dataset )
- messages_list = [ data_source_dict[ 'message' ] for data_source_dict in data_sources.values() ]
- msg = get_highest_priority_msg( messages_list )
- if msg:
- return msg
-
- # NOTE: finding valid chroms is prohibitive for large summary trees and is not currently used by
- # the client.
- valid_chroms = None
- # Check for data in the genome window.
- if data_sources.get( 'index' ):
- tracks_dataset_type = data_sources['index']['name']
- converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
- indexer = get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
- if not indexer.has_data( chrom ):
- return messages.NO_DATA
- #valid_chroms = indexer.valid_chroms()
- else:
- # Standalone data provider
- standalone_provider = get_data_provider( data_sources['data_standalone']['name'] )( dataset )
- kwargs = {"stats": True}
- if not standalone_provider.has_data( chrom ):
- return messages.NO_DATA
- #valid_chroms = standalone_provider.valid_chroms()
-
- # Have data if we get here
- return { "status": messages.DATA, "valid_chroms": valid_chroms }
-
- @web.json
- def search_features( self, trans, hda_ldda, dataset_id, query ):
- """
- Returns features, locations in dataset that match query. Format is a
- list of features; each feature is a list itself: [name, location]
- """
- dataset = self.get_hda_or_ldda( trans, hda_ldda, dataset_id )
- if dataset.can_convert_to( "fli" ):
- converted_dataset = dataset.get_converted_dataset( trans, "fli" )
- if converted_dataset:
- data_provider = FeatureLocationIndexDataProvider( converted_dataset=converted_dataset )
- if data_provider:
- return data_provider.get_data( query )
-
- return []
-
- @web.json
- def data( self, trans, hda_ldda, dataset_id, chrom, low, high, start_val=0, max_vals=None, **kwargs ):
- """
- Provides a block of data from a dataset.
- """
-
- # Parameter check.
- if not chrom:
- return messages.NO_DATA
-
- # Dataset check.
- if hda_ldda == "hda":
- dataset = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True )
- else:
- dataset = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
- msg = self.check_dataset_state( trans, dataset )
- if msg:
- return msg
-
- # Get datasources and check for messages.
- data_sources = self._get_datasources( trans, dataset )
- messages_list = [ data_source_dict[ 'message' ] for data_source_dict in data_sources.values() ]
- return_message = get_highest_priority_msg( messages_list )
- if return_message:
- return return_message
-
- extra_info = None
- mode = kwargs.get( "mode", "Auto" )
- # Handle histogram mode uniquely for now:
- if mode == "Coverage":
- # Get summary using minimal cutoffs.
- tracks_dataset_type = data_sources['index']['name']
- converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
- indexer = get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
- summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ], detail_cutoff=0, draw_cutoff=0 )
- if summary == "detail":
- # Use maximum level of detail--2--to get summary data no matter the resolution.
- summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ], level=2, detail_cutoff=0, draw_cutoff=0 )
- frequencies, max_v, avg_v, delta = summary
- return { 'dataset_type': tracks_dataset_type, 'data': frequencies, 'max': max_v, 'avg': avg_v, 'delta': delta }
-
- if 'index' in data_sources and data_sources['index']['name'] == "summary_tree" and mode == "Auto":
- # Only check for summary_tree if it's Auto mode (which is the default)
- #
- # Have to choose between indexer and data provider
- tracks_dataset_type = data_sources['index']['name']
- converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
- indexer = get_data_provider( tracks_dataset_type )( converted_dataset, dataset )
- summary = indexer.get_data( chrom, low, high, resolution=kwargs[ 'resolution' ] )
- if summary is None:
- return { 'dataset_type': tracks_dataset_type, 'data': None }
-
- if summary == "draw":
- kwargs["no_detail"] = True # meh
- extra_info = "no_detail"
- elif summary != "detail":
- frequencies, max_v, avg_v, delta = summary
- return { 'dataset_type': tracks_dataset_type, 'data': frequencies, 'max': max_v, 'avg': avg_v, 'delta': delta }
-
- # Get data provider.
- if "data_standalone" in data_sources:
- tracks_dataset_type = data_sources['data_standalone']['name']
- data_provider_class = get_data_provider( name=tracks_dataset_type, original_dataset=dataset )
- data_provider = data_provider_class( original_dataset=dataset )
- else:
- tracks_dataset_type = data_sources['data']['name']
- data_provider_class = get_data_provider( name=tracks_dataset_type, original_dataset=dataset )
- converted_dataset = dataset.get_converted_dataset( trans, tracks_dataset_type )
- deps = dataset.get_converted_dataset_deps( trans, tracks_dataset_type )
- data_provider = data_provider_class( converted_dataset=converted_dataset, original_dataset=dataset, dependencies=deps )
-
- # Allow max_vals top be data provider set if not passed
- if max_vals is None:
- max_vals = data_provider.get_default_max_vals()
-
- # Get and return data from data_provider.
- result = data_provider.get_data( chrom, int( low ), int( high ), int( start_val ), int( max_vals ), **kwargs )
- result.update( { 'dataset_type': tracks_dataset_type, 'extra_info': extra_info } )
- return result
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py
+++ b/lib/galaxy/web/controllers/visualization.py
@@ -148,15 +148,9 @@
"""
Returns dictionary used to create item link.
"""
- controller = "tracks"
- if item.type == "trackster":
- action = "browser"
- elif item.type == "paramamonster":
- action = "paramamonster"
- elif item.type == "circster":
- action = "circster"
- elif item.type == "phyloviz":
- # Support phyloviz
+ controller = "visualization"
+ action = item.type
+ if item.type == "phyloviz":
controller = "phyloviz"
action = "visualization"
return dict( controller=controller, action=action, id=item.id )
@@ -679,6 +673,65 @@
help="A description of the visualization; annotation is shown alongside published visualizations."),
template="visualization/create.mako" )
+ #
+ # Visualizations.
+ #
+
+ @web.expose
+ @web.require_login()
+ def new_browser( self, trans, **kwargs ):
+ """
+ Provide info necessary for creating a new trackster browser.
+ """
+ return trans.fill_template( "tracks/new_browser.mako",
+ dbkeys=trans.app.genomes.get_dbkeys_with_chrom_info( trans ),
+ default_dbkey=kwargs.get("default_dbkey", None) )
+
+ @web.expose
+ @web.require_login()
+ def trackster(self, trans, id=None, **kwargs):
+ """
+ Display browser for the visualization denoted by id and add the datasets listed in `dataset_ids`.
+ """
+
+ # Display new browser if no id provided.
+ if not id:
+ return trans.fill_template( "tracks/browser.mako", config={},
+ add_dataset=kwargs.get("dataset_id", None),
+ default_dbkey=kwargs.get("default_dbkey", None) )
+
+ # Display saved visualization.
+ vis = self.get_visualization( trans, id, check_ownership=False, check_accessible=True )
+ viz_config = self.get_visualization_config( trans, vis )
+
+ # Get new dataset if specified.
+ new_dataset = kwargs.get("dataset_id", None)
+ if new_dataset is not None:
+ if trans.security.decode_id(new_dataset) in [ d["dataset_id"] for d in viz_config.get("tracks") ]:
+ new_dataset = None # Already in browser, so don't add
+ return trans.fill_template( 'tracks/browser.mako', config=viz_config, add_dataset=new_dataset )
+
+ @web.json
+ def save_trackster( self, trans, vis_json ):
+ """
+ Save a visualization; if visualization does not have an ID, a new
+ visualization is created. Returns JSON of visualization.
+ """
+
+ # TODO: Need from_dict to convert json to Visualization object.
+ vis_config = from_json_string( vis_json )
+ config = {
+ 'view': vis_config[ 'datasets' ],
+ 'bookmarks': vis_config[ 'bookmarks' ],
+ 'viewport': vis_config[ 'viewport' ]
+ }
+ type = vis_config[ 'type' ]
+ id = vis_config.get( 'id', None )
+ title = vis_config[ 'title' ]
+ dbkey = vis_config[ 'dbkey' ]
+ annotation = vis_config.get( 'annotation', None )
+ return self.save_visualization( trans, config, type, id, title, dbkey, annotation )
+
@web.expose
def circster( self, trans, id, **kwargs ):
"""
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 static/scripts/viz/trackster.js
--- a/static/scripts/viz/trackster.js
+++ b/static/scripts/viz/trackster.js
@@ -2974,12 +2974,10 @@
//
// Attribute init.
//
- this.data_url = ('data_url' in obj_dict ? obj_dict.data_url : default_data_url);
+ var url_base = datasets_url + '/' + obj_dict.dataset_id;
+ this.data_url = ('data_url' in obj_dict ? obj_dict.data_url : url_base);
this.data_url_extra_params = {};
this.data_query_wait = ('data_query_wait' in obj_dict ? obj_dict.data_query_wait : DEFAULT_DATA_QUERY_WAIT);
- this.dataset_check_url = ('converted_datasets_state_url' in obj_dict ? obj_dict.converted_datasets_state_url : converted_datasets_state_url);
- this.feature_search_url = ('feature_search_url' in obj_dict ? obj_dict.feature_search_url : feature_search_url);
-
// A little ugly creating data manager right now due to transition to Backbone-based objects.
var track = this,
dataset = new Dataset({
@@ -2991,8 +2989,6 @@
new GenomeDataManager({
dataset: dataset,
data_url: track.data_url,
- dataset_state_url: track.dataset_check_url,
- feature_search_url: track.feature_search_url,
data_mode_compatible: this.data_and_mode_compatible,
can_subset: this.can_subset
}));
@@ -3312,9 +3308,12 @@
// Get dataset state; if state is fine, enable and draw track. Otherwise, show message
// about track status.
- var init_deferred = $.Deferred();
- $.getJSON(this.dataset_check_url, { hda_ldda: track.hda_ldda, dataset_id: track.dataset_id, chrom: track.view.chrom},
- function (result) {
+ var init_deferred = $.Deferred(),
+ params = {
+ hda_ldda: track.hda_ldda,
+ data_type: 'converted_datasets_state',
+ chrom: track.view.chrom}
+ $.getJSON(this.data_url, params, function (result) {
if (!result || result === "error" || result.kind === "error") {
track.container_div.addClass("error");
track.tiles_div.text(DATA_ERROR);
@@ -4320,8 +4319,10 @@
predraw_init: function() {
var track = this;
track.vertical_range = undefined;
- return $.getJSON( track.data_url, { stats: true, chrom: track.view.chrom, low: 0, high: track.view.max_high,
- hda_ldda: track.hda_ldda, dataset_id: track.dataset_id }, function(result) {
+ return $.getJSON( track.data_url,
+ { data_type: 'data', stats: true, chrom: track.view.chrom, low: 0,
+ high: track.view.max_high, hda_ldda: track.hda_ldda, dataset_id:
+ track.dataset_id }, function(result) {
track.container_div.addClass( "line-track" );
var data = result.data;
if ( isNaN(parseFloat(track.prefs.min_value)) || isNaN(parseFloat(track.prefs.max_value)) ) {
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -170,7 +170,6 @@
dataset: null,
filters_manager: null,
data_url: null,
- dataset_state_url: null,
feature_search_url: null,
genome_wide_summary_data: null,
data_mode_compatible: function(entry, mode) { return true; },
@@ -186,10 +185,11 @@
ready_deferred = $.Deferred(),
ss_deferred = new ServerStateDeferred({
ajax_settings: {
- url: this.get('dataset_state_url'),
+ url: this.get('data_url'),
data: {
dataset_id: dataset.id,
- hda_ldda: dataset.get('hda_ldda')
+ hda_ldda: dataset.get('hda_ldda'),
+ data_type: 'state'
},
dataType: "json"
},
@@ -211,9 +211,10 @@
params = {
query: query,
dataset_id: dataset.id,
- hda_ldda: dataset.get('hda_ldda')
+ hda_ldda: dataset.get('hda_ldda'),
+ data_type: 'features'
};
- return $.getJSON(this.get('feature_search_url'), params);
+ return $.getJSON(this.get('data_url'), params);
},
/**
@@ -222,10 +223,11 @@
load_data: function(region, mode, resolution, extra_params) {
// Setup data request params.
var params = {
+ "data_type": "data",
"chrom": region.get('chrom'),
"low": region.get('start'),
"high": region.get('end'),
- "mode": mode,
+ "mode": mode,
"resolution": resolution
},
dataset = this.get('dataset');
@@ -743,7 +745,7 @@
var requests = [];
$('input[name=id]:checked,input[name=ldda_ids]:checked').each(function() {
var data = {
- 'track_config': true,
+ data_type: 'track_config',
'hda_ldda': 'hda'
},
id = $(this).val();
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 templates/base_panels.mako
--- a/templates/base_panels.mako
+++ b/templates/base_panels.mako
@@ -58,10 +58,7 @@
tool_url: '${h.url_for( controller="/api/tools" )}',
history_url: '${h.url_for( controller="/api/histories" )}',
- data_url: '${h.url_for( controller="/tracks", action="data" )}',
- raw_data_url: '${h.url_for( controller="/tracks", action="raw_data" )}',
- converted_datasets_state_url: '${h.url_for( controller="/tracks", action="converted_datasets_state" )}',
- dataset_state_url: '${h.url_for( controller="/tracks", action="dataset_state" )}',
+ datasets_url: '${h.url_for( controller="/api/datasets" )}',
sweepster_url: '${h.url_for( controller="/visualization", action="sweepster" )}',
visualization_url: '${h.url_for( controller="/visualization", action="save" )}',
});
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 templates/root/alternate_history.mako
--- a/templates/root/alternate_history.mako
+++ b/templates/root/alternate_history.mako
@@ -136,8 +136,8 @@
else:
data_url = h.url_for( controller='visualization', action='list_tracks' )
trackster_urls[ 'hda-url' ] = data_url
- trackster_urls[ 'action-url' ] = h.url_for( controller='tracks', action='browser', dataset_id=encoded_data_id )
- trackster_urls[ 'new-url' ] = h.url_for( controller='tracks', action='index', dataset_id=encoded_data_id, default_dbkey=hda.dbkey )
+ trackster_urls[ 'action-url' ] = h.url_for( controller='visualization', action='trackster', dataset_id=encoded_data_id )
+ trackster_urls[ 'new-url' ] = h.url_for( controller='visualization', action='trackster', dataset_id=encoded_data_id, default_dbkey=hda.dbkey )
add_to_data( trackster_url=trackster_urls )
if trans.user:
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -235,8 +235,8 @@
data_url = h.url_for( controller='visualization', action='list_tracks' )
%><a href="javascript:void(0)" data-url="${data_url}" class="icon-button chart_curve tooltip trackster-add"
- action-url="${h.url_for( controller='tracks', action='browser', dataset_id=dataset_id)}"
- new-url="${h.url_for( controller='tracks', action='index', dataset_id=dataset_id, default_dbkey=data.dbkey)}" title="View in Trackster"></a>
+ action-url="${h.url_for( controller='visualization', action='trackster', dataset_id=dataset_id)}"
+ new-url="${h.url_for( controller='visualization', action='trackster', dataset_id=dataset_id, default_dbkey=data.dbkey)}" title="View in Trackster"></a>
%endif
<%
isPhylogenyData = isinstance(data.datatype, (Phyloxml, Nexus, Newick))
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 templates/tool_form.mako
--- a/templates/tool_form.mako
+++ b/templates/tool_form.mako
@@ -77,7 +77,7 @@
$(".add-librarydataset").live("click", function() {
var link = $(this);
$.ajax({
- url: "/tracks/list_libraries",
+ url: "/visualization/list_libraries",
error: function(xhr, ajaxOptions, thrownError) { alert( "Grid failed" ); console.log(xhr, ajaxOptions, thrownError); },
success: function(table_html) {
show_modal(
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -23,13 +23,15 @@
<![endif]-->
${render_trackster_js_files()}
+${h.js( "libs/jquery/jquery.autocomplete" )}
+
<script type="text/javascript">
//
// Place URLs here so that url_for can be used to generate them.
//
galaxy_paths.set({
- visualization_url: "${h.url_for( action='save' )}"
+ visualization_url: "${h.url_for( action='save_trackster' )}"
});
${render_trackster_js_vars()}
@@ -234,7 +236,7 @@
%if add_dataset is not None:
$.ajax({
url: add_track_async_url + "/${add_dataset}",
- data: { hda_ldda: 'hda', 'track_config': true },
+ data: { hda_ldda: 'hda', data_type: 'track_config' },
dataType: "json",
success: function(track_data) { view.add_drawable( object_from_template(track_data, view, view) ) }
});
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 templates/visualization/trackster_common.mako
--- a/templates/visualization/trackster_common.mako
+++ b/templates/visualization/trackster_common.mako
@@ -18,11 +18,7 @@
<%def name="render_trackster_js_vars()">
var add_track_async_url = "${h.url_for( controller='/api/datasets' )}",
add_datasets_url = "${h.url_for( controller='/visualization', action='list_current_history_datasets' )}",
- default_data_url = "${h.url_for( controller='/tracks', action='data' )}",
- raw_data_url = "${h.url_for( controller='/tracks', action='raw_data' )}",
reference_url = "${h.url_for( controller='/api/genomes' )}",
chrom_url = "${h.url_for( controller='/api/genomes' )}",
- dataset_state_url = "${h.url_for( controller='/tracks', action='dataset_state' )}",
- converted_datasets_state_url = "${h.url_for( controller='/tracks', action='converted_datasets_state' )}",
- feature_search_url = "${h.url_for( controller='/tracks', action='search_features' )}";
+ datasets_url = "${h.url_for( controller='/api/datasets' )}";
</%def>
\ No newline at end of file
diff -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 -r 6243b992762c3f90abda948e081d266ca63e1db0 templates/webapps/galaxy/base_panels.mako
--- a/templates/webapps/galaxy/base_panels.mako
+++ b/templates/webapps/galaxy/base_panels.mako
@@ -98,7 +98,7 @@
## Visualization menu.
<%
menu_options = [
- [_('New Visualization'), h.url_for( controller='/tracks', action='index' ) ],
+ [_('New Visualization'), h.url_for( controller='/visualization', action='trackster' ) ],
[_('Saved Visualizations'), h.url_for( controller='/visualization', action='list' ) ]
]
tab( "visualization", _("Visualization"), h.url_for( controller='/visualization', action='list'), menu_options=menu_options )
https://bitbucket.org/galaxy/galaxy-central/changeset/2f63df922488/
changeset: 2f63df922488
user: jgoecks
date: 2012-09-15 23:06:36
summary: Bug fixes for changeset 6243b992762c that enable tools to be run in Trackster. Also add URL to all datasets and pack scripts.
affected #: 19 files
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 lib/galaxy/web/api/datasets.py
--- a/lib/galaxy/web/api/datasets.py
+++ b/lib/galaxy/web/api/datasets.py
@@ -7,6 +7,10 @@
from galaxy.web.base.controller import *
from galaxy.util.sanitize_html import sanitize_html
from galaxy.model.orm import *
+from galaxy.datatypes.interval import Gff, Bed
+from galaxy.datatypes.tabular import Vcf
+from galaxy.visualization.genome.data_providers import *
+from galaxy.model import NoConverterException, ConverterDependencyException
log = logging.getLogger( __name__ )
@@ -35,7 +39,7 @@
# Use data type to return particular type of data.
if data_type == 'state':
- rval = self._dataset_state( self, trans, dataset )
+ rval = self._dataset_state( trans, dataset )
elif data_type == 'converted_datasets_state':
rval = self._converted_datasets_state( trans, dataset, kwd.get( 'chrom', None ) )
elif data_type == 'data':
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/mvc/data.js
--- a/static/scripts/mvc/data.js
+++ b/static/scripts/mvc/data.js
@@ -8,7 +8,9 @@
type: '',
name: '',
hda_ldda: 'hda'
- }
+ },
+
+ urlRoot: galaxy_paths.get('datasets_url')
});
var DatasetCollection = Backbone.Collection.extend({
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/libs/require.js
--- /dev/null
+++ b/static/scripts/packed/libs/require.js
@@ -0,0 +1,1 @@
+var requirejs,require,define;(function(global){var req,s,head,baseElement,dataMain,src,interactiveScript,currentlyAddingScript,mainScript,subPath,version="2.0.6",commentRegExp=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,cjsRequireRegExp=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,jsSuffixRegExp=/\.js$/,currDirRegExp=/^\.\//,op=Object.prototype,ostring=op.toString,hasOwn=op.hasOwnProperty,ap=Array.prototype,aps=ap.slice,apsp=ap.splice,isBrowser=!!(typeof window!=="undefined"&&navigator&&document),isWebWorker=!isBrowser&&typeof importScripts!=="undefined",readyRegExp=isBrowser&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaded)$/,defContextName="_",isOpera=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",contexts={},cfg={},globalDefQueue=[],useInteractive=false;function isFunction(it){return ostring.call(it)==="[object Function]"}function isArray(it){return ostring.call(it)==="[object Array]"}function each(ary,func){if(ary){var i;for(i=0;i<ary.length;i+=1){if(ary[i]&&func(ary[i],i,ary)){break}}}}function eachReverse(ary,func){if(ary){var i;for(i=ary.length-1;i>-1;i-=1){if(ary[i]&&func(ary[i],i,ary)){break}}}}function hasProp(obj,prop){return hasOwn.call(obj,prop)}function eachProp(obj,func){var prop;for(prop in obj){if(obj.hasOwnProperty(prop)){if(func(obj[prop],prop)){break}}}}function mixin(target,source,force,deepStringMixin){if(source){eachProp(source,function(value,prop){if(force||!hasProp(target,prop)){if(deepStringMixin&&typeof value!=="string"){if(!target[prop]){target[prop]={}}mixin(target[prop],value,force,deepStringMixin)}else{target[prop]=value}}})}return target}function bind(obj,fn){return function(){return fn.apply(obj,arguments)}}function scripts(){return document.getElementsByTagName("script")}function getGlobal(value){if(!value){return value}var g=global;each(value.split("."),function(part){g=g[part]});return g}function makeContextModuleFunc(func,relMap,enableBuildCallback){return function(){var args=aps.call(arguments,0),lastArg;if(enableBuildCallback&&isFunction((lastArg=args[args.length-1]))){lastArg.__requireJsBuild=true}args.push(relMap);return func.apply(null,args)}}function addRequireMethods(req,context,relMap){each([["toUrl"],["undef"],["defined","requireDefined"],["specified","requireSpecified"]],function(item){var prop=item[1]||item[0];req[item[0]]=context?makeContextModuleFunc(context[prop],relMap):function(){var ctx=contexts[defContextName];return ctx[prop].apply(ctx,arguments)}})}function makeError(id,msg,err,requireModules){var e=new Error(msg+"\nhttp://requirejs.org/docs/errors.html#"+id);e.requireType=id;e.requireModules=requireModules;if(err){e.originalError=err}return e}if(typeof define!=="undefined"){return}if(typeof requirejs!=="undefined"){if(isFunction(requirejs)){return}cfg=requirejs;requirejs=undefined}if(typeof require!=="undefined"&&!isFunction(require)){cfg=require;require=undefined}function newContext(contextName){var inCheckLoaded,Module,context,handlers,checkLoadedTimeoutId,config={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},shim:{}},registry={},undefEvents={},defQueue=[],defined={},urlFetched={},requireCounter=1,unnormalizedCounter=1,waitAry=[];function trimDots(ary){var i,part;for(i=0;ary[i];i+=1){part=ary[i];if(part==="."){ary.splice(i,1);i-=1}else{if(part===".."){if(i===1&&(ary[2]===".."||ary[0]==="..")){break}else{if(i>0){ary.splice(i-1,2);i-=2}}}}}}function normalize(name,baseName,applyMap){var pkgName,pkgConfig,mapValue,nameParts,i,j,nameSegment,foundMap,foundI,foundStarMap,starI,baseParts=baseName&&baseName.split("/"),normalizedBaseParts=baseParts,map=config.map,starMap=map&&map["*"];if(name&&name.charAt(0)==="."){if(baseName){if(config.pkgs[baseName]){normalizedBaseParts=baseParts=[baseName]}else{normalizedBaseParts=baseParts.slice(0,baseParts.length-1)}name=normalizedBaseParts.concat(name.split("/"));trimDots(name);pkgConfig=config.pkgs[(pkgName=name[0])];name=name.join("/");if(pkgConfig&&name===pkgName+"/"+pkgConfig.main){name=pkgName}}else{if(name.indexOf("./")===0){name=name.substring(2)}}}if(applyMap&&(baseParts||starMap)&&map){nameParts=name.split("/");for(i=nameParts.length;i>0;i-=1){nameSegment=nameParts.slice(0,i).join("/");if(baseParts){for(j=baseParts.length;j>0;j-=1){mapValue=map[baseParts.slice(0,j).join("/")];if(mapValue){mapValue=mapValue[nameSegment];if(mapValue){foundMap=mapValue;foundI=i;break}}}}if(foundMap){break}if(!foundStarMap&&starMap&&starMap[nameSegment]){foundStarMap=starMap[nameSegment];starI=i}}if(!foundMap&&foundStarMap){foundMap=foundStarMap;foundI=starI}if(foundMap){nameParts.splice(0,foundI,foundMap);name=nameParts.join("/")}}return name}function removeScript(name){if(isBrowser){each(scripts(),function(scriptNode){if(scriptNode.getAttribute("data-requiremodule")===name&&scriptNode.getAttribute("data-requirecontext")===context.contextName){scriptNode.parentNode.removeChild(scriptNode);return true}})}}function hasPathFallback(id){var pathConfig=config.paths[id];if(pathConfig&&isArray(pathConfig)&&pathConfig.length>1){removeScript(id);pathConfig.shift();context.undef(id);context.require([id]);return true}}function makeModuleMap(name,parentModuleMap,isNormalized,applyMap){var url,pluginModule,suffix,index=name?name.indexOf("!"):-1,prefix=null,parentName=parentModuleMap?parentModuleMap.name:null,originalName=name,isDefine=true,normalizedName="";if(!name){isDefine=false;name="_@r"+(requireCounter+=1)}if(index!==-1){prefix=name.substring(0,index);name=name.substring(index+1,name.length)}if(prefix){prefix=normalize(prefix,parentName,applyMap);pluginModule=defined[prefix]}if(name){if(prefix){if(pluginModule&&pluginModule.normalize){normalizedName=pluginModule.normalize(name,function(name){return normalize(name,parentName,applyMap)})}else{normalizedName=normalize(name,parentName,applyMap)}}else{normalizedName=normalize(name,parentName,applyMap);url=context.nameToUrl(normalizedName)}}suffix=prefix&&!pluginModule&&!isNormalized?"_unnormalized"+(unnormalizedCounter+=1):"";return{prefix:prefix,name:normalizedName,parentMap:parentModuleMap,unnormalized:!!suffix,url:url,originalName:originalName,isDefine:isDefine,id:(prefix?prefix+"!"+normalizedName:normalizedName)+suffix}}function getModule(depMap){var id=depMap.id,mod=registry[id];if(!mod){mod=registry[id]=new context.Module(depMap)}return mod}function on(depMap,name,fn){var id=depMap.id,mod=registry[id];if(hasProp(defined,id)&&(!mod||mod.defineEmitComplete)){if(name==="defined"){fn(defined[id])}}else{getModule(depMap).on(name,fn)}}function onError(err,errback){var ids=err.requireModules,notified=false;if(errback){errback(err)}else{each(ids,function(id){var mod=registry[id];if(mod){mod.error=err;if(mod.events.error){notified=true;mod.emit("error",err)}}});if(!notified){req.onError(err)}}}function takeGlobalQueue(){if(globalDefQueue.length){apsp.apply(defQueue,[defQueue.length-1,0].concat(globalDefQueue));globalDefQueue=[]}}function makeRequire(mod,enableBuildCallback,altRequire){var relMap=mod&&mod.map,modRequire=makeContextModuleFunc(altRequire||context.require,relMap,enableBuildCallback);addRequireMethods(modRequire,context,relMap);modRequire.isBrowser=isBrowser;return modRequire}handlers={require:function(mod){return makeRequire(mod)},exports:function(mod){mod.usingExports=true;if(mod.map.isDefine){return(mod.exports=defined[mod.map.id]={})}},module:function(mod){return(mod.module={id:mod.map.id,uri:mod.map.url,config:function(){return(config.config&&config.config[mod.map.id])||{}},exports:defined[mod.map.id]})}};function removeWaiting(id){delete registry[id];each(waitAry,function(mod,i){if(mod.map.id===id){waitAry.splice(i,1);if(!mod.defined){context.waitCount-=1}return true}})}function findCycle(mod,traced,processed){var id=mod.map.id,depArray=mod.depMaps,foundModule;if(!mod.inited){return}if(traced[id]){return mod}traced[id]=true;each(depArray,function(depMap){var depId=depMap.id,depMod=registry[depId];if(!depMod||processed[depId]||!depMod.inited||!depMod.enabled){return}return(foundModule=findCycle(depMod,traced,processed))});processed[id]=true;return foundModule}function forceExec(mod,traced,uninited){var id=mod.map.id,depArray=mod.depMaps;if(!mod.inited||!mod.map.isDefine){return}if(traced[id]){return defined[id]}traced[id]=mod;each(depArray,function(depMap){var depId=depMap.id,depMod=registry[depId],value;if(handlers[depId]){return}if(depMod){if(!depMod.inited||!depMod.enabled){uninited[id]=true;return}value=forceExec(depMod,traced,uninited);if(!uninited[depId]){mod.defineDepById(depId,value)}}});mod.check(true);return defined[id]}function modCheck(mod){mod.check()}function checkLoaded(){var map,modId,err,usingPathFallback,waitInterval=config.waitSeconds*1000,expired=waitInterval&&(context.startTime+waitInterval)<new Date().getTime(),noLoads=[],stillLoading=false,needCycleCheck=true;if(inCheckLoaded){return}inCheckLoaded=true;eachProp(registry,function(mod){map=mod.map;modId=map.id;if(!mod.enabled){return}if(!mod.error){if(!mod.inited&&expired){if(hasPathFallback(modId)){usingPathFallback=true;stillLoading=true}else{noLoads.push(modId);removeScript(modId)}}else{if(!mod.inited&&mod.fetched&&map.isDefine){stillLoading=true;if(!map.prefix){return(needCycleCheck=false)}}}}});if(expired&&noLoads.length){err=makeError("timeout","Load timeout for modules: "+noLoads,null,noLoads);err.contextName=context.contextName;return onError(err)}if(needCycleCheck){each(waitAry,function(mod){if(mod.defined){return}var cycleMod=findCycle(mod,{},{}),traced={};if(cycleMod){forceExec(cycleMod,traced,{});eachProp(traced,modCheck)}});eachProp(registry,modCheck)}if((!expired||usingPathFallback)&&stillLoading){if((isBrowser||isWebWorker)&&!checkLoadedTimeoutId){checkLoadedTimeoutId=setTimeout(function(){checkLoadedTimeoutId=0;checkLoaded()},50)}}inCheckLoaded=false}Module=function(map){this.events=undefEvents[map.id]||{};this.map=map;this.shim=config.shim[map.id];this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};Module.prototype={init:function(depMaps,factory,errback,options){options=options||{};if(this.inited){return}this.factory=factory;if(errback){this.on("error",errback)}else{if(this.events.error){errback=bind(this,function(err){this.emit("error",err)})}}this.depMaps=depMaps&&depMaps.slice(0);this.depMaps.rjsSkipMap=depMaps.rjsSkipMap;this.errback=errback;this.inited=true;this.ignore=options.ignore;if(options.enabled||this.enabled){this.enable()}else{this.check()}},defineDepById:function(id,depExports){var i;each(this.depMaps,function(map,index){if(map.id===id){i=index;return true}});return this.defineDep(i,depExports)},defineDep:function(i,depExports){if(!this.depMatched[i]){this.depMatched[i]=true;this.depCount-=1;this.depExports[i]=depExports}},fetch:function(){if(this.fetched){return}this.fetched=true;context.startTime=(new Date()).getTime();var map=this.map;if(this.shim){makeRequire(this,true)(this.shim.deps||[],bind(this,function(){return map.prefix?this.callPlugin():this.load()}))}else{return map.prefix?this.callPlugin():this.load()}},load:function(){var url=this.map.url;if(!urlFetched[url]){urlFetched[url]=true;context.load(this.map.id,url)}},check:function(silent){if(!this.enabled||this.enabling){return}var err,cjsModule,id=this.map.id,depExports=this.depExports,exports=this.exports,factory=this.factory;if(!this.inited){this.fetch()}else{if(this.error){this.emit("error",this.error)}else{if(!this.defining){this.defining=true;if(this.depCount<1&&!this.defined){if(isFunction(factory)){if(this.events.error){try{exports=context.execCb(id,factory,depExports,exports)}catch(e){err=e}}else{exports=context.execCb(id,factory,depExports,exports)}if(this.map.isDefine){cjsModule=this.module;if(cjsModule&&cjsModule.exports!==undefined&&cjsModule.exports!==this.exports){exports=cjsModule.exports}else{if(exports===undefined&&this.usingExports){exports=this.exports}}}if(err){err.requireMap=this.map;err.requireModules=[this.map.id];err.requireType="define";return onError((this.error=err))}}else{exports=factory}this.exports=exports;if(this.map.isDefine&&!this.ignore){defined[id]=exports;if(req.onResourceLoad){req.onResourceLoad(context,this.map,this.depMaps)}}delete registry[id];this.defined=true;context.waitCount-=1;if(context.waitCount===0){waitAry=[]}}this.defining=false;if(!silent){if(this.defined&&!this.defineEmitted){this.defineEmitted=true;this.emit("defined",this.exports);this.defineEmitComplete=true}}}}}},callPlugin:function(){var map=this.map,id=map.id,pluginMap=makeModuleMap(map.prefix,null,false,true);on(pluginMap,"defined",bind(this,function(plugin){var load,normalizedMap,normalizedMod,name=this.map.name,parentName=this.map.parentMap?this.map.parentMap.name:null;if(this.map.unnormalized){if(plugin.normalize){name=plugin.normalize(name,function(name){return normalize(name,parentName,true)})||""}normalizedMap=makeModuleMap(map.prefix+"!"+name,this.map.parentMap,false,true);on(normalizedMap,"defined",bind(this,function(value){this.init([],function(){return value},null,{enabled:true,ignore:true})}));normalizedMod=registry[normalizedMap.id];if(normalizedMod){if(this.events.error){normalizedMod.on("error",bind(this,function(err){this.emit("error",err)}))}normalizedMod.enable()}return}load=bind(this,function(value){this.init([],function(){return value},null,{enabled:true})});load.error=bind(this,function(err){this.inited=true;this.error=err;err.requireModules=[id];eachProp(registry,function(mod){if(mod.map.id.indexOf(id+"_unnormalized")===0){removeWaiting(mod.map.id)}});onError(err)});load.fromText=function(moduleName,text){var hasInteractive=useInteractive;if(hasInteractive){useInteractive=false}getModule(makeModuleMap(moduleName));req.exec(text);if(hasInteractive){useInteractive=true}context.completeLoad(moduleName)};plugin.load(map.name,makeRequire(map.parentMap,true,function(deps,cb,er){deps.rjsSkipMap=true;return context.require(deps,cb,er)}),load,config)}));context.enable(pluginMap,this);this.pluginMaps[pluginMap.id]=pluginMap},enable:function(){this.enabled=true;if(!this.waitPushed){waitAry.push(this);context.waitCount+=1;this.waitPushed=true}this.enabling=true;each(this.depMaps,bind(this,function(depMap,i){var id,mod,handler;if(typeof depMap==="string"){depMap=makeModuleMap(depMap,(this.map.isDefine?this.map:this.map.parentMap),false,!this.depMaps.rjsSkipMap);this.depMaps[i]=depMap;handler=handlers[depMap.id];if(handler){this.depExports[i]=handler(this);return}this.depCount+=1;on(depMap,"defined",bind(this,function(depExports){this.defineDep(i,depExports);this.check()}));if(this.errback){on(depMap,"error",this.errback)}}id=depMap.id;mod=registry[id];if(!handlers[id]&&mod&&!mod.enabled){context.enable(depMap,this)}}));eachProp(this.pluginMaps,bind(this,function(pluginMap){var mod=registry[pluginMap.id];if(mod&&!mod.enabled){context.enable(pluginMap,this)}}));this.enabling=false;this.check()},on:function(name,cb){var cbs=this.events[name];if(!cbs){cbs=this.events[name]=[]}cbs.push(cb)},emit:function(name,evt){each(this.events[name],function(cb){cb(evt)});if(name==="error"){delete this.events[name]}}};function callGetModule(args){getModule(makeModuleMap(args[0],null,true)).init(args[1],args[2])}function removeListener(node,func,name,ieName){if(node.detachEvent&&!isOpera){if(ieName){node.detachEvent(ieName,func)}}else{node.removeEventListener(name,func,false)}}function getScriptData(evt){var node=evt.currentTarget||evt.srcElement;removeListener(node,context.onScriptLoad,"load","onreadystatechange");removeListener(node,context.onScriptError,"error");return{node:node,id:node&&node.getAttribute("data-requiremodule")}}return(context={config:config,contextName:contextName,registry:registry,defined:defined,urlFetched:urlFetched,waitCount:0,defQueue:defQueue,Module:Module,makeModuleMap:makeModuleMap,configure:function(cfg){if(cfg.baseUrl){if(cfg.baseUrl.charAt(cfg.baseUrl.length-1)!=="/"){cfg.baseUrl+="/"}}var pkgs=config.pkgs,shim=config.shim,paths=config.paths,map=config.map;mixin(config,cfg,true);config.paths=mixin(paths,cfg.paths,true);if(cfg.map){config.map=mixin(map||{},cfg.map,true,true)}if(cfg.shim){eachProp(cfg.shim,function(value,id){if(isArray(value)){value={deps:value}}if(value.exports&&!value.exports.__buildReady){value.exports=context.makeShimExports(value.exports)}shim[id]=value});config.shim=shim}if(cfg.packages){each(cfg.packages,function(pkgObj){var location;pkgObj=typeof pkgObj==="string"?{name:pkgObj}:pkgObj;location=pkgObj.location;pkgs[pkgObj.name]={name:pkgObj.name,location:location||pkgObj.name,main:(pkgObj.main||"main").replace(currDirRegExp,"").replace(jsSuffixRegExp,"")}});config.pkgs=pkgs}eachProp(registry,function(mod,id){if(!mod.inited&&!mod.map.unnormalized){mod.map=makeModuleMap(id)}});if(cfg.deps||cfg.callback){context.require(cfg.deps||[],cfg.callback)}},makeShimExports:function(exports){var func;if(typeof exports==="string"){func=function(){return getGlobal(exports)};func.exports=exports;return func}else{return function(){return exports.apply(global,arguments)}}},requireDefined:function(id,relMap){return hasProp(defined,makeModuleMap(id,relMap,false,true).id)},requireSpecified:function(id,relMap){id=makeModuleMap(id,relMap,false,true).id;return hasProp(defined,id)||hasProp(registry,id)},require:function(deps,callback,errback,relMap){var moduleName,id,map,requireMod,args;if(typeof deps==="string"){if(isFunction(callback)){return onError(makeError("requireargs","Invalid require call"),errback)}if(req.get){return req.get(context,deps,callback)}moduleName=deps;relMap=callback;map=makeModuleMap(moduleName,relMap,false,true);id=map.id;if(!hasProp(defined,id)){return onError(makeError("notloaded",'Module name "'+id+'" has not been loaded yet for context: '+contextName))}return defined[id]}if(errback&&!isFunction(errback)){relMap=errback;errback=undefined}if(callback&&!isFunction(callback)){relMap=callback;callback=undefined}takeGlobalQueue();while(defQueue.length){args=defQueue.shift();if(args[0]===null){return onError(makeError("mismatch","Mismatched anonymous define() module: "+args[args.length-1]))}else{callGetModule(args)}}requireMod=getModule(makeModuleMap(null,relMap));requireMod.init(deps,callback,errback,{enabled:true});checkLoaded();return context.require},undef:function(id){takeGlobalQueue();var map=makeModuleMap(id,null,true),mod=registry[id];delete defined[id];delete urlFetched[map.url];delete undefEvents[id];if(mod){if(mod.events.defined){undefEvents[id]=mod.events}removeWaiting(id)}},enable:function(depMap,parent){var mod=registry[depMap.id];if(mod){getModule(depMap).enable()}},completeLoad:function(moduleName){var found,args,mod,shim=config.shim[moduleName]||{},shExports=shim.exports&&shim.exports.exports;takeGlobalQueue();while(defQueue.length){args=defQueue.shift();if(args[0]===null){args[0]=moduleName;if(found){break}found=true}else{if(args[0]===moduleName){found=true}}callGetModule(args)}mod=registry[moduleName];if(!found&&!defined[moduleName]&&mod&&!mod.inited){if(config.enforceDefine&&(!shExports||!getGlobal(shExports))){if(hasPathFallback(moduleName)){return}else{return onError(makeError("nodefine","No define call for "+moduleName,null,[moduleName]))}}else{callGetModule([moduleName,(shim.deps||[]),shim.exports])}}checkLoaded()},toUrl:function(moduleNamePlusExt,relModuleMap){var index=moduleNamePlusExt.lastIndexOf("."),ext=null;if(index!==-1){ext=moduleNamePlusExt.substring(index,moduleNamePlusExt.length);moduleNamePlusExt=moduleNamePlusExt.substring(0,index)}return context.nameToUrl(normalize(moduleNamePlusExt,relModuleMap&&relModuleMap.id,true),ext)},nameToUrl:function(moduleName,ext){var paths,pkgs,pkg,pkgPath,syms,i,parentModule,url,parentPath;if(req.jsExtRegExp.test(moduleName)){url=moduleName+(ext||"")}else{paths=config.paths;pkgs=config.pkgs;syms=moduleName.split("/");for(i=syms.length;i>0;i-=1){parentModule=syms.slice(0,i).join("/");pkg=pkgs[parentModule];parentPath=paths[parentModule];if(parentPath){if(isArray(parentPath)){parentPath=parentPath[0]}syms.splice(0,i,parentPath);break}else{if(pkg){if(moduleName===pkg.name){pkgPath=pkg.location+"/"+pkg.main}else{pkgPath=pkg.location}syms.splice(0,i,pkgPath);break}}}url=syms.join("/");url+=(ext||(/\?/.test(url)?"":".js"));url=(url.charAt(0)==="/"||url.match(/^[\w\+\.\-]+:/)?"":config.baseUrl)+url}return config.urlArgs?url+((url.indexOf("?")===-1?"?":"&")+config.urlArgs):url},load:function(id,url){req.load(context,id,url)},execCb:function(name,callback,args,exports){return callback.apply(exports,args)},onScriptLoad:function(evt){if(evt.type==="load"||(readyRegExp.test((evt.currentTarget||evt.srcElement).readyState))){interactiveScript=null;var data=getScriptData(evt);context.completeLoad(data.id)}},onScriptError:function(evt){var data=getScriptData(evt);if(!hasPathFallback(data.id)){return onError(makeError("scripterror","Script error",evt,[data.id]))}}})}req=requirejs=function(deps,callback,errback,optional){var context,config,contextName=defContextName;if(!isArray(deps)&&typeof deps!=="string"){config=deps;if(isArray(callback)){deps=callback;callback=errback;errback=optional}else{deps=[]}}if(config&&config.context){contextName=config.context}context=contexts[contextName];if(!context){context=contexts[contextName]=req.s.newContext(contextName)}if(config){context.configure(config)}return context.require(deps,callback,errback)};req.config=function(config){return req(config)};if(!require){require=req}req.version=version;req.jsExtRegExp=/^\/|:|\?|\.js$/;req.isBrowser=isBrowser;s=req.s={contexts:contexts,newContext:newContext};req({});addRequireMethods(req);if(isBrowser){head=s.head=document.getElementsByTagName("head")[0];baseElement=document.getElementsByTagName("base")[0];if(baseElement){head=s.head=baseElement.parentNode}}req.onError=function(err){throw err};req.load=function(context,moduleName,url){var config=(context&&context.config)||{},node;if(isBrowser){node=config.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");node.type=config.scriptType||"text/javascript";node.charset="utf-8";node.async=true;node.setAttribute("data-requirecontext",context.contextName);node.setAttribute("data-requiremodule",moduleName);if(node.attachEvent&&!(node.attachEvent.toString&&node.attachEvent.toString().indexOf("[native code")<0)&&!isOpera){useInteractive=true;node.attachEvent("onreadystatechange",context.onScriptLoad)}else{node.addEventListener("load",context.onScriptLoad,false);node.addEventListener("error",context.onScriptError,false)}node.src=url;currentlyAddingScript=node;if(baseElement){head.insertBefore(node,baseElement)}else{head.appendChild(node)}currentlyAddingScript=null;return node}else{if(isWebWorker){importScripts(url);context.completeLoad(moduleName)}}};function getInteractiveScript(){if(interactiveScript&&interactiveScript.readyState==="interactive"){return interactiveScript}eachReverse(scripts(),function(script){if(script.readyState==="interactive"){return(interactiveScript=script)}});return interactiveScript}if(isBrowser){eachReverse(scripts(),function(script){if(!head){head=script.parentNode}dataMain=script.getAttribute("data-main");if(dataMain){if(!cfg.baseUrl){src=dataMain.split("/");mainScript=src.pop();subPath=src.length?src.join("/")+"/":"./";cfg.baseUrl=subPath;dataMain=mainScript}dataMain=dataMain.replace(jsSuffixRegExp,"");cfg.deps=cfg.deps?cfg.deps.concat(dataMain):[dataMain];return true}})}define=function(name,deps,callback){var node,context;if(typeof name!=="string"){callback=deps;deps=name;name=null}if(!isArray(deps)){callback=deps;deps=[]}if(!deps.length&&isFunction(callback)){if(callback.length){callback.toString().replace(commentRegExp,"").replace(cjsRequireRegExp,function(match,dep){deps.push(dep)});deps=(callback.length===1?["require"]:["require","exports","module"]).concat(deps)}}if(useInteractive){node=currentlyAddingScript||getInteractiveScript();if(node){if(!name){name=node.getAttribute("data-requiremodule")}context=contexts[node.getAttribute("data-requirecontext")]}}(context?context.defQueue:globalDefQueue).push([name,deps,callback])};define.amd={jQuery:true};req.exec=function(text){return eval(text)};req(cfg)}(this));
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/mvc/data.js
--- a/static/scripts/packed/mvc/data.js
+++ b/static/scripts/packed/mvc/data.js
@@ -1,1 +1,1 @@
-var Dataset=Backbone.RelationalModel.extend({defaults:{id:"",type:"",name:"",hda_ldda:"hda"}});var DatasetCollection=Backbone.Collection.extend({model:Dataset});
\ No newline at end of file
+var Dataset=Backbone.RelationalModel.extend({defaults:{id:"",type:"",name:"",hda_ldda:"hda"},urlRoot:galaxy_paths.get("datasets_url")});var DatasetCollection=Backbone.Collection.extend({model:Dataset});
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/mvc/history.js
--- a/static/scripts/packed/mvc/history.js
+++ b/static/scripts/packed/mvc/history.js
@@ -1,1 +1,1 @@
-function linkHTMLTemplate(b,a){if(!b){return"<a></a>"}a=a||"a";var c=["<"+a];for(key in b){var d=b[key];if(d===""){continue}switch(key){case"text":continue;case"classes":key="class";d=(b.classes.join)?(b.classes.join(" ")):(b.classes);default:c.push([" ",key,'="',d,'"'].join(""))}}c.push(">");if("text" in b){c.push(b.text)}c.push("</"+a+">");return c.join("")}var HistoryItem=BaseModel.extend(LoggableMixin).extend({defaults:{id:null,name:"",data_type:null,file_size:0,genome_build:null,metadata_data_lines:0,metadata_dbkey:null,metadata_sequences:0,misc_blurb:"",misc_info:"",model_class:"",state:"",deleted:false,purged:false,visible:true,for_editing:true,bodyIsShown:false},initialize:function(){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"))},isEditable:function(){return(!(this.get("deleted")||this.get("purged")))},hasData:function(){return(this.get("file_size")>0)},toString:function(){var a=this.get("id")||"";if(this.get("name")){a+=':"'+this.get("name")+'"'}return"HistoryItem("+a+")"}});HistoryItem.STATES={NEW:"new",UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",OK:"ok",EMPTY:"empty",ERROR:"error",DISCARDED:"discarded",SETTING_METADATA:"setting_metadata",FAILED_METADATA:"failed_metadata"};var HistoryItemView=BaseView.extend(LoggableMixin).extend({logger:console,tagName:"div",className:"historyItemContainer",initialize:function(){this.log(this+".initialize:",this,this.model)},render:function(){this.log(this+".model:",this.model);var d=this.model.get("id"),c=this.model.get("state");this.clearReferences();this.$el.attr("id","historyItemContainer-"+d);var a=$("<div/>").attr("id","historyItem-"+d).addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);a.find(".tooltip").tooltip({placement:"bottom"});var b=a.find("[popupmenu]");b.each(function(e,f){f=$(f);make_popupmenu(f)});this.$el.children().remove();return this.$el.append(a)},clearReferences:function(){this.displayButton=null;this.editButton=null;this.deleteButton=null;this.errButton=null},_render_warnings:function(){return $(jQuery.trim(HistoryItemView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_displayButton:function(){if(this.model.get("state")===HistoryItem.STATES.UPLOAD){return null}displayBtnData=(this.model.get("purged"))?({title:"Cannot display datasets removed from disk",enabled:false,icon_class:"display",}):({title:"Display data in browser",href:this.model.get("display_url"),target:(this.model.get("for_editing"))?("galaxy_main"):(null),icon_class:"display",});this.displayButton=new IconButtonView({model:new IconButton(displayBtnData)});return this.displayButton.render().$el},_render_editButton:function(){if((this.model.get("state")===HistoryItem.STATES.UPLOAD)||(!this.model.get("for_editing"))){return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:"Edit attributes",href:this.model.get("edit_url"),target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false}if(a){b.title="Undelete dataset to edit attributes"}else{if(c){b.title="Cannot edit attributes of datasets removed from disk"}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if(!this.model.get("for_editing")){return null}var a=(this.model.get("delete_url"))?({title:"Delete",href:this.model.get("delete_url"),target:"galaxy_main",id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"}):({title:"Dataset is already deleted",icon_class:"delete",enabled:false});this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_titleLink:function(){this.log("model:",this.model.toJSON());return $(jQuery.trim(HistoryItemView.templates.titleLink(this.model.toJSON())))},_render_body_not_viewable:function(a){a.append($("<div>You do not have permission to view dataset.</div>"))},_render_body_uploading:function(a){a.append($("<div>Dataset is uploading</div>"))},_render_body_queued:function(a){a.append($("<div>Job is waiting to run.</div>"));a.append(this._render_showParamsAndRerun())},_render_body_running:function(a){a.append("<div>Job is currently running.</div>");a.append(this._render_showParamsAndRerun())},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append(("An error occurred running this job: <i>"+$.trim(this.model.get("misc_info"))+"</i>"));var b=$(this._render_showParamsAndRerun());if(this.model.get("for_editing")){this.errButton=new IconButtonView({model:new IconButton({title:"View or report this error",href:this.model.get("report_error_url"),target:"galaxy_main",icon_class:"bug"})});b.prepend(this.errButton.render().$el)}if(this.model.hasData()){b.prepend(this._render_downloadLinks())}a.append(b)},_render_body_discarded:function(a){a.append("<div>The job creating this dataset was cancelled before completion.</div>");a.append(this._render_showParamsAndRerun())},_render_body_setting_metadata:function(a){a.append($("<div>Metadata is being auto-detected.</div>"))},_render_body_empty:function(a){a.append($("<div>No data: <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_showParamsAndRerun())},_render_body_failed_metadata:function(b){var c="An error occurred setting the metadata for this dataset.";if(this.model.isEditable()){var a=linkHTMLTemplate({text:"set it manually or retry auto-detection",href:this.model.get("edit_url"),target:"galaxy_main"});c+="You may be able to "+a+"."}b.append($(HistoryItemView.templates.warningMsg({warning:c})));this._render_body_ok(b)},_render_body_ok:function(h){h.append(this._render_hdaSummary());if(this.model.get("misc_info")){h.append($('<div class="info">Info: '+this.model.get("misc_info")+"</div>"))}if(this.model.hasData()){var c=$("<div/>");c.append(this._render_downloadLinks());c.append($(linkHTMLTemplate({title:"View details",href:this.model.get("show_params_url"),target:"galaxy_main",classes:["icon-button","tooltip","information"]})));if(this.model.get("for_editing")){c.append($(linkHTMLTemplate({title:"Run this job again",href:this.model.get("rerun_url"),target:"galaxy_main",classes:["icon-button","tooltip","arrow-circle"]})));if(this.model.get("trackster_urls")){var a=this.model.get("trackster_urls");c.append($(linkHTMLTemplate({title:"View in Trackster",href:"javascript:void(0)",classes:["icon-button","tooltip","chart_curve","trackster-add"],"data-url":a["data-url"],"action-url":a["action-url"],"new-url":a["new-url"]})))}if(this.model.get("retag_url")&&this.model.get("annotate_url")){var d=$('<div style="float: right;"></div>');d.append($(linkHTMLTemplate({title:"Edit dataset tags",target:"galaxy_main",href:this.model.get("retag_url"),classes:["icon-button","tooltip","tags"]})));d.append($(linkHTMLTemplate({title:"Edit dataset annotation",target:"galaxy_main",href:this.model.get("annotation_url"),classes:["icon-button","tooltip","annotate"]})));c.append(d);c.append('<div style="clear: both"></div>');this.tagArea=$('<div class="tag-area" style="display: none">');this.tagArea.append("<strong>Tags:</strong>");this.tagElt=$('<div class="tag-elt"></div>');c.append(this.tagArea.append(this.tagElt));var e=$(('<div id="${dataset_id}-annotation-area" class="annotation-area" style="display: none">'));this.annotationArea=e;e.append("<strong>Annotation:</strong>");this.annotationElem=$('<div id="'+this.model.get("id")+'-annotation-elt" style="margin: 1px 0px 1px 0px" class="annotation-elt tooltip editable-text" title="Edit dataset annotation"></div>');e.append(this.annotationElem);c.append(e)}}c.append('<div style="clear: both;"></div>');h.append(c);var i=$("<div/>");if(this.model.get("display_apps")){var j=this.model.get("display_apps"),b=$("<span/>");for(app_name in j){var g=j[app_name],f=app_name+" ";for(location_name in g){f+=linkHTMLTemplate({text:location_name,href:g[location_name].url,target:g[location_name].target})+" "}b.append(f)}i.append(b)}h.append(i)}else{if(this.model.get("for_editing")){h.append(this._render_showParamsAndRerun())}}h.append(this._render_peek())},_render_body:function(){var b=this.model.get("state"),c=this.model.get("for_editing");var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(b){case HistoryItem.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryItem.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryItem.STATES.QUEUED:this._render_body_queued(a);break;case HistoryItem.STATES.RUNNING:this._render_body_running(a);break;case HistoryItem.STATES.ERROR:this._render_body_error(a);break;case HistoryItem.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryItem.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryItem.STATES.EMPTY:this._render_body_empty(a);break;case HistoryItem.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryItem.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+b+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.model.get("bodyIsShown")===false){a.hide()}return a},_render_hdaSummary:function(){var a=this.model.toJSON();if(this.model.get("metadata_dbkey")==="?"&&this.model.isEditable()){_.extend(a,{dbkey_unknown_and_editable:true})}return HistoryItemView.templates.hdaSummary(a)},_render_showParamsAndRerun:function(){var a=$("<div/>");this.showParamsButton=new IconButtonView({model:new IconButton({title:"View details",href:this.model.get("show_params_url"),target:"galaxy_main",icon_class:"information"})});a.append(this.showParamsButton.render().$el);if(this.model.get("for_editing")){this.rerunButton=new IconButtonView({model:new IconButton({title:"Run this job again",href:this.model.get("rerun_url"),target:"galaxy_main",icon_class:"arrow-circle"})})}return a},_render_downloadLinks:function(){if(this.model.get("purged")){return null}var a=linkHTMLTemplate({title:"Download",href:this.model.get("download_url"),classes:["icon-button","tooltip","disk"]});var d=this.model.get("download_meta_urls");if(!d){return a}var c=$('<div popupmenu="dataset-'+this.model.get("id")+'-popup"></div>');c.append(linkHTMLTemplate({text:"Download Dataset",title:"Download",href:this.model.get("download_url"),classes:["icon-button","tooltip","disk"]}));c.append("<a>Additional Files</a>");for(file_type in d){c.append(linkHTMLTemplate({text:"Download "+file_type,href:d[file_type],classes:["action-button"]}))}var b=$(('<div style="float:left;" class="menubutton split popup" id="dataset-${dataset_id}-popup"></div>'));b.append(a);c.append(b);return c},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this,".loadAndDisplayTags",b);var c=this.tagArea;var a=this.tagElt;if(c.is(":hidden")){if(!a.html()){$.ajax({url:this.model.get("ajax_get_tag_url"),error:function(){alert("Tagging failed")},success:function(d){this.log("tag_elt_html:",d);a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this,".loadAndDisplayAnnotation",b);var d=this.annotationArea,c=this.annotationElem,a=this.model.get("ajax_set_annotation_url");this.log("annotationArea hidden:",d.is(":hidden"));this.log("annotationElem html:",c.html());if(d.is(":hidden")){if(!c.html()){$.ajax({url:this.model.get("ajax_get_annotation_url"),error:function(){alert("Annotations failed")},success:function(e){if(e===""){e="<em>Describe or add notes to dataset</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toggleBodyVisibility:function(){this.log(this+".toggleBodyVisibility");this.$el.find(".historyItemBody").toggle()},toString:function(){var a=(this.model)?(this.model+""):("");return"HistoryItemView("+a+")"}});HistoryItemView.templates=CompiledTemplateLoader.getTemplates({"history-templates.html":{messages:"template-history-warning-messages",titleLink:"template-history-titleLink",hdaSummary:"template-history-hdaSummary"}});var HistoryCollection=Backbone.Collection.extend({model:HistoryItem,toString:function(){return("HistoryCollection()")}});var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",state_details:{discarded:0,empty:0,error:0,failed_metadata:0,ok:0,queued:0,running:0,setting_metadata:0,upload:0}},initialize:function(b,a){this.log(this+".initialize",b,a);this.items=new HistoryCollection()},loadDatasetsAsHistoryItems:function(c){var a=this,b=this.get("id"),d=this.get("state_details");_.each(c,function(f,e){a.log("loading dataset: ",f,e);var h=new HistoryItem(_.extend(f,{history_id:b}));a.log("as History:",h);a.items.add(h);var g=f.state;d[g]+=1});this.set("state_details",d);this._stateFromStateDetails();return this},_stateFromStateDetails:function(){this.set("state","");var a=this.get("state_details");if((a.error>0)||(a.failed_metadata>0)){this.set("state",HistoryItem.STATES.ERROR)}else{if((a.running>0)||(a.setting_metadata>0)){this.set("state",HistoryItem.STATES.RUNNING)}else{if(a.queued>0){this.set("state",HistoryItem.STATES.QUEUED)}else{if(a.ok===this.items.length){this.set("state",HistoryItem.STATES.OK)}else{throw ("_stateFromStateDetails: unable to determine history state from state details: "+this.state_details)}}}}return this},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryView=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",initialize:function(){this.log(this+".initialize");this.itemViews=[];var a=this;this.model.items.each(function(c){var b=new HistoryItemView({model:c});a.itemViews.push(b)})},render:function(){this.log(this+".render");var a=$("<div/>");_.each(this.itemViews,function(b){a.prepend(b.render())});this.$el.append(a.children());a.remove()},toString:function(){var a=this.model.get("name")||"";return"HistoryView("+a+")"}});function createMockHistoryData(){mockHistory={};mockHistory.data={template:{id:"a799d38679e985db",name:"template",data_type:"fastq",file_size:226297533,genome_build:"?",metadata_data_lines:0,metadata_dbkey:"?",metadata_sequences:0,misc_blurb:"215.8 MB",misc_info:"uploaded fastq file",model_class:"HistoryDatasetAssociation",download_url:"",state:"ok",visible:true,deleted:false,purged:false,hid:0,for_editing:true,undelete_url:"example.com/undelete",purge_url:"example.com/purge",unhide_url:"example.com/unhide",display_url:"example.com/display",edit_url:"example.com/edit",delete_url:"example.com/delete",show_params_url:"example.com/show_params",rerun_url:"example.com/rerun",retag_url:"example.com/retag",annotate_url:"example.com/annotate",peek:['<table cellspacing="0" cellpadding="3"><tr><th>1.QNAME</th><th>2.FLAG</th><th>3.RNAME</th><th>4.POS</th><th>5.MAPQ</th><th>6.CIGAR</th><th>7.MRNM</th><th>8.MPOS</th><th>9.ISIZE</th><th>10.SEQ</th><th>11.QUAL</th><th>12.OPT</th></tr>','<tr><td colspan="100%">@SQ SN:gi|87159884|ref|NC_007793.1| LN:2872769</td></tr>','<tr><td colspan="100%">@PG ID:bwa PN:bwa VN:0.5.9-r16</td></tr>','<tr><td colspan="100%">HWUSI-EAS664L:15:64HOJAAXX:1:1:13280:968 73 gi|87159884|ref|NC_007793.1| 2720169 37 101M = 2720169 0 NAATATGACATTATTTTCAAAACAGCTGAAAATTTAGACGTACCGATTTATCTACATCCCGCGCCAGTTAACAGTGACATTTATCAATCATACTATAAAGG !!!!!!!!!!$!!!$!!!!!$!!!!!!$!$!$$$!!$!!$!!!!!!!!!!!$!</td></tr>','<tr><td colspan="100%">!!!$!$!$$!!$$!!$!!!!!!!!!!!!!!!!!!!!!!!!!!$!!$!! XT:A:U NM:i:1 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:0 XG:i:0 MD:Z:0A100</td></tr>','<tr><td colspan="100%">HWUSI-EAS664L:15:64HOJAAXX:1:1:13280:968 133 gi|87159884|ref|NC_007793.1| 2720169 0 * = 2720169 0 NAAACTGTGGCTTCGTTNNNNNNNNNNNNNNNGTGANNNNNNNNNNNNNNNNNNNGNNNNNNNNNNNNNNNNNNNNCNAANNNNNNNNNNNNNNNNNNNNN !!!!!!!!!!!!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</td></tr>','<tr><td colspan="100%">!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</td></tr>',"</table>"].join("")}};_.extend(mockHistory.data,{deleted:_.extend(_.clone(mockHistory.data.template),{deleted:true}),purgedNotDeleted:_.extend(_.clone(mockHistory.data.template),{purged:true}),notvisible:_.extend(_.clone(mockHistory.data.template),{visible:false}),hasDisplayApps:_.extend(_.clone(mockHistory.data.template),{display_apps:{"display in IGB":{Web:"/display_application/63cd3858d057a6d1/igb_bam/Web",Local:"/display_application/63cd3858d057a6d1/igb_bam/Local"}}}),canTrackster:_.extend(_.clone(mockHistory.data.template),{trackster_urls:{"data-url":"example.com/trackster-data","action-url":"example.com/trackster-action","new-url":"example.com/trackster-new"}}),zeroSize:_.extend(_.clone(mockHistory.data.template),{file_size:0}),hasMetafiles:_.extend(_.clone(mockHistory.data.template),{download_meta_urls:{bam_index:"example.com/bam-index"}}),upload:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.UPLOAD}),queued:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.QUEUED}),running:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.RUNNING}),empty:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.EMPTY}),error:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.ERROR,report_error_url:"example.com/report_err"}),discarded:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.DISCARDED}),setting_metadata:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.SETTING_METADATA}),failed_metadata:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.FAILED_METADATA})});$(document).ready(function(){mockHistory.items={};mockHistory.views={};for(key in mockHistory.data){mockHistory.items[key]=new HistoryItem(mockHistory.data[key]);mockHistory.items[key].set("name",key);mockHistory.views[key]=new HistoryItemView({model:mockHistory.items[key]});$("body").append(mockHistory.views[key].render())}})};
\ No newline at end of file
+function linkHTMLTemplate(b,a){if(!b){return"<a></a>"}a=a||"a";var c=["<"+a];for(key in b){var d=b[key];if(d===""){continue}switch(key){case"text":continue;case"classes":key="class";d=(b.classes.join)?(b.classes.join(" ")):(b.classes);default:c.push([" ",key,'="',d,'"'].join(""))}}c.push(">");if("text" in b){c.push(b.text)}c.push("</"+a+">");return c.join("")}var HistoryItem=BaseModel.extend(LoggableMixin).extend({defaults:{id:null,name:"",data_type:null,file_size:0,genome_build:null,metadata_data_lines:0,metadata_dbkey:null,metadata_sequences:0,misc_blurb:"",misc_info:"",model_class:"",state:"",deleted:false,purged:false,visible:true,for_editing:true,bodyIsShown:false},initialize:function(){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"));if(!this.get("accessible")){this.set("state",HistoryItem.STATES.NOT_VIEWABLE)}},isEditable:function(){return(!(this.get("deleted")||this.get("purged")))},hasData:function(){return(this.get("file_size")>0)},toString:function(){var a=this.get("id")||"";if(this.get("name")){a+=':"'+this.get("name")+'"'}return"HistoryItem("+a+")"}});HistoryItem.STATES={NOT_VIEWABLE:"not_viewable",NEW:"new",UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",OK:"ok",EMPTY:"empty",ERROR:"error",DISCARDED:"discarded",SETTING_METADATA:"setting_metadata",FAILED_METADATA:"failed_metadata"};var HistoryItemView=BaseView.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(){this.log(this+".initialize:",this,this.model)},render:function(){var d=this.model.get("id"),c=this.model.get("state");this.clearReferences();this.$el.attr("id","historyItemContainer-"+d);var a=$("<div/>").attr("id","historyItem-"+d).addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);a.find(".tooltip").tooltip({placement:"bottom"});var b=a.find("[popupmenu]");b.each(function(e,f){f=$(f);make_popupmenu(f)});this.$el.children().remove();return this.$el.append(a)},clearReferences:function(){this.displayButton=null;this.editButton=null;this.deleteButton=null;this.errButton=null},_render_warnings:function(){return $(jQuery.trim(HistoryItemView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_displayButton:function(){if(this.model.get("state")===HistoryItem.STATES.UPLOAD){return null}displayBtnData=(this.model.get("purged"))?({title:"Cannot display datasets removed from disk",enabled:false,icon_class:"display"}):({title:"Display data in browser",href:this.model.get("display_url"),target:(this.model.get("for_editing"))?("galaxy_main"):(null),icon_class:"display"});this.displayButton=new IconButtonView({model:new IconButton(displayBtnData)});return this.displayButton.render().$el},_render_editButton:function(){if((this.model.get("state")===HistoryItem.STATES.UPLOAD)||(!this.model.get("for_editing"))){return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:"Edit attributes",href:this.model.get("edit_url"),target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false}if(a){b.title="Undelete dataset to edit attributes"}else{if(c){b.title="Cannot edit attributes of datasets removed from disk"}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if(!this.model.get("for_editing")){return null}var a={title:"Delete",href:this.model.get("delete_url"),target:"galaxy_main",id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"};if((this.model.get("deleted")||this.model.get("purged"))&&(!this.model.get("delete_url"))){a={title:"Dataset is already deleted",icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HistoryItemView.templates.titleLink(this.model.toJSON())))},_render_hdaSummary:function(){var a=this.model.toJSON();if(this.model.get("metadata_dbkey")==="?"&&this.model.isEditable()){_.extend(a,{dbkey_unknown_and_editable:true})}return HistoryItemView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var b=$("<div/>"),a=this;_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")){return null}var a=linkHTMLTemplate({title:"Download",href:this.model.get("download_url"),classes:["icon-button","tooltip","disk"]});var d=this.model.get("download_meta_urls");if(!d){return a}var c=$('<div popupmenu="dataset-'+this.model.get("id")+'-popup"></div>');c.append(linkHTMLTemplate({text:"Download Dataset",title:"Download",href:this.model.get("download_url"),classes:["icon-button","tooltip","disk"]}));c.append("<a>Additional Files</a>");for(file_type in d){c.append(linkHTMLTemplate({text:"Download "+file_type,href:d[file_type],classes:["action-button"]}))}var b=$(('<div style="float:left;" class="menubutton split popup" id="dataset-${dataset_id}-popup"></div>'));b.append(a);c.append(b);return c},_render_errButton:function(){if((this.model.get("state")!==HistoryItem.STATES.ERROR)||(!this.model.get("for_editing"))){return null}this.errButton=new IconButtonView({model:new IconButton({title:"View or report this error",href:this.model.get("report_error_url"),target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:"View details",href:this.model.get("show_params_url"),target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_rerunButton:function(){if(!this.model.get("for_editing")){return null}this.rerunButton=new IconButtonView({model:new IconButton({title:"Run this job again",href:this.model.get("rerun_url"),target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_tracksterButton:function(){var a=this.model.get("trackster_urls");if(!(this.model.hasData())||!(this.model.get("for_editing"))||!(a)){return null}this.tracksterButton=new IconButtonView({model:new IconButton({title:"View in Trackster",icon_class:"chart_curve"})});this.errButton.render();this.errButton.$el.addClass("trackster-add").attr({"data-url":a["data-url"],"action-url":a["action-url"],"new-url":a["new-url"]});return this.errButton.$el},_render_secondaryActionButtons:function(b){var c=$('<div style="float: right;"></div>'),a=this;_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||!(this.model.get("for_editing"))||(!this.model.get("retag_url"))){return null}this.tagButton=new IconButtonView({model:new IconButton({title:"Edit dataset tags",target:"galaxy_main",href:this.model.get("retag_url"),icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||!(this.model.get("for_editing"))||(!this.model.get("annotate_url"))){return null}this.annotateButton=new IconButtonView({model:new IconButton({title:"Edit dataset annotation",target:"galaxy_main",href:this.model.get("annotate_url"),icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(this.model.get("retag_url")){return null}return $(HistoryItemView.templates.tagArea(this.model.toJSON()))},_render_annotationArea:function(){if(!this.model.get("annotate_url")){return null}return $(HistoryItemView.templates.annotationArea(this.model.toJSON()))},_render_displayApps:function(){if(!this.model.get("display_apps")){return null}var a=this.model.get("displayApps"),c=$("<div/>"),b=$("<span/>");this.log(this+"displayApps:",a);return c},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},_render_body_not_viewable:function(a){a.append($("<div>You do not have permission to view dataset.</div>"))},_render_body_uploading:function(a){a.append($("<div>Dataset is uploading</div>"))},_render_body_queued:function(a){a.append($("<div>Job is waiting to run.</div>"));a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_running:function(a){a.append("<div>Job is currently running.</div>");a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append(("An error occurred running this job: <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_errButton,this._render_showParamsButton,this._render_rerunButton]))},_render_body_discarded:function(a){a.append("<div>The job creating this dataset was cancelled before completion.</div>");a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_setting_metadata:function(a){a.append($("<div>Metadata is being auto-detected.</div>"))},_render_body_empty:function(a){a.append($("<div>No data: <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons([this._render_showParamsButton,this._render_rerunButton]))},_render_body_failed_metadata:function(a){a.append($(HistoryItemView.templates.failedMetadata(this.model.toJSON())));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_errButton,this._render_showParamsButton,this._render_rerunButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayApps());a.append(this._render_peek())},_render_body:function(){var b=this.model.get("state");var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(b){case HistoryItem.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryItem.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryItem.STATES.QUEUED:this._render_body_queued(a);break;case HistoryItem.STATES.RUNNING:this._render_body_running(a);break;case HistoryItem.STATES.ERROR:this._render_body_error(a);break;case HistoryItem.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryItem.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryItem.STATES.EMPTY:this._render_body_empty(a);break;case HistoryItem.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryItem.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+b+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.model.get("bodyIsShown")===false){a.hide()}return a},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this+".loadAndDisplayTags",b);var c=this.$el.find(".tag-area"),a=c.find(".tag-elt");if(c.is(":hidden")){if(!a.html()){$.ajax({url:this.model.get("ajax_get_tag_url"),error:function(){alert("Tagging failed")},success:function(d){a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.model.get("ajax_set_annotation_url");if(d.is(":hidden")){if(!c.html()){$.ajax({url:this.model.get("ajax_get_annotation_url"),error:function(){alert("Annotations failed")},success:function(e){if(e===""){e="<em>Describe or add notes to dataset</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toggleBodyVisibility:function(){this.log(this+".toggleBodyVisibility");this.$el.find(".historyItemBody").toggle()},toString:function(){var a=(this.model)?(this.model+""):("");return"HistoryItemView("+a+")"}});HistoryItemView.templates=CompiledTemplateLoader.getTemplates({"common-templates.html":{warningMsg:"template-warningmessagesmall"},"history-templates.html":{messages:"template-history-warning-messages",titleLink:"template-history-titleLink",hdaSummary:"template-history-hdaSummary",failedMetadata:"template-history-failedMetaData",tagArea:"template-history-tagArea",annotationArea:"template-history-annotationArea"}});var HistoryCollection=Backbone.Collection.extend({model:HistoryItem,toString:function(){return("HistoryCollection()")}});var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",state_details:{discarded:0,empty:0,error:0,failed_metadata:0,ok:0,queued:0,running:0,setting_metadata:0,upload:0}},initialize:function(b,a){this.log(this+".initialize",b,a);this.items=new HistoryCollection()},loadDatasetsAsHistoryItems:function(c){var a=this,b=this.get("id"),d=this.get("state_details");_.each(c,function(f,e){a.log("loading dataset: ",f,e);var h=new HistoryItem(_.extend(f,{history_id:b}));a.log("as History:",h);a.items.add(h);var g=f.state;d[g]+=1});this.set("state_details",d);this._stateFromStateDetails();return this},_stateFromStateDetails:function(){this.set("state","");var a=this.get("state_details");if((a.error>0)||(a.failed_metadata>0)){this.set("state",HistoryItem.STATES.ERROR)}else{if((a.running>0)||(a.setting_metadata>0)){this.set("state",HistoryItem.STATES.RUNNING)}else{if(a.queued>0){this.set("state",HistoryItem.STATES.QUEUED)}else{if(a.ok===this.items.length){this.set("state",HistoryItem.STATES.OK)}else{throw ("_stateFromStateDetails: unable to determine history state from state details: "+this.state_details)}}}}return this},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryView=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",initialize:function(){this.log(this+".initialize");this.itemViews=[];var a=this;this.model.items.each(function(c){var b=new HistoryItemView({model:c});a.itemViews.push(b)})},render:function(){this.log(this+".render");var a=$("<div/>");_.each(this.itemViews,function(b){a.prepend(b.render())});this.$el.append(a.children());a.remove()},toString:function(){var a=this.model.get("name")||"";return"HistoryView("+a+")"}});function createMockHistoryData(){mockHistory={};mockHistory.data={template:{id:"a799d38679e985db",name:"template",data_type:"fastq",file_size:226297533,genome_build:"?",metadata_data_lines:0,metadata_dbkey:"?",metadata_sequences:0,misc_blurb:"215.8 MB",misc_info:"uploaded fastq file (misc_info)",model_class:"HistoryDatasetAssociation",download_url:"",state:"ok",visible:true,deleted:false,purged:false,hid:0,for_editing:true,accessible:true,undelete_url:"",purge_url:"",unhide_url:"",display_url:"example.com/display",edit_url:"example.com/edit",delete_url:"example.com/delete",show_params_url:"example.com/show_params",rerun_url:"example.com/rerun",retag_url:"example.com/retag",annotate_url:"example.com/annotate",peek:['<table cellspacing="0" cellpadding="3"><tr><th>1.QNAME</th><th>2.FLAG</th><th>3.RNAME</th><th>4.POS</th><th>5.MAPQ</th><th>6.CIGAR</th><th>7.MRNM</th><th>8.MPOS</th><th>9.ISIZE</th><th>10.SEQ</th><th>11.QUAL</th><th>12.OPT</th></tr>','<tr><td colspan="100%">@SQ SN:gi|87159884|ref|NC_007793.1| LN:2872769</td></tr>','<tr><td colspan="100%">@PG ID:bwa PN:bwa VN:0.5.9-r16</td></tr>','<tr><td colspan="100%">HWUSI-EAS664L:15:64HOJAAXX:1:1:13280:968 73 gi|87159884|ref|NC_007793.1| 2720169 37 101M = 2720169 0 NAATATGACATTATTTTCAAAACAGCTGAAAATTTAGACGTACCGATTTATCTACATCCCGCGCCAGTTAACAGTGACATTTATCAATCATACTATAAAGG !!!!!!!!!!$!!!$!!!!!$!!!!!!$!$!$$$!!$!!$!!!!!!!!!!!$!</td></tr>','<tr><td colspan="100%">!!!$!$!$$!!$$!!$!!!!!!!!!!!!!!!!!!!!!!!!!!$!!$!! XT:A:U NM:i:1 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:0 XG:i:0 MD:Z:0A100</td></tr>','<tr><td colspan="100%">HWUSI-EAS664L:15:64HOJAAXX:1:1:13280:968 133 gi|87159884|ref|NC_007793.1| 2720169 0 * = 2720169 0 NAAACTGTGGCTTCGTTNNNNNNNNNNNNNNNGTGANNNNNNNNNNNNNNNNNNNGNNNNNNNNNNNNNNNNNNNNCNAANNNNNNNNNNNNNNNNNNNNN !!!!!!!!!!!!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</td></tr>','<tr><td colspan="100%">!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</td></tr>',"</table>"].join("")}};_.extend(mockHistory.data,{notAccessible:_.extend(_.clone(mockHistory.data.template),{accessible:false}),deleted:_.extend(_.clone(mockHistory.data.template),{deleted:true,delete_url:"",purge_url:"example.com/purge",undelete_url:"example.com/undelete"}),purgedNotDeleted:_.extend(_.clone(mockHistory.data.template),{purged:true,delete_url:""}),notvisible:_.extend(_.clone(mockHistory.data.template),{visible:false,unhide_url:"example.com/unhide"}),hasDisplayApps:_.extend(_.clone(mockHistory.data.template),{display_apps:{"display in IGB":{Web:"/display_application/63cd3858d057a6d1/igb_bam/Web",Local:"/display_application/63cd3858d057a6d1/igb_bam/Local"}}}),canTrackster:_.extend(_.clone(mockHistory.data.template),{trackster_urls:{"data-url":"example.com/trackster-data","action-url":"example.com/trackster-action","new-url":"example.com/trackster-new"}}),zeroSize:_.extend(_.clone(mockHistory.data.template),{file_size:0}),hasMetafiles:_.extend(_.clone(mockHistory.data.template),{download_meta_urls:{bam_index:"example.com/bam-index"}}),upload:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.UPLOAD}),queued:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.QUEUED}),running:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.RUNNING}),empty:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.EMPTY}),error:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.ERROR,report_error_url:"example.com/report_err"}),discarded:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.DISCARDED}),setting_metadata:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.SETTING_METADATA}),failed_metadata:_.extend(_.clone(mockHistory.data.template),{state:HistoryItem.STATES.FAILED_METADATA})});$(document).ready(function(){mockHistory.items={};mockHistory.views={};for(key in mockHistory.data){mockHistory.items[key]=new HistoryItem(mockHistory.data[key]);mockHistory.items[key].set("name",key);mockHistory.views[key]=new HistoryItemView({model:mockHistory.items[key]});$("body").append(mockHistory.views[key].render())}})};
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 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,tooltip_config:{},isMenuButton:true,id:null,href:null,target:null,enabled:true,visible:true}});var IconButtonView=Backbone.View.extend({tagName:"a",className:"icon-button",hrefVoidFn:["javascript",":void(0)"].join(""),fadeSpeed:0,initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){var a=this.model.attributes.icon_class+"_disabled";if(!this.model.attributes.visible){this.$el.fadeOut(this.fadeSpeed)}if(this.model.attributes.enabled){if(this.$el.hasClass(a)){this.$el.removeClass(a)}this.$el.addClass(this.model.attributes.icon_class)}else{this.$el.removeClass(this.model.attributes.icon_class);this.$el.addClass(a)}if(this.model.attributes.isMenuButton){this.$el.addClass("menu-button")}else{this.$el.removeClass("menu-button")}this.$el.data("tooltip",false);this.$el.attr("data-original-title",null);this.$el.removeClass("tooltip");if(this.model.attributes.title){this.$el.attr("title",this.model.attributes.title).addClass("tooltip");this.$el.tooltip(this.model.attributes.tooltip_config)}this.$el.attr("id",(this.model.attributes.id)?(this.model.attributes.id):(null));this.$el.attr("target",(this.model.attributes.target)?(this.model.attributes.target):(null));this.$el.attr("href",(this.model.attributes.href&&!this.model.attributes.on_click)?(this.model.attributes.href):(this.hrefVoidFn));if(this.model.attributes.visible){this.$el.fadeIn(this.fadeSpeed)}return this},events:{click:"click"},click:function(a){if(this.model.attributes.on_click){this.model.attributes.on_click(a);return false}return true}});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(c){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",c.attributes.title).addClass("icon-button menu-button").addClass(c.attributes.icon_class).appendTo(a.$el).click(c.attributes.on_click);if(c.attributes.tooltip_config){b.tooltip(c.attributes.tooltip_config)}});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 GalaxyLocalization=jQuery.extend({},{aliasName:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(b){try{return this.localizedStrings[b]}catch(a){return b}},toString:function(){return"GalaxyLocalization"}});window[GalaxyLocalization.aliasName]=function(a){return GalaxyLocalization.localize(a)};
\ No newline at end of file
+var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,tooltip_config:{},isMenuButton:true,id:null,href:null,target:null,enabled:true,visible:true}});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=$(Handlebars.partials.iconButton(this.model.toJSON()));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}});IconButtonView.templates={iconButton:Handlebars.partials.iconButton};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(c){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",c.attributes.title).addClass("icon-button menu-button").addClass(c.attributes.icon_class).appendTo(a.$el).click(c.attributes.on_click);if(c.attributes.tooltip_config){b.tooltip(c.attributes.tooltip_config)}});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 GalaxyLocalization=jQuery.extend({},{aliasName:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(b){try{return this.localizedStrings[b]}catch(a){return b}},toString:function(){return"GalaxyLocalization"}});window[GalaxyLocalization.aliasName]=function(a){return GalaxyLocalization.localize(a)};
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/require.js
--- a/static/scripts/packed/require.js
+++ /dev/null
@@ -1,1 +0,0 @@
-var requirejs,require,define;(function(global){var req,s,head,baseElement,dataMain,src,interactiveScript,currentlyAddingScript,mainScript,subPath,version="2.0.6",commentRegExp=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,cjsRequireRegExp=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,jsSuffixRegExp=/\.js$/,currDirRegExp=/^\.\//,op=Object.prototype,ostring=op.toString,hasOwn=op.hasOwnProperty,ap=Array.prototype,aps=ap.slice,apsp=ap.splice,isBrowser=!!(typeof window!=="undefined"&&navigator&&document),isWebWorker=!isBrowser&&typeof importScripts!=="undefined",readyRegExp=isBrowser&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaded)$/,defContextName="_",isOpera=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",contexts={},cfg={},globalDefQueue=[],useInteractive=false;function isFunction(it){return ostring.call(it)==="[object Function]"}function isArray(it){return ostring.call(it)==="[object Array]"}function each(ary,func){if(ary){var i;for(i=0;i<ary.length;i+=1){if(ary[i]&&func(ary[i],i,ary)){break}}}}function eachReverse(ary,func){if(ary){var i;for(i=ary.length-1;i>-1;i-=1){if(ary[i]&&func(ary[i],i,ary)){break}}}}function hasProp(obj,prop){return hasOwn.call(obj,prop)}function eachProp(obj,func){var prop;for(prop in obj){if(obj.hasOwnProperty(prop)){if(func(obj[prop],prop)){break}}}}function mixin(target,source,force,deepStringMixin){if(source){eachProp(source,function(value,prop){if(force||!hasProp(target,prop)){if(deepStringMixin&&typeof value!=="string"){if(!target[prop]){target[prop]={}}mixin(target[prop],value,force,deepStringMixin)}else{target[prop]=value}}})}return target}function bind(obj,fn){return function(){return fn.apply(obj,arguments)}}function scripts(){return document.getElementsByTagName("script")}function getGlobal(value){if(!value){return value}var g=global;each(value.split("."),function(part){g=g[part]});return g}function makeContextModuleFunc(func,relMap,enableBuildCallback){return function(){var args=aps.call(arguments,0),lastArg;if(enableBuildCallback&&isFunction((lastArg=args[args.length-1]))){lastArg.__requireJsBuild=true}args.push(relMap);return func.apply(null,args)}}function addRequireMethods(req,context,relMap){each([["toUrl"],["undef"],["defined","requireDefined"],["specified","requireSpecified"]],function(item){var prop=item[1]||item[0];req[item[0]]=context?makeContextModuleFunc(context[prop],relMap):function(){var ctx=contexts[defContextName];return ctx[prop].apply(ctx,arguments)}})}function makeError(id,msg,err,requireModules){var e=new Error(msg+"\nhttp://requirejs.org/docs/errors.html#"+id);e.requireType=id;e.requireModules=requireModules;if(err){e.originalError=err}return e}if(typeof define!=="undefined"){return}if(typeof requirejs!=="undefined"){if(isFunction(requirejs)){return}cfg=requirejs;requirejs=undefined}if(typeof require!=="undefined"&&!isFunction(require)){cfg=require;require=undefined}function newContext(contextName){var inCheckLoaded,Module,context,handlers,checkLoadedTimeoutId,config={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},shim:{}},registry={},undefEvents={},defQueue=[],defined={},urlFetched={},requireCounter=1,unnormalizedCounter=1,waitAry=[];function trimDots(ary){var i,part;for(i=0;ary[i];i+=1){part=ary[i];if(part==="."){ary.splice(i,1);i-=1}else{if(part===".."){if(i===1&&(ary[2]===".."||ary[0]==="..")){break}else{if(i>0){ary.splice(i-1,2);i-=2}}}}}}function normalize(name,baseName,applyMap){var pkgName,pkgConfig,mapValue,nameParts,i,j,nameSegment,foundMap,foundI,foundStarMap,starI,baseParts=baseName&&baseName.split("/"),normalizedBaseParts=baseParts,map=config.map,starMap=map&&map["*"];if(name&&name.charAt(0)==="."){if(baseName){if(config.pkgs[baseName]){normalizedBaseParts=baseParts=[baseName]}else{normalizedBaseParts=baseParts.slice(0,baseParts.length-1)}name=normalizedBaseParts.concat(name.split("/"));trimDots(name);pkgConfig=config.pkgs[(pkgName=name[0])];name=name.join("/");if(pkgConfig&&name===pkgName+"/"+pkgConfig.main){name=pkgName}}else{if(name.indexOf("./")===0){name=name.substring(2)}}}if(applyMap&&(baseParts||starMap)&&map){nameParts=name.split("/");for(i=nameParts.length;i>0;i-=1){nameSegment=nameParts.slice(0,i).join("/");if(baseParts){for(j=baseParts.length;j>0;j-=1){mapValue=map[baseParts.slice(0,j).join("/")];if(mapValue){mapValue=mapValue[nameSegment];if(mapValue){foundMap=mapValue;foundI=i;break}}}}if(foundMap){break}if(!foundStarMap&&starMap&&starMap[nameSegment]){foundStarMap=starMap[nameSegment];starI=i}}if(!foundMap&&foundStarMap){foundMap=foundStarMap;foundI=starI}if(foundMap){nameParts.splice(0,foundI,foundMap);name=nameParts.join("/")}}return name}function removeScript(name){if(isBrowser){each(scripts(),function(scriptNode){if(scriptNode.getAttribute("data-requiremodule")===name&&scriptNode.getAttribute("data-requirecontext")===context.contextName){scriptNode.parentNode.removeChild(scriptNode);return true}})}}function hasPathFallback(id){var pathConfig=config.paths[id];if(pathConfig&&isArray(pathConfig)&&pathConfig.length>1){removeScript(id);pathConfig.shift();context.undef(id);context.require([id]);return true}}function makeModuleMap(name,parentModuleMap,isNormalized,applyMap){var url,pluginModule,suffix,index=name?name.indexOf("!"):-1,prefix=null,parentName=parentModuleMap?parentModuleMap.name:null,originalName=name,isDefine=true,normalizedName="";if(!name){isDefine=false;name="_@r"+(requireCounter+=1)}if(index!==-1){prefix=name.substring(0,index);name=name.substring(index+1,name.length)}if(prefix){prefix=normalize(prefix,parentName,applyMap);pluginModule=defined[prefix]}if(name){if(prefix){if(pluginModule&&pluginModule.normalize){normalizedName=pluginModule.normalize(name,function(name){return normalize(name,parentName,applyMap)})}else{normalizedName=normalize(name,parentName,applyMap)}}else{normalizedName=normalize(name,parentName,applyMap);url=context.nameToUrl(normalizedName)}}suffix=prefix&&!pluginModule&&!isNormalized?"_unnormalized"+(unnormalizedCounter+=1):"";return{prefix:prefix,name:normalizedName,parentMap:parentModuleMap,unnormalized:!!suffix,url:url,originalName:originalName,isDefine:isDefine,id:(prefix?prefix+"!"+normalizedName:normalizedName)+suffix}}function getModule(depMap){var id=depMap.id,mod=registry[id];if(!mod){mod=registry[id]=new context.Module(depMap)}return mod}function on(depMap,name,fn){var id=depMap.id,mod=registry[id];if(hasProp(defined,id)&&(!mod||mod.defineEmitComplete)){if(name==="defined"){fn(defined[id])}}else{getModule(depMap).on(name,fn)}}function onError(err,errback){var ids=err.requireModules,notified=false;if(errback){errback(err)}else{each(ids,function(id){var mod=registry[id];if(mod){mod.error=err;if(mod.events.error){notified=true;mod.emit("error",err)}}});if(!notified){req.onError(err)}}}function takeGlobalQueue(){if(globalDefQueue.length){apsp.apply(defQueue,[defQueue.length-1,0].concat(globalDefQueue));globalDefQueue=[]}}function makeRequire(mod,enableBuildCallback,altRequire){var relMap=mod&&mod.map,modRequire=makeContextModuleFunc(altRequire||context.require,relMap,enableBuildCallback);addRequireMethods(modRequire,context,relMap);modRequire.isBrowser=isBrowser;return modRequire}handlers={require:function(mod){return makeRequire(mod)},exports:function(mod){mod.usingExports=true;if(mod.map.isDefine){return(mod.exports=defined[mod.map.id]={})}},module:function(mod){return(mod.module={id:mod.map.id,uri:mod.map.url,config:function(){return(config.config&&config.config[mod.map.id])||{}},exports:defined[mod.map.id]})}};function removeWaiting(id){delete registry[id];each(waitAry,function(mod,i){if(mod.map.id===id){waitAry.splice(i,1);if(!mod.defined){context.waitCount-=1}return true}})}function findCycle(mod,traced,processed){var id=mod.map.id,depArray=mod.depMaps,foundModule;if(!mod.inited){return}if(traced[id]){return mod}traced[id]=true;each(depArray,function(depMap){var depId=depMap.id,depMod=registry[depId];if(!depMod||processed[depId]||!depMod.inited||!depMod.enabled){return}return(foundModule=findCycle(depMod,traced,processed))});processed[id]=true;return foundModule}function forceExec(mod,traced,uninited){var id=mod.map.id,depArray=mod.depMaps;if(!mod.inited||!mod.map.isDefine){return}if(traced[id]){return defined[id]}traced[id]=mod;each(depArray,function(depMap){var depId=depMap.id,depMod=registry[depId],value;if(handlers[depId]){return}if(depMod){if(!depMod.inited||!depMod.enabled){uninited[id]=true;return}value=forceExec(depMod,traced,uninited);if(!uninited[depId]){mod.defineDepById(depId,value)}}});mod.check(true);return defined[id]}function modCheck(mod){mod.check()}function checkLoaded(){var map,modId,err,usingPathFallback,waitInterval=config.waitSeconds*1000,expired=waitInterval&&(context.startTime+waitInterval)<new Date().getTime(),noLoads=[],stillLoading=false,needCycleCheck=true;if(inCheckLoaded){return}inCheckLoaded=true;eachProp(registry,function(mod){map=mod.map;modId=map.id;if(!mod.enabled){return}if(!mod.error){if(!mod.inited&&expired){if(hasPathFallback(modId)){usingPathFallback=true;stillLoading=true}else{noLoads.push(modId);removeScript(modId)}}else{if(!mod.inited&&mod.fetched&&map.isDefine){stillLoading=true;if(!map.prefix){return(needCycleCheck=false)}}}}});if(expired&&noLoads.length){err=makeError("timeout","Load timeout for modules: "+noLoads,null,noLoads);err.contextName=context.contextName;return onError(err)}if(needCycleCheck){each(waitAry,function(mod){if(mod.defined){return}var cycleMod=findCycle(mod,{},{}),traced={};if(cycleMod){forceExec(cycleMod,traced,{});eachProp(traced,modCheck)}});eachProp(registry,modCheck)}if((!expired||usingPathFallback)&&stillLoading){if((isBrowser||isWebWorker)&&!checkLoadedTimeoutId){checkLoadedTimeoutId=setTimeout(function(){checkLoadedTimeoutId=0;checkLoaded()},50)}}inCheckLoaded=false}Module=function(map){this.events=undefEvents[map.id]||{};this.map=map;this.shim=config.shim[map.id];this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};Module.prototype={init:function(depMaps,factory,errback,options){options=options||{};if(this.inited){return}this.factory=factory;if(errback){this.on("error",errback)}else{if(this.events.error){errback=bind(this,function(err){this.emit("error",err)})}}this.depMaps=depMaps&&depMaps.slice(0);this.depMaps.rjsSkipMap=depMaps.rjsSkipMap;this.errback=errback;this.inited=true;this.ignore=options.ignore;if(options.enabled||this.enabled){this.enable()}else{this.check()}},defineDepById:function(id,depExports){var i;each(this.depMaps,function(map,index){if(map.id===id){i=index;return true}});return this.defineDep(i,depExports)},defineDep:function(i,depExports){if(!this.depMatched[i]){this.depMatched[i]=true;this.depCount-=1;this.depExports[i]=depExports}},fetch:function(){if(this.fetched){return}this.fetched=true;context.startTime=(new Date()).getTime();var map=this.map;if(this.shim){makeRequire(this,true)(this.shim.deps||[],bind(this,function(){return map.prefix?this.callPlugin():this.load()}))}else{return map.prefix?this.callPlugin():this.load()}},load:function(){var url=this.map.url;if(!urlFetched[url]){urlFetched[url]=true;context.load(this.map.id,url)}},check:function(silent){if(!this.enabled||this.enabling){return}var err,cjsModule,id=this.map.id,depExports=this.depExports,exports=this.exports,factory=this.factory;if(!this.inited){this.fetch()}else{if(this.error){this.emit("error",this.error)}else{if(!this.defining){this.defining=true;if(this.depCount<1&&!this.defined){if(isFunction(factory)){if(this.events.error){try{exports=context.execCb(id,factory,depExports,exports)}catch(e){err=e}}else{exports=context.execCb(id,factory,depExports,exports)}if(this.map.isDefine){cjsModule=this.module;if(cjsModule&&cjsModule.exports!==undefined&&cjsModule.exports!==this.exports){exports=cjsModule.exports}else{if(exports===undefined&&this.usingExports){exports=this.exports}}}if(err){err.requireMap=this.map;err.requireModules=[this.map.id];err.requireType="define";return onError((this.error=err))}}else{exports=factory}this.exports=exports;if(this.map.isDefine&&!this.ignore){defined[id]=exports;if(req.onResourceLoad){req.onResourceLoad(context,this.map,this.depMaps)}}delete registry[id];this.defined=true;context.waitCount-=1;if(context.waitCount===0){waitAry=[]}}this.defining=false;if(!silent){if(this.defined&&!this.defineEmitted){this.defineEmitted=true;this.emit("defined",this.exports);this.defineEmitComplete=true}}}}}},callPlugin:function(){var map=this.map,id=map.id,pluginMap=makeModuleMap(map.prefix,null,false,true);on(pluginMap,"defined",bind(this,function(plugin){var load,normalizedMap,normalizedMod,name=this.map.name,parentName=this.map.parentMap?this.map.parentMap.name:null;if(this.map.unnormalized){if(plugin.normalize){name=plugin.normalize(name,function(name){return normalize(name,parentName,true)})||""}normalizedMap=makeModuleMap(map.prefix+"!"+name,this.map.parentMap,false,true);on(normalizedMap,"defined",bind(this,function(value){this.init([],function(){return value},null,{enabled:true,ignore:true})}));normalizedMod=registry[normalizedMap.id];if(normalizedMod){if(this.events.error){normalizedMod.on("error",bind(this,function(err){this.emit("error",err)}))}normalizedMod.enable()}return}load=bind(this,function(value){this.init([],function(){return value},null,{enabled:true})});load.error=bind(this,function(err){this.inited=true;this.error=err;err.requireModules=[id];eachProp(registry,function(mod){if(mod.map.id.indexOf(id+"_unnormalized")===0){removeWaiting(mod.map.id)}});onError(err)});load.fromText=function(moduleName,text){var hasInteractive=useInteractive;if(hasInteractive){useInteractive=false}getModule(makeModuleMap(moduleName));req.exec(text);if(hasInteractive){useInteractive=true}context.completeLoad(moduleName)};plugin.load(map.name,makeRequire(map.parentMap,true,function(deps,cb,er){deps.rjsSkipMap=true;return context.require(deps,cb,er)}),load,config)}));context.enable(pluginMap,this);this.pluginMaps[pluginMap.id]=pluginMap},enable:function(){this.enabled=true;if(!this.waitPushed){waitAry.push(this);context.waitCount+=1;this.waitPushed=true}this.enabling=true;each(this.depMaps,bind(this,function(depMap,i){var id,mod,handler;if(typeof depMap==="string"){depMap=makeModuleMap(depMap,(this.map.isDefine?this.map:this.map.parentMap),false,!this.depMaps.rjsSkipMap);this.depMaps[i]=depMap;handler=handlers[depMap.id];if(handler){this.depExports[i]=handler(this);return}this.depCount+=1;on(depMap,"defined",bind(this,function(depExports){this.defineDep(i,depExports);this.check()}));if(this.errback){on(depMap,"error",this.errback)}}id=depMap.id;mod=registry[id];if(!handlers[id]&&mod&&!mod.enabled){context.enable(depMap,this)}}));eachProp(this.pluginMaps,bind(this,function(pluginMap){var mod=registry[pluginMap.id];if(mod&&!mod.enabled){context.enable(pluginMap,this)}}));this.enabling=false;this.check()},on:function(name,cb){var cbs=this.events[name];if(!cbs){cbs=this.events[name]=[]}cbs.push(cb)},emit:function(name,evt){each(this.events[name],function(cb){cb(evt)});if(name==="error"){delete this.events[name]}}};function callGetModule(args){getModule(makeModuleMap(args[0],null,true)).init(args[1],args[2])}function removeListener(node,func,name,ieName){if(node.detachEvent&&!isOpera){if(ieName){node.detachEvent(ieName,func)}}else{node.removeEventListener(name,func,false)}}function getScriptData(evt){var node=evt.currentTarget||evt.srcElement;removeListener(node,context.onScriptLoad,"load","onreadystatechange");removeListener(node,context.onScriptError,"error");return{node:node,id:node&&node.getAttribute("data-requiremodule")}}return(context={config:config,contextName:contextName,registry:registry,defined:defined,urlFetched:urlFetched,waitCount:0,defQueue:defQueue,Module:Module,makeModuleMap:makeModuleMap,configure:function(cfg){if(cfg.baseUrl){if(cfg.baseUrl.charAt(cfg.baseUrl.length-1)!=="/"){cfg.baseUrl+="/"}}var pkgs=config.pkgs,shim=config.shim,paths=config.paths,map=config.map;mixin(config,cfg,true);config.paths=mixin(paths,cfg.paths,true);if(cfg.map){config.map=mixin(map||{},cfg.map,true,true)}if(cfg.shim){eachProp(cfg.shim,function(value,id){if(isArray(value)){value={deps:value}}if(value.exports&&!value.exports.__buildReady){value.exports=context.makeShimExports(value.exports)}shim[id]=value});config.shim=shim}if(cfg.packages){each(cfg.packages,function(pkgObj){var location;pkgObj=typeof pkgObj==="string"?{name:pkgObj}:pkgObj;location=pkgObj.location;pkgs[pkgObj.name]={name:pkgObj.name,location:location||pkgObj.name,main:(pkgObj.main||"main").replace(currDirRegExp,"").replace(jsSuffixRegExp,"")}});config.pkgs=pkgs}eachProp(registry,function(mod,id){if(!mod.inited&&!mod.map.unnormalized){mod.map=makeModuleMap(id)}});if(cfg.deps||cfg.callback){context.require(cfg.deps||[],cfg.callback)}},makeShimExports:function(exports){var func;if(typeof exports==="string"){func=function(){return getGlobal(exports)};func.exports=exports;return func}else{return function(){return exports.apply(global,arguments)}}},requireDefined:function(id,relMap){return hasProp(defined,makeModuleMap(id,relMap,false,true).id)},requireSpecified:function(id,relMap){id=makeModuleMap(id,relMap,false,true).id;return hasProp(defined,id)||hasProp(registry,id)},require:function(deps,callback,errback,relMap){var moduleName,id,map,requireMod,args;if(typeof deps==="string"){if(isFunction(callback)){return onError(makeError("requireargs","Invalid require call"),errback)}if(req.get){return req.get(context,deps,callback)}moduleName=deps;relMap=callback;map=makeModuleMap(moduleName,relMap,false,true);id=map.id;if(!hasProp(defined,id)){return onError(makeError("notloaded",'Module name "'+id+'" has not been loaded yet for context: '+contextName))}return defined[id]}if(errback&&!isFunction(errback)){relMap=errback;errback=undefined}if(callback&&!isFunction(callback)){relMap=callback;callback=undefined}takeGlobalQueue();while(defQueue.length){args=defQueue.shift();if(args[0]===null){return onError(makeError("mismatch","Mismatched anonymous define() module: "+args[args.length-1]))}else{callGetModule(args)}}requireMod=getModule(makeModuleMap(null,relMap));requireMod.init(deps,callback,errback,{enabled:true});checkLoaded();return context.require},undef:function(id){takeGlobalQueue();var map=makeModuleMap(id,null,true),mod=registry[id];delete defined[id];delete urlFetched[map.url];delete undefEvents[id];if(mod){if(mod.events.defined){undefEvents[id]=mod.events}removeWaiting(id)}},enable:function(depMap,parent){var mod=registry[depMap.id];if(mod){getModule(depMap).enable()}},completeLoad:function(moduleName){var found,args,mod,shim=config.shim[moduleName]||{},shExports=shim.exports&&shim.exports.exports;takeGlobalQueue();while(defQueue.length){args=defQueue.shift();if(args[0]===null){args[0]=moduleName;if(found){break}found=true}else{if(args[0]===moduleName){found=true}}callGetModule(args)}mod=registry[moduleName];if(!found&&!defined[moduleName]&&mod&&!mod.inited){if(config.enforceDefine&&(!shExports||!getGlobal(shExports))){if(hasPathFallback(moduleName)){return}else{return onError(makeError("nodefine","No define call for "+moduleName,null,[moduleName]))}}else{callGetModule([moduleName,(shim.deps||[]),shim.exports])}}checkLoaded()},toUrl:function(moduleNamePlusExt,relModuleMap){var index=moduleNamePlusExt.lastIndexOf("."),ext=null;if(index!==-1){ext=moduleNamePlusExt.substring(index,moduleNamePlusExt.length);moduleNamePlusExt=moduleNamePlusExt.substring(0,index)}return context.nameToUrl(normalize(moduleNamePlusExt,relModuleMap&&relModuleMap.id,true),ext)},nameToUrl:function(moduleName,ext){var paths,pkgs,pkg,pkgPath,syms,i,parentModule,url,parentPath;if(req.jsExtRegExp.test(moduleName)){url=moduleName+(ext||"")}else{paths=config.paths;pkgs=config.pkgs;syms=moduleName.split("/");for(i=syms.length;i>0;i-=1){parentModule=syms.slice(0,i).join("/");pkg=pkgs[parentModule];parentPath=paths[parentModule];if(parentPath){if(isArray(parentPath)){parentPath=parentPath[0]}syms.splice(0,i,parentPath);break}else{if(pkg){if(moduleName===pkg.name){pkgPath=pkg.location+"/"+pkg.main}else{pkgPath=pkg.location}syms.splice(0,i,pkgPath);break}}}url=syms.join("/");url+=(ext||(/\?/.test(url)?"":".js"));url=(url.charAt(0)==="/"||url.match(/^[\w\+\.\-]+:/)?"":config.baseUrl)+url}return config.urlArgs?url+((url.indexOf("?")===-1?"?":"&")+config.urlArgs):url},load:function(id,url){req.load(context,id,url)},execCb:function(name,callback,args,exports){return callback.apply(exports,args)},onScriptLoad:function(evt){if(evt.type==="load"||(readyRegExp.test((evt.currentTarget||evt.srcElement).readyState))){interactiveScript=null;var data=getScriptData(evt);context.completeLoad(data.id)}},onScriptError:function(evt){var data=getScriptData(evt);if(!hasPathFallback(data.id)){return onError(makeError("scripterror","Script error",evt,[data.id]))}}})}req=requirejs=function(deps,callback,errback,optional){var context,config,contextName=defContextName;if(!isArray(deps)&&typeof deps!=="string"){config=deps;if(isArray(callback)){deps=callback;callback=errback;errback=optional}else{deps=[]}}if(config&&config.context){contextName=config.context}context=contexts[contextName];if(!context){context=contexts[contextName]=req.s.newContext(contextName)}if(config){context.configure(config)}return context.require(deps,callback,errback)};req.config=function(config){return req(config)};if(!require){require=req}req.version=version;req.jsExtRegExp=/^\/|:|\?|\.js$/;req.isBrowser=isBrowser;s=req.s={contexts:contexts,newContext:newContext};req({});addRequireMethods(req);if(isBrowser){head=s.head=document.getElementsByTagName("head")[0];baseElement=document.getElementsByTagName("base")[0];if(baseElement){head=s.head=baseElement.parentNode}}req.onError=function(err){throw err};req.load=function(context,moduleName,url){var config=(context&&context.config)||{},node;if(isBrowser){node=config.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");node.type=config.scriptType||"text/javascript";node.charset="utf-8";node.async=true;node.setAttribute("data-requirecontext",context.contextName);node.setAttribute("data-requiremodule",moduleName);if(node.attachEvent&&!(node.attachEvent.toString&&node.attachEvent.toString().indexOf("[native code")<0)&&!isOpera){useInteractive=true;node.attachEvent("onreadystatechange",context.onScriptLoad)}else{node.addEventListener("load",context.onScriptLoad,false);node.addEventListener("error",context.onScriptError,false)}node.src=url;currentlyAddingScript=node;if(baseElement){head.insertBefore(node,baseElement)}else{head.appendChild(node)}currentlyAddingScript=null;return node}else{if(isWebWorker){importScripts(url);context.completeLoad(moduleName)}}};function getInteractiveScript(){if(interactiveScript&&interactiveScript.readyState==="interactive"){return interactiveScript}eachReverse(scripts(),function(script){if(script.readyState==="interactive"){return(interactiveScript=script)}});return interactiveScript}if(isBrowser){eachReverse(scripts(),function(script){if(!head){head=script.parentNode}dataMain=script.getAttribute("data-main");if(dataMain){if(!cfg.baseUrl){src=dataMain.split("/");mainScript=src.pop();subPath=src.length?src.join("/")+"/":"./";cfg.baseUrl=subPath;dataMain=mainScript}dataMain=dataMain.replace(jsSuffixRegExp,"");cfg.deps=cfg.deps?cfg.deps.concat(dataMain):[dataMain];return true}})}define=function(name,deps,callback){var node,context;if(typeof name!=="string"){callback=deps;deps=name;name=null}if(!isArray(deps)){callback=deps;deps=[]}if(!deps.length&&isFunction(callback)){if(callback.length){callback.toString().replace(commentRegExp,"").replace(cjsRequireRegExp,function(match,dep){deps.push(dep)});deps=(callback.length===1?["require"]:["require","exports","module"]).concat(deps)}}if(useInteractive){node=currentlyAddingScript||getInteractiveScript();if(node){if(!name){name=node.getAttribute("data-requiremodule")}context=contexts[node.getAttribute("data-requirecontext")]}}(context?context.defQueue:globalDefQueue).push([name,deps,callback])};define.amd={jQuery:true};req.exec=function(text){return eval(text)};req(cfg)}(this));
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/templates/compiled/helpers-common-templates.js
--- a/static/scripts/packed/templates/compiled/helpers-common-templates.js
+++ b/static/scripts/packed/templates/compiled/helpers-common-templates.js
@@ -1,1 +1,1 @@
-Handlebars.registerPartial("clearFloatDiv",function(a){return'<div class="clear"></div>'});Handlebars.registerPartial("iconButton",function(c,b){var a="";a+=(c.enabled)?("<a"):("<span");if(c.title){c.buffer+=' title="'+c.title+'"'}a+=' class="icon-button';if(c.isMenuButton){a+=" menu-button"}if(c.title){a+=" tooltip"}a+=" "+c.icon_class;if(!c.enabled){a+="_disabled"}a+='"';if(c.id){a+=' id="'+c.id+'"'}a+=' href="'+((c.href)?(c.href):("javascript:void(0);"))+'"';if(c.target){a+=' target="'+c.target+'"'}if(!c.visible){a+=' style="display: none;"'}a+=">Bler"+((c.enabled)?("</a>"):("</span>"));return a});Handlebars.registerHelper("warningmessagesmall",function(a){return'<div class="warningmessagesmall"><strong>'+a.fn(this)+"</strong></div>"});
\ No newline at end of file
+Handlebars.registerPartial("clearFloatDiv",function(a){return'<div class="clear"></div>'});Handlebars.registerPartial("iconButton",function(c,b){var a="";a+=(c.enabled)?("<a"):("<span");if(c.title){a+=' title="'+c.title+'"'}a+=' class="icon-button';if(c.isMenuButton){a+=" menu-button"}if(c.title){a+=" tooltip"}a+=" "+c.icon_class;if(!c.enabled){a+="_disabled"}a+='"';if(c.id){a+=' id="'+c.id+'"'}a+=' href="'+((c.href)?(c.href):("javascript:void(0);"))+'"';if(c.target){a+=' target="'+c.target+'"'}if(!c.visible){a+=' style="display: none;"'}a+=">"+((c.enabled)?("</a>"):("</span>"));return a});Handlebars.registerHelper("warningmessagesmall",function(a){return'<div class="warningmessagesmall"><strong>'+a.fn(this)+"</strong></div>"});
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/templates/compiled/template-history-annotationArea.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/template-history-annotationArea.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-annotationArea"]=b(function(e,l,d,k,j){d=d||e.helpers;var h="",c,g,f="function",i=this.escapeExpression;h+='\n<div id="';g=d.id;if(g){c=g.call(l,{hash:{}})}else{c=l.id;c=typeof c===f?c():c}h+=i(c)+'-annotation-area" class="annotation-area" style="display: none;">\n <strong>Annotation:</strong>\n <div id="';g=d.id;if(g){c=g.call(l,{hash:{}})}else{c=l.id;c=typeof c===f?c():c}h+=i(c)+'-anotation-elt" class="annotation-elt tooltip editable-text"\n style="margin: 1px 0px 1px 0px" title="Edit dataset annotation">\n </div>\n</div>';return h})})();
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/templates/compiled/template-history-failedMetaData.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/template-history-failedMetaData.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-failedMetaData"]=b(function(f,l,e,k,j){e=e||f.helpers;var c,h,g="function",i=this.escapeExpression,n=this,m=e.blockHelperMissing;function d(s,r){var p="",q,o;p+='\nAn error occurred setting the metadata for this dataset.\nYou may be able to <a href="';o=e.edit_url;if(o){q=o.call(s,{hash:{}})}else{q=s.edit_url;q=typeof q===g?q():q}p+=i(q)+'" target="galaxy_main">set it manually or retry auto-detection</a>.\n';return p}h=e.warningmessagesmall;if(h){c=h.call(l,{hash:{},inverse:n.noop,fn:n.program(1,d,j)})}else{c=l.warningmessagesmall;c=typeof c===g?c():c}if(!e.warningmessagesmall){c=m.call(l,c,{hash:{},inverse:n.noop,fn:n.program(1,d,j)})}if(c||c===0){return c}else{return""}})})();
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/templates/compiled/template-history-hdaSummary.js
--- a/static/scripts/packed/templates/compiled/template-history-hdaSummary.js
+++ b/static/scripts/packed/templates/compiled/template-history-hdaSummary.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-hdaSummary"]=b(function(g,n,f,m,l){f=f||g.helpers;var j="",d,i,h="function",k=this.escapeExpression,o=this;function e(t,s){var q="",r,p;q+='\n <a href="';p=f.edit_url;if(p){r=p.call(t,{hash:{}})}else{r=t.edit_url;r=typeof r===h?r():r}q+=k(r)+'" target="galaxy_main">';p=f.metadata_dbkey;if(p){r=p.call(t,{hash:{}})}else{r=t.metadata_dbkey;r=typeof r===h?r():r}q+=k(r)+"</a>\n";return q}function c(t,s){var q="",r,p;q+='\n <span class="';p=f.metadata_dbkey;if(p){r=p.call(t,{hash:{}})}else{r=t.metadata_dbkey;r=typeof r===h?r():r}q+=k(r)+'">';p=f.metadata_dbkey;if(p){r=p.call(t,{hash:{}})}else{r=t.metadata_dbkey;r=typeof r===h?r():r}q+=k(r)+"</span>\n";return q}i=f.misc_blurb;if(i){d=i.call(n,{hash:{}})}else{d=n.misc_blurb;d=typeof d===h?d():d}j+=k(d)+'<br />\nformat: <span class="';i=f.data_type;if(i){d=i.call(n,{hash:{}})}else{d=n.data_type;d=typeof d===h?d():d}j+=k(d)+'">';i=f.data_type;if(i){d=i.call(n,{hash:{}})}else{d=n.data_type;d=typeof d===h?d():d}j+=k(d)+"</span>,\ndatabase:\n";d=n.dbkey_unknown_and_editable;d=f["if"].call(n,d,{hash:{},inverse:o.program(3,c,l),fn:o.program(1,e,l)});if(d||d===0){j+=d}return j})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-hdaSummary"]=b(function(g,n,f,m,l){f=f||g.helpers;var j="",d,i,h="function",k=this.escapeExpression,p=this;function e(u,t){var r="",s,q;r+='\n <a href="';q=f.edit_url;if(q){s=q.call(u,{hash:{}})}else{s=u.edit_url;s=typeof s===h?s():s}r+=k(s)+'" target="galaxy_main">';q=f.metadata_dbkey;if(q){s=q.call(u,{hash:{}})}else{s=u.metadata_dbkey;s=typeof s===h?s():s}r+=k(s)+"</a>\n ";return r}function c(u,t){var r="",s,q;r+='\n <span class="';q=f.metadata_dbkey;if(q){s=q.call(u,{hash:{}})}else{s=u.metadata_dbkey;s=typeof s===h?s():s}r+=k(s)+'">';q=f.metadata_dbkey;if(q){s=q.call(u,{hash:{}})}else{s=u.metadata_dbkey;s=typeof s===h?s():s}r+=k(s)+"</span>\n ";return r}function o(u,t){var r="",s,q;r+='\n<div class="hda-info">';q=f.misc_info;if(q){s=q.call(u,{hash:{}})}else{s=u.misc_info;s=typeof s===h?s():s}r+=k(s)+"</div>\n";return r}j+='<div class="hda-summary">\n ';i=f.misc_blurb;if(i){d=i.call(n,{hash:{}})}else{d=n.misc_blurb;d=typeof d===h?d():d}j+=k(d)+'<br />\n format: <span class="';i=f.data_type;if(i){d=i.call(n,{hash:{}})}else{d=n.data_type;d=typeof d===h?d():d}j+=k(d)+'">';i=f.data_type;if(i){d=i.call(n,{hash:{}})}else{d=n.data_type;d=typeof d===h?d():d}j+=k(d)+"</span>,\n database:\n ";d=n.dbkey_unknown_and_editable;d=f["if"].call(n,d,{hash:{},inverse:p.program(3,c,l),fn:p.program(1,e,l)});if(d||d===0){j+=d}j+="\n</div>\n";d=n.misc_info;d=f["if"].call(n,d,{hash:{},inverse:p.noop,fn:p.program(5,o,l)});if(d||d===0){j+=d}return j})})();
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/templates/compiled/template-history-tagArea.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/template-history-tagArea.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-tagArea"]=b(function(g,h,e,d,f){e=e||g.helpers;var c="";c+='\n<div class="tag-area" style="display: none;">\n <strong>Tags:</strong>\n <div class="tag-elt">\n </div>\n</div>';return c})})();
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/templates/compiled/template-history-warning-messages.js
--- a/static/scripts/packed/templates/compiled/template-history-warning-messages.js
+++ b/static/scripts/packed/templates/compiled/template-history-warning-messages.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-warning-messages"]=b(function(g,s,q,k,v){q=q||g.helpers;var r="",h,e="function",d=this.escapeExpression,p=this,c=q.blockHelperMissing;function o(z,y){var x,w;w=q.warningmessagesmall;if(w){x=w.call(z,{hash:{},inverse:p.noop,fn:p.program(2,n,y)})}else{x=z.warningmessagesmall;x=typeof x===e?x():x}if(!q.warningmessagesmall){x=c.call(z,x,{hash:{},inverse:p.noop,fn:p.program(2,n,y)})}if(x||x===0){return x}else{return""}}function n(z,y){var w="",x;w+="\n This dataset has been deleted.\n ";x=z.undelete_url;x=q["if"].call(z,x,{hash:{},inverse:p.noop,fn:p.program(3,m,y)});if(x||x===0){w+=x}w+="\n";return w}function m(A,z){var x="",y,w;x+='\n Click <a href="';w=q.undelete_url;if(w){y=w.call(A,{hash:{}})}else{y=A.undelete_url;y=typeof y===e?y():y}x+=d(y)+'" class="historyItemUndelete" id="historyItemUndeleter-';w=q.id;if(w){y=w.call(A,{hash:{}})}else{y=A.id;y=typeof y===e?y():y}x+=d(y)+'"\n target="galaxy_history">here</a> to undelete it\n ';y=A.purge_url;y=q["if"].call(A,y,{hash:{},inverse:p.noop,fn:p.program(4,l,z)});if(y||y===0){x+=y}x+="\n ";return x}function l(A,z){var x="",y,w;x+='\n or <a href="';w=q.purge_url;if(w){y=w.call(A,{hash:{}})}else{y=A.purge_url;y=typeof y===e?y():y}x+=d(y)+'" class="historyItemPurge" id="historyItemPurger-';w=q.id;if(w){y=w.call(A,{hash:{}})}else{y=A.id;y=typeof y===e?y():y}x+=d(y)+'"\n target="galaxy_history">here</a> to immediately remove it from disk\n ';return x}function j(z,y){var x,w;w=q.warningmessagesmall;if(w){x=w.call(z,{hash:{},inverse:p.noop,fn:p.program(7,i,y)})}else{x=z.warningmessagesmall;x=typeof x===e?x():x}if(!q.warningmessagesmall){x=c.call(z,x,{hash:{},inverse:p.noop,fn:p.program(7,i,y)})}if(x||x===0){return x}else{return""}}function i(x,w){return"\n This dataset has been deleted and removed from disk.\n"}function f(z,y){var x,w;w=q.warningmessagesmall;if(w){x=w.call(z,{hash:{},inverse:p.noop,fn:p.program(10,u,y)})}else{x=z.warningmessagesmall;x=typeof x===e?x():x}if(!q.warningmessagesmall){x=c.call(z,x,{hash:{},inverse:p.noop,fn:p.program(10,u,y)})}if(x||x===0){return x}else{return""}}function u(z,y){var w="",x;w+="\n This dataset has been hidden.\n ";x=z.undelete_url;x=q["if"].call(z,x,{hash:{},inverse:p.noop,fn:p.program(11,t,y)});if(x||x===0){w+=x}w+="\n";return w}function t(A,z){var x="",y,w;x+='\n Click <a href="';w=q.unhide_url;if(w){y=w.call(A,{hash:{}})}else{y=A.unhide_url;y=typeof y===e?y():y}x+=d(y)+'" class="historyItemUnhide" id="historyItemUnhider-';w=q.id;if(w){y=w.call(A,{hash:{}})}else{y=A.id;y=typeof y===e?y():y}x+=d(y)+'"\n target="galaxy_history">here</a> to unhide it\n ';return x}h=s.deleted;h=q["if"].call(s,h,{hash:{},inverse:p.noop,fn:p.program(1,o,v)});if(h||h===0){r+=h}r+="\n\n";h=s.purged;h=q["if"].call(s,h,{hash:{},inverse:p.noop,fn:p.program(6,j,v)});if(h||h===0){r+=h}r+="\n\n";h=s.visible;h=q.unless.call(s,h,{hash:{},inverse:p.noop,fn:p.program(9,f,v)});if(h||h===0){r+=h}return r})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-warning-messages"]=b(function(g,s,q,k,v){q=q||g.helpers;var r="",h,e="function",d=this.escapeExpression,p=this,c=q.blockHelperMissing;function o(z,y){var x,w;w=q.warningmessagesmall;if(w){x=w.call(z,{hash:{},inverse:p.noop,fn:p.program(2,n,y)})}else{x=z.warningmessagesmall;x=typeof x===e?x():x}if(!q.warningmessagesmall){x=c.call(z,x,{hash:{},inverse:p.noop,fn:p.program(2,n,y)})}if(x||x===0){return x}else{return""}}function n(z,y){var w="",x;w+="\n This dataset has been deleted.\n ";x=z.undelete_url;x=q["if"].call(z,x,{hash:{},inverse:p.noop,fn:p.program(3,m,y)});if(x||x===0){w+=x}w+="\n";return w}function m(A,z){var x="",y,w;x+='\n Click <a href="';w=q.undelete_url;if(w){y=w.call(A,{hash:{}})}else{y=A.undelete_url;y=typeof y===e?y():y}x+=d(y)+'" class="historyItemUndelete" id="historyItemUndeleter-';w=q.id;if(w){y=w.call(A,{hash:{}})}else{y=A.id;y=typeof y===e?y():y}x+=d(y)+'"\n target="galaxy_history">here</a> to undelete it\n ';y=A.purge_url;y=q["if"].call(A,y,{hash:{},inverse:p.noop,fn:p.program(4,l,z)});if(y||y===0){x+=y}x+="\n ";return x}function l(A,z){var x="",y,w;x+='\n or <a href="';w=q.purge_url;if(w){y=w.call(A,{hash:{}})}else{y=A.purge_url;y=typeof y===e?y():y}x+=d(y)+'" class="historyItemPurge" id="historyItemPurger-';w=q.id;if(w){y=w.call(A,{hash:{}})}else{y=A.id;y=typeof y===e?y():y}x+=d(y)+'"\n target="galaxy_history">here</a> to immediately remove it from disk\n ';return x}function j(z,y){var x,w;w=q.warningmessagesmall;if(w){x=w.call(z,{hash:{},inverse:p.noop,fn:p.program(7,i,y)})}else{x=z.warningmessagesmall;x=typeof x===e?x():x}if(!q.warningmessagesmall){x=c.call(z,x,{hash:{},inverse:p.noop,fn:p.program(7,i,y)})}if(x||x===0){return x}else{return""}}function i(x,w){return"\n This dataset has been deleted and removed from disk.\n"}function f(z,y){var x,w;w=q.warningmessagesmall;if(w){x=w.call(z,{hash:{},inverse:p.noop,fn:p.program(10,u,y)})}else{x=z.warningmessagesmall;x=typeof x===e?x():x}if(!q.warningmessagesmall){x=c.call(z,x,{hash:{},inverse:p.noop,fn:p.program(10,u,y)})}if(x||x===0){return x}else{return""}}function u(z,y){var w="",x;w+="\n This dataset has been hidden.\n ";x=z.unhide_url;x=q["if"].call(z,x,{hash:{},inverse:p.noop,fn:p.program(11,t,y)});if(x||x===0){w+=x}w+="\n";return w}function t(A,z){var x="",y,w;x+='\n Click <a href="';w=q.unhide_url;if(w){y=w.call(A,{hash:{}})}else{y=A.unhide_url;y=typeof y===e?y():y}x+=d(y)+'" class="historyItemUnhide" id="historyItemUnhider-';w=q.id;if(w){y=w.call(A,{hash:{}})}else{y=A.id;y=typeof y===e?y():y}x+=d(y)+'"\n target="galaxy_history">here</a> to unhide it\n ';return x}h=s.deleted;h=q["if"].call(s,h,{hash:{},inverse:p.noop,fn:p.program(1,o,v)});if(h||h===0){r+=h}r+="\n\n";h=s.purged;h=q["if"].call(s,h,{hash:{},inverse:p.noop,fn:p.program(6,j,v)});if(h||h===0){r+=h}r+="\n\n";h=s.visible;h=q.unless.call(s,h,{hash:{},inverse:p.noop,fn:p.program(9,f,v)});if(h||h===0){r+=h}return r})})();
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/templates/compiled/template-iconButton.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/template-iconButton.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-iconButton"]=b(function(i,j,g,e,h){g=g||i.helpers;e=e||i.partials;var c="",f,d=this;c+="\n";f=d.invokePartial(e.iconButton,"iconButton",j,g,e);if(f||f===0){c+=f}return c})})();
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/templates/compiled/template-warningmessagesmall.js
--- a/static/scripts/packed/templates/compiled/template-warningmessagesmall.js
+++ b/static/scripts/packed/templates/compiled/template-warningmessagesmall.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-warningmessagesmall"]=b(function(e,l,d,k,j){d=d||e.helpers;var h="",c,g,f="function",i=this.escapeExpression;h+=' \n <div class="warningmessagesmall"><strong>';g=d.warning;if(g){c=g.call(l,{hash:{}})}else{c=l.warning;c=typeof c===f?c():c}h+=i(c)+"</strong></div>";return h})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-warningmessagesmall"]=b(function(e,k,d,j,i){d=d||e.helpers;var h="",c,g,f="function";h+=' \n <div class="warningmessagesmall"><strong>';g=d.warning;if(g){c=g.call(k,{hash:{}})}else{c=k.warning;c=typeof c===f?c():c}if(c||c===0){h+=c}h+="</strong></div>";return h})})();
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 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 class_module=function(b,a){var c=function(){var g=arguments[0];for(var f=1;f<arguments.length;f++){var d=arguments[f];for(var e in d){g[e]=d[e]}}return g};a.extend=c};var requestAnimationFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(b,a){window.setTimeout(b,1000/60)}})();var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(e,b){var g=e[0],f=e[1],d=b[0],c=b[1],a;if(g<d){if(f<d){a=BEFORE}else{if(f<=c){a=OVERLAP_START}else{a=CONTAINS}}}else{if(g>c){a=AFTER}else{if(f<=c){a=CONTAINED_BY}else{a=OVERLAP_END}}}return a};var is_overlap=function(c,b){var a=compute_overlap(c,b);return(a!==BEFORE&&a!==AFTER)};var is_deferred=function(a){return("isResolved" in a)};var get_random_color=function(a){if(!a){a="#ffffff"}if(typeof(a)==="string"){a=[a]}for(var j=0;j<a.length;j++){a[j]=parseInt(a[j].slice(1),16)}var n=function(t,s,i){return((t*299)+(s*587)+(i*114))/1000};var e=function(v,u,w,s,i,t){return(Math.max(v,s)-Math.min(v,s))+(Math.max(u,i)-Math.min(u,i))+(Math.max(w,t)-Math.min(w,t))};var g,o,f,k,q,h,r,c,d,b,p,m=false,l=0;do{g=Math.round(Math.random()*16777215);o=(g&16711680)>>16;f=(g&65280)>>8;k=g&255;d=n(o,f,k);m=true;for(j=0;j<a.length;j++){q=a[j];h=(q&16711680)>>16;r=(q&65280)>>8;c=q&255;b=n(h,r,c);p=e(o,f,k,h,r,c);if((Math.abs(d-b)<40)||(p<200)){m=false;break}}l++}while(!m&&l<=10);return"#"+(16777216+g).toString(16).substr(1,6)};var create_action_icon=function(c,b,a){return $("<a/>").attr("href","javascript:void(0);").attr("title",c).addClass("icon-button").addClass(b).tooltip().click(a)};var trackster_module=function(d,S){var o=d("class").extend,s=d("slotting"),I=d("painters");var m={};var k=function(Z,aa){m[Z.attr("id")]=aa};var l=function(Z,ab,ad,ac){ad=".group";var aa={};m[Z.attr("id")]=ac;Z.bind("drag",{handle:"."+ab,relative:true},function(al,am){var ak=$(this),ap=$(this).parent(),ah=ap.children(),aj=m[$(this).attr("id")],ag,af,an,ae,ai;af=$(this).parents(ad);if(af.length!==0){an=af.position().top;ae=an+af.outerHeight();if(am.offsetY<an){$(this).insertBefore(af);var ao=m[af.attr("id")];ao.remove_drawable(aj);ao.container.add_drawable_before(aj,ao);return}else{if(am.offsetY>ae){$(this).insertAfter(af);var ao=m[af.attr("id")];ao.remove_drawable(aj);ao.container.add_drawable(aj);return}}}af=null;for(ai=0;ai<ah.length;ai++){ag=$(ah.get(ai));an=ag.position().top;ae=an+ag.outerHeight();if(ag.is(ad)&&this!==ag.get(0)&&am.offsetY>=an&&am.offsetY<=ae){if(am.offsetY-an<ae-am.offsetY){ag.find(".content-div").prepend(this)}else{ag.find(".content-div").append(this)}if(aj.container){aj.container.remove_drawable(aj)}m[ag.attr("id")].add_drawable(aj);return}}for(ai=0;ai<ah.length;ai++){ag=$(ah.get(ai));if(am.offsetY<ag.position().top&&!(ag.hasClass("reference-track")||ag.hasClass("intro"))){break}}if(ai===ah.length){if(this!==ah.get(ai-1)){ap.append(this);m[ap.attr("id")].move_drawable(aj,ai)}}else{if(this!==ah.get(ai)){$(this).insertBefore(ah.get(ai));m[ap.attr("id")].move_drawable(aj,(am.deltaY>0?ai-1:ai))}}}).bind("dragstart",function(){aa["border-top"]=Z.css("border-top");aa["border-bottom"]=Z.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(aa)})};S.moveable=l;var Y=16,D=9,A=20,x=100,F=12000,P=400,H=5000,u=100,n="There was an error in indexing this dataset. ",G="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",B="No data for this chrom/contig.",t="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",v="Tool cannot be rerun: ",a="Loading data...",T="Ready for display",N=10,E=20;function U(aa,Z){if(!Z){Z=0}var ab=Math.pow(10,Z);return Math.round(aa*ab)/ab}var p=function(aa,Z,ac){if(!p.id_counter){p.id_counter=0}this.id=p.id_counter++;this.name=ac.name;this.view=aa;this.container=Z;this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:ac.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=ac.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(ad){ad.stopPropagation()});var ab=this;this.container_div.hover(function(){ab.icons_div.show()},function(){ab.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};p.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(Z){if(Z.content_visible){Z.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");Z.hide_contents();Z.content_visible=false}else{Z.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");Z.content_visible=true;Z.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(aa){var ac=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},Z=function(){aa.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ab=function(ad){if((ad.keyCode||ad.which)===27){ac()}else{if((ad.keyCode||ad.which)===13){Z()}}};$(window).bind("keypress.check_enter_esc",ab);show_modal("Configure",aa.config.build_form(),{Cancel:ac,OK:Z})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(Z){$(".bs-tooltip").remove();Z.remove()}}];o(p.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(){},to_dict:function(){},set_name:function(Z){this.old_name=this.name;this.name=Z;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 Z=this.view;this.container_div.hide(0,function(){$(this).remove();Z.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(aa,af,ae,ad,Z,ac){var ab=this;this.action_icons[aa]=$("<a/>").attr("href","javascript:void(0);").attr("title",af).addClass("icon-button").addClass(ae).tooltip().click(function(){ad(ab)}).appendTo(this.icons_div);if(ac){this.action_icons[aa].hide()}},build_action_icons:function(Z){var ab;for(var aa=0;aa<Z.length;aa++){ab=Z[aa];this.add_action_icon(ab.name,ab.title,ab.css_class,ab.on_click_fn,ab.prepend,ab.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var w=function(aa,Z,ab){p.call(this,aa,Z,ab);this.obj_type=ab.obj_type;this.drawables=[]};o(w.prototype,p.prototype,{unpack_drawables:function(ab){this.drawables=[];var aa;for(var Z=0;Z<ab.length;Z++){aa=object_from_template(ab[Z],this.view,this);this.add_drawable(aa)}},init:function(){for(var Z=0;Z<this.drawables.length;Z++){this.drawables[Z].init()}},_draw:function(){for(var Z=0;Z<this.drawables.length;Z++){this.drawables[Z]._draw()}},to_dict:function(){var aa=[];for(var Z=0;Z<this.drawables.length;Z++){aa.push(this.drawables[Z].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:aa}},add_drawable:function(Z){this.drawables.push(Z);Z.container=this;this.changed()},add_drawable_before:function(ab,Z){this.changed();var aa=this.drawables.indexOf(Z);if(aa!==-1){this.drawables.splice(aa,0,ab);return true}return false},replace_drawable:function(ab,Z,aa){var ac=this.drawables.indexOf(ab);if(ac!==-1){this.drawables[ac]=Z;if(aa){ab.container_div.replaceWith(Z.container_div)}this.changed()}return ac},remove_drawable:function(aa){var Z=this.drawables.indexOf(aa);if(Z!==-1){this.drawables.splice(Z,1);aa.container=null;this.changed();return true}return false},move_drawable:function(aa,ab){var Z=this.drawables.indexOf(aa);if(Z!==-1){this.drawables.splice(Z,1);this.drawables.splice(ab,0,aa);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var M=function(aa,Z,ac){o(ac,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});w.call(this,aa,Z,ac);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);l(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new V(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ac){this.unpack_drawables(ac.drawables)}if("filters" in ac){var ab=this.filters_manager;this.filters_manager=new V(this,ac.filters);ab.parent_div.replaceWith(this.filters_manager.parent_div);if(ac.filters.visible){this.setup_multitrack_filtering()}}};o(M.prototype,p.prototype,w.prototype,{action_icons_def:[p.prototype.action_icons_def[0],p.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(Z){$(".bs-tooltip").remove();Z.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(Z){if(Z.filters_manager.visible()){Z.filters_manager.clear_filters();Z._restore_filter_managers()}else{Z.setup_multitrack_filtering();Z.request_draw(true)}Z.filters_manager.toggle()}},p.prototype.action_icons_def[2]],build_container_div:function(){var Z=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(Z)}return Z},build_header_div:function(){var Z=$("<div/>").addClass("track-header");Z.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(Z);return Z},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ab=this.drawables.length;if(ab===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ab===1){if(this.drawables[0] instanceof g){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var ai,ah,af,al=true,ad=this.drawables[0].get_type(),Z=0;for(ai=0;ai<ab;ai++){af=this.drawables[ai];if(af.get_type()!==ad){can_composite=false;break}if(af instanceof c){Z++}}if(al||Z===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(Z>1&&Z===this.drawables.length){var am={},aa;af=this.drawables[0];for(ah=0;ah<af.filters_manager.filters.length;ah++){aa=af.filters_manager.filters[ah];am[aa.name]=[aa]}for(ai=1;ai<this.drawables.length;ai++){af=this.drawables[ai];for(ah=0;ah<af.filters_manager.filters.length;ah++){aa=af.filters_manager.filters[ah];if(aa.name in am){am[aa.name].push(aa)}}}this.filters_manager.remove_all();var ac,ae,ag,aj;for(var ak in am){ac=am[ak];if(ac.length===Z){ae=new Q({name:ac[0].name,index:ac[0].index});this.filters_manager.add_filter(ae)}}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 Z=0;Z<this.drawables.length;Z++){this.drawables[Z].filters_manager=this.saved_filters_managers[Z]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var Z=0;Z<this.drawables.length;Z++){drawable=this.drawables[Z];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=[];for(var aa=0;aa<this.drawables.length;aa++){ad.push(this.drawables[aa].name)}var ab="Composite Track of "+this.drawables.length+" tracks ("+ad.join(", ")+")";var ac=new g(this.view,this.view,{name:ab,drawables:this.drawables});var Z=this.container.replace_drawable(this,ac,true);ac.request_draw()},add_drawable:function(Z){w.prototype.add_drawable.call(this,Z);this.update_icons()},remove_drawable:function(Z){w.prototype.remove_drawable.call(this,Z);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var Z=o(w.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return Z},request_draw:function(Z,ab){for(var aa=0;aa<this.drawables.length;aa++){this.drawables[aa].request_draw(Z,ab)}}});var X=function(Z){o(Z,{obj_type:"View"});w.call(this,"View",Z.container,Z);this.chrom=null;this.vis_id=Z.vis_id;this.dbkey=Z.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.init();this.canvas_manager=new CanvasManager(this.container.get(0).ownerDocument);this.reset()};_.extend(X.prototype,Backbone.Events);o(X.prototype,w.prototype,{init:function(){this.requested_redraw=false;var ab=this.container,Z=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ab);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ab);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ab);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;k(this.viewport_container,Z);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ac=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){add_datasets(add_datasets_url,add_track_async_url,function(ad){_.each(ad,function(ae){Z.add_drawable(object_from_template(ae,Z,Z))})})});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 aa=function(ad){if(ad.type==="focusout"||(ad.keyCode||ad.which)===13||(ad.keyCode||ad.which)===27){if((ad.keyCode||ad.which)!==27){Z.go_to($(this).val())}$(this).hide();$(this).val("");Z.location_span.show();Z.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",aa).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(){Z.location_span.hide();Z.chrom_select.hide();Z.nav_input.val(Z.chrom+":"+Z.low+"-"+Z.high);Z.nav_input.css("display","inline-block");Z.nav_input.select();Z.nav_input.focus();Z.nav_input.autocomplete({source:function(af,ad){var ag=[],ae=$.map(Z.get_drawables(),function(ah){return ah.data_manager.search_features(af.term).success(function(ai){ag=ag.concat(ai)})});$.when.apply($,ae).done(function(){ad($.map(ag,function(ah){return{label:ah[0],value:ah[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(){Z.zoom_out();Z.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){Z.zoom_in();Z.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){Z.change_chrom(Z.chrom_select.val())});this.browser_content_div.click(function(ad){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ad){Z.zoom_in(ad.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ad,ae){this.current_x=ae.offsetX}).bind("drag",function(ad,af){var ag=af.offsetX-this.current_x;this.current_x=af.offsetX;var ae=Math.round(ag/Z.viewport_container.width()*(Z.max_high-Z.max_low));Z.move_delta(-ae)});this.overview_close.click(function(){Z.reset_overview()});this.viewport_container.bind("draginit",function(ad,ae){if(ad.clientX>Z.viewport_container.width()-16){return false}}).bind("dragstart",function(ad,ae){ae.original_low=Z.low;ae.current_height=ad.clientY;ae.current_x=ae.offsetX}).bind("drag",function(af,ah){var ad=$(this);var ai=ah.offsetX-ah.current_x;var ae=ad.scrollTop()-(af.clientY-ah.current_height);ad.scrollTop(ae);ah.current_height=af.clientY;ah.current_x=ah.offsetX;var ag=Math.round(ai/Z.viewport_container.width()*(Z.high-Z.low));Z.move_delta(ag)}).bind("mousewheel",function(af,ah,ae,ad){if(ae){ae*=50;var ag=Math.round(-ae/Z.viewport_container.width()*(Z.high-Z.low));Z.move_delta(ag)}});this.top_labeltrack.bind("dragstart",function(ad,ae){return $("<div />").css({height:Z.browser_content_div.height()+Z.top_labeltrack.height()+Z.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ah,ai){$(ai.proxy).css({left:Math.min(ah.pageX,ai.startX)-Z.container.offset().left,width:Math.abs(ah.pageX-ai.startX)});var ae=Math.min(ah.pageX,ai.startX)-Z.container.offset().left,ad=Math.max(ah.pageX,ai.startX)-Z.container.offset().left,ag=(Z.high-Z.low),af=Z.viewport_container.width();Z.update_location(Math.round(ae/af*ag)+Z.low,Math.round(ad/af*ag)+Z.low)}).bind("dragend",function(ai,aj){var ae=Math.min(ai.pageX,aj.startX),ad=Math.max(ai.pageX,aj.startX),ag=(Z.high-Z.low),af=Z.viewport_container.width(),ah=Z.low;Z.low=Math.round(ae/af*ag)+ah;Z.high=Math.round(ad/af*ag)+ah;$(aj.proxy).remove();Z.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(){Z.resize_window()},500)});$(document).bind("redraw",function(){Z.redraw()});this.reset();$(window).trigger("resize")},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(aa,ac,Z,ad){if(this.timer){clearTimeout(this.timer)}if(ad){var ab=this;this.timer=setTimeout(function(){ab.trigger("navigate",aa+":"+ac+"-"+Z)},500)}else{view.trigger("navigate",aa+":"+ac+"-"+Z)}},update_location:function(Z,ab){this.location_span.text(commatize(Z)+" - "+commatize(ab));this.nav_input.val(this.chrom+":"+commatize(Z)+"-"+commatize(ab));var aa=view.chrom_select.val();if(aa!==""){this.trigger_navigate(aa,view.low,view.high,true)}},load_chroms:function(ab){ab.num=u;ab.dbkey=this.dbkey;var Z=this,aa=$.Deferred();$.ajax({url:chrom_url,data:ab,dataType:"json",success:function(ad){if(ad.chrom_info.length===0){return}if(ad.reference){Z.add_label_track(new y(Z))}Z.chrom_data=ad.chrom_info;var ag='<option value="">Select Chrom/Contig</option>';for(var af=0,ac=Z.chrom_data.length;af<ac;af++){var ae=Z.chrom_data[af].chrom;ag+='<option value="'+ae+'">'+ae+"</option>"}if(ad.prev_chroms){ag+='<option value="previous">Previous '+u+"</option>"}if(ad.next_chroms){ag+='<option value="next">Next '+u+"</option>"}Z.chrom_select.html(ag);Z.chrom_start_index=ad.start_index;aa.resolve(ad)},error:function(){alert("Could not load chroms for this dbkey:",Z.dbkey)}});return aa},change_chrom:function(ae,aa,ag){var ab=this;if(!ab.chrom_data){ab.load_chroms_deferred.then(function(){ab.change_chrom(ae,aa,ag)});return}if(!ae||ae==="None"){return}if(ae==="previous"){ab.load_chroms({low:this.chrom_start_index-u});return}if(ae==="next"){ab.load_chroms({low:this.chrom_start_index+u});return}var af=$.grep(ab.chrom_data,function(ah,ai){return ah.chrom===ae})[0];if(af===undefined){ab.load_chroms({chrom:ae},function(){ab.change_chrom(ae,aa,ag)});return}else{if(ae!==ab.chrom){ab.chrom=ae;ab.chrom_select.val(ab.chrom);ab.max_high=af.len-1;ab.reset();ab.request_redraw(true);for(var ad=0,Z=ab.drawables.length;ad<Z;ad++){var ac=ab.drawables[ad];if(ac.init){ac.init()}}if(ab.reference_track){ab.reference_track.init()}}if(aa!==undefined&&ag!==undefined){ab.low=Math.max(aa,0);ab.high=Math.min(ag,ab.max_high)}else{ab.low=0;ab.high=ab.max_high}ab.reset_overview();ab.request_redraw()}},go_to:function(ad){ad=ad.replace(/ |,/g,"");var ah=this,Z,ac,aa=ad.split(":"),af=aa[0],ag=aa[1];if(ag!==undefined){try{var ae=ag.split("-");Z=parseInt(ae[0],10);ac=parseInt(ae[1],10)}catch(ab){return false}}ah.change_chrom(af,Z,ac)},move_fraction:function(ab){var Z=this;var aa=Z.high-Z.low;this.move_delta(ab*aa)},move_delta:function(ac){var Z=this;var ab=Z.high-Z.low;if(Z.low-ac<Z.max_low){Z.low=Z.max_low;Z.high=Z.max_low+ab}else{if(Z.high-ac>Z.max_high){Z.high=Z.max_high;Z.low=Z.max_high-ab}else{Z.high-=ac;Z.low-=ac}}Z.request_redraw();var aa=Z.chrom_select.val();this.trigger_navigate(aa,Z.low,Z.high,true)},add_drawable:function(Z){w.prototype.add_drawable.call(this,Z);Z.init();this.changed();this.update_intro_div()},add_label_track:function(Z){Z.view=this;Z.init();this.label_tracks.push(Z)},remove_drawable:function(ab,aa){w.prototype.remove_drawable.call(this,ab);if(aa){var Z=this;ab.container_div.hide(0,function(){$(this).remove();Z.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ah,Z,ag,ai){var af=this,ae=(ai?[ai]:af.drawables),ab;var aa;for(var ad=0;ad<ae.length;ad++){aa=ae[ad];ab=-1;for(var ac=0;ac<af.tracks_to_be_redrawn.length;ac++){if(af.tracks_to_be_redrawn[ac][0]===aa){ab=ac;break}}if(ab<0){af.tracks_to_be_redrawn.push([aa,Z,ag])}else{af.tracks_to_be_redrawn[ad][1]=Z;af.tracks_to_be_redrawn[ad][2]=ag}}if(!this.requested_redraw){requestAnimationFrame(function(){af._redraw(ah)});this.requested_redraw=true}},_redraw:function(aj){this.requested_redraw=false;var ag=this.low,ac=this.high;if(ag<this.max_low){ag=this.max_low}if(ac>this.max_high){ac=this.max_high}var ai=this.high-this.low;if(this.high!==0&&ai<this.min_separation){ac=ag+this.min_separation}this.low=Math.floor(ag);this.high=Math.ceil(ac);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var Z=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var af=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ak=13;this.overview_box.css({left:Z,width:Math.max(ak,af)}).show();if(af<ak){this.overview_box.css("left",Z-(ak-af)/2)}if(this.overview_highlight){this.overview_highlight.css({left:Z,width:af})}if(!aj){var ab,aa,ah;for(var ad=0,ae=this.tracks_to_be_redrawn.length;ad<ae;ad++){ab=this.tracks_to_be_redrawn[ad][0];aa=this.tracks_to_be_redrawn[ad][1];ah=this.tracks_to_be_redrawn[ad][2];if(ab){ab._draw(aa,ah)}}this.tracks_to_be_redrawn=[];for(ad=0,ae=this.label_tracks.length;ad<ae;ad++){this.label_tracks[ad]._draw()}}},zoom_in:function(aa,ab){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ac=this.high-this.low,ad=ac/2+this.low,Z=(ac/this.zoom_factor)/2;if(aa){ad=aa/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ad-Z);this.high=Math.round(ad+Z);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var aa=this.high-this.low,ab=aa/2+this.low,Z=(aa*this.zoom_factor)/2;this.low=Math.round(ab-Z);this.high=Math.round(ab+Z);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(ab){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ab.dataset_id){return}this.overview_viewport.find(".track").remove()}var aa=ab.copy({content_div:this.overview_viewport}),Z=this;aa.header_div.hide();aa.is_overview=true;Z.overview_drawable=aa;this.overview_drawable.postdraw_actions=function(){Z.overview_highlight.show().height(Z.overview_drawable.content_div.height());Z.overview_viewport.height(Z.overview_drawable.content_div.height()+Z.overview_box.outerHeight());Z.overview_close.show();Z.resize_window()};Z.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 q=function(ab,ag,ac){this.track=ab;this.name=ag.name;this.params=[];var an=ag.params;for(var ad=0;ad<an.length;ad++){var ai=an[ad],aa=ai.name,am=ai.label,ae=unescape(ai.html),ao=ai.value,ak=ai.type;if(ak==="number"){this.params.push(new e(aa,am,ae,(aa in ac?ac[aa]:ao),ai.min,ai.max))}else{if(ak==="select"){this.params.push(new K(aa,am,ae,(aa in ac?ac[aa]:ao)))}else{console.log("WARNING: unrecognized tool parameter type:",aa,ak)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(aq){aq.stopPropagation()}).click(function(aq){aq.stopPropagation()}).bind("dblclick",function(aq){aq.stopPropagation()});var al=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var aj=this.params;var ah=this;$.each(this.params,function(ar,av){var au=$("<div>").addClass("param-row").appendTo(ah.parent_div);var aq=$("<div>").addClass("param-label").text(av.label).appendTo(au);var at=$("<div/>").addClass("param-input").html(av.html).appendTo(au);at.find(":input").val(av.value);$("<div style='clear: both;'/>").appendTo(au)});this.parent_div.find("input").click(function(){$(this).select()});var ap=$("<div>").addClass("param-row").appendTo(this.parent_div);var af=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(ap);var Z=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(ap);Z.click(function(){ah.run_on_region()});af.click(function(){ah.run_on_dataset()});if("visible" in ac&&ac.visible){this.parent_div.show()}};o(q.prototype,{update_params:function(){for(var Z=0;Z<this.params.length;Z++){this.params[Z].update_value()}},state_dict:function(){var aa={};for(var Z=0;Z<this.params.length;Z++){aa[this.params[Z].name]=this.params[Z].value}aa.visible=this.parent_div.is(":visible");return aa},get_param_values_dict:function(){var Z={};this.parent_div.find(":input").each(function(){var aa=$(this).attr("name"),ab=$(this).val();Z[aa]=ab});return Z},get_param_values:function(){var Z=[];this.parent_div.find(":input").each(function(){var aa=$(this).attr("name"),ab=$(this).val();if(aa){Z[Z.length]=ab}});return Z},run_on_dataset:function(){var Z=this;Z.run({target_dataset_id:this.track.original_dataset_id,tool_id:Z.name},null,function(aa){show_modal(Z.name+" is Running",Z.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var aa={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},ae=this.track,ab=aa.tool_id+ae.tool_region_and_parameters_str(aa.chrom,aa.low,aa.high),Z;if(ae.container===view){var ad=new M(view,view,{name:this.name});var ac=ae.container.replace_drawable(ae,ad,false);ad.container_div.insertBefore(ae.view.content_div.children()[ac]);ad.add_drawable(ae);ae.container_div.appendTo(ad.content_div);Z=ad}else{Z=ae.container}var af=new ae.constructor(view,Z,{name:ab,hda_ldda:"hda"});af.init_for_tool_data();af.change_mode(ae.mode);af.set_filters_manager(ae.filters_manager.copy(af));af.update_icons();Z.add_drawable(af);af.tiles_div.text("Starting job.");this.update_params();this.run(aa,af,function(ag){af.set_dataset(new Dataset(ag));af.tiles_div.text("Running job.");af.init()})},run:function(Z,ab,ac){Z.inputs=this.get_param_values_dict();var aa=new ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(Z),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ad){return ad!=="pending"}});$.when(aa.go()).then(function(ad){if(ad==="no converter"){ab.container_div.addClass("error");ab.content_div.text(G)}else{if(ad.error){ab.container_div.addClass("error");ab.content_div.text(v+ad.message)}else{ac(ad)}}})}});var K=function(aa,Z,ab,ac){this.name=aa;this.label=Z;this.html=$(ab);this.value=ac};o(K.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ab,aa,ad,ae,ac,Z){K.call(this,ab,aa,ad,ae);this.min=ac;this.max=Z};o(e.prototype,K.prototype,{update_value:function(){K.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var f=function(Z){this.manager=null;this.name=Z.name;this.index=Z.index;this.tool_id=Z.tool_id;this.tool_exp_name=Z.tool_exp_name};o(f.prototype,{to_dict:function(){return{name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name}}});var Q=function(ah){f.call(this,ah);this.low=("low" in ah?ah.low:-Number.MAX_VALUE);this.high=("high" in ah?ah.high:Number.MAX_VALUE);this.min=("min" in ah?ah.min:Number.MAX_VALUE);this.max=("max" in ah?ah.max:-Number.MAX_VALUE);this.container=null;this.slider=null;this.slider_label=null;var ad=function(ai,aj,ak){ai.click(function(){var ap=aj.text(),an=parseFloat(ak.slider("option","max")),am=(an<=1?4:an<=1000000?an.toString().length:6),ao=false,al=$(this).parents(".slider-row");al.addClass("input");if(ak.slider("option","values")){am=2*am+1;ao=true}aj.text("");$("<input type='text'/>").attr("size",am).attr("maxlength",am).attr("value",ap).appendTo(aj).focus().select().click(function(aq){aq.stopPropagation()}).blur(function(){$(this).remove();aj.text(ap);al.removeClass("input")}).keyup(function(av){if(av.keyCode===27){$(this).trigger("blur")}else{if(av.keyCode===13){var at=ak.slider("option","min"),aq=ak.slider("option","max"),au=function(aw){return(isNaN(aw)||aw>aq||aw<at)},ar=$(this).val();if(!ao){ar=parseFloat(ar);if(au(ar)){alert("Parameter value must be in the range ["+at+"-"+aq+"]");return $(this)}}else{ar=ar.split("-");ar=[parseFloat(ar[0]),parseFloat(ar[1])];if(au(ar[0])||au(ar[1])){alert("Parameter value must be in the range ["+at+"-"+aq+"]");return $(this)}}ak.slider((ao?"values":"value"),ar);al.removeClass("input")}}})})};var aa=this;aa.parent_div=$("<div/>").addClass("filter-row slider-row");var Z=$("<div/>").addClass("elt-label").appendTo(aa.parent_div),af=$("<span/>").addClass("slider-name").text(aa.name+" ").appendTo(Z),ab=$("<span/>").text(this.low+"-"+this.high),ac=$("<span/>").addClass("slider-value").appendTo(Z).append("[").append(ab).append("]");aa.values_span=ab;var ae=$("<div/>").addClass("slider").appendTo(aa.parent_div);aa.control_element=$("<div/>").attr("id",aa.name+"-filter-control").appendTo(ae);aa.control_element.slider({range:true,min:this.min,max:this.max,step:this.get_slider_step(this.min,this.max),values:[this.low,this.high],slide:function(ai,aj){aa.slide(ai,aj)},change:function(ai,aj){aa.control_element.slider("option","slide").call(aa.control_element,ai,aj)}});aa.slider=aa.control_element;aa.slider_label=ab;ad(ac,ab,aa.control_element);var ag=$("<div/>").addClass("display-controls").appendTo(aa.parent_div);this.transparency_icon=create_action_icon("Use filter for data transparency","layer-transparent",function(){if(aa.manager.alpha_filter!==aa){aa.manager.alpha_filter=aa;aa.manager.parent_div.find(".layer-transparent").removeClass("active").hide();aa.transparency_icon.addClass("active").show()}else{aa.manager.alpha_filter=null;aa.transparency_icon.removeClass("active")}aa.manager.track.request_draw(true,true)}).appendTo(ag).hide();this.height_icon=create_action_icon("Use filter for data height","arrow-resize-090",function(){if(aa.manager.height_filter!==aa){aa.manager.height_filter=aa;aa.manager.parent_div.find(".arrow-resize-090").removeClass("active").hide();aa.height_icon.addClass("active").show()}else{aa.manager.height_filter=null;aa.height_icon.removeClass("active")}aa.manager.track.request_draw(true,true)}).appendTo(ag).hide();aa.parent_div.hover(function(){aa.transparency_icon.show();aa.height_icon.show()},function(){if(aa.manager.alpha_filter!==aa){aa.transparency_icon.hide()}if(aa.manager.height_filter!==aa){aa.height_icon.hide()}});$("<div style='clear: both;'/>").appendTo(aa.parent_div)};o(Q.prototype,{to_dict:function(){var Z=f.prototype.to_dict.call(this);return o(Z,{type:"number",min:this.min,max:this.max,low:this.low,high:this.high})},copy:function(){return new Q({name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name})},get_slider_step:function(ab,Z){var aa=Z-ab;return(aa<=2?0.01:1)},slide:function(ab,ac){var aa=ac.values;this.values_span.text(aa[0]+"-"+aa[1]);this.low=aa[0];this.high=aa[1];var Z=this;setTimeout(function(){if(aa[0]===Z.low&&aa[1]===Z.high){Z.manager.track.request_draw(true,true)}},25)},applies_to:function(Z){if(Z.length>this.index){return true}return false},_keep_val:function(Z){return(isNaN(Z)||(Z>=this.low&&Z<=this.high))},keep:function(aa){if(!this.applies_to(aa)){return true}var ac=this;var ad=aa[this.index];if(ad instanceof Array){var ab=true;for(var Z=0;Z<ad.length;Z++){if(!this._keep_val(ad[Z])){ab=false;break}}return ab}else{return this._keep_val(aa[this.index])}},update_attrs:function(ac){var Z=false;if(!this.applies_to(ac)){return Z}var aa=ac[this.index];if(!(aa instanceof Array)){aa=[aa]}for(var ab=0;ab<aa.length;ab++){var ad=aa[ab];if(ad<this.min){this.min=Math.floor(ad);Z=true}if(ad>this.max){this.max=Math.ceil(ad);Z=true}}return Z},update_ui_elt:function(){if(this.min<this.max){this.parent_div.show()}else{this.parent_div.hide()}var aa=this.slider.slider("option","min"),Z=this.slider.slider("option","max");if(this.min<aa||this.max>Z){this.slider.slider("option","min",this.min);this.slider.slider("option","max",this.max);this.slider.slider("option","step",this.get_slider_step(this.min,this.max));this.slider.slider("option","values",[this.min,this.max])}}});var V=function(ab,ah){this.track=ab;this.alpha_filter=null;this.height_filter=null;this.filters=[];this.parent_div=$("<div/>").addClass("filters").hide();this.parent_div.bind("drag",function(aj){aj.stopPropagation()}).click(function(aj){aj.stopPropagation()}).bind("dblclick",function(aj){aj.stopPropagation()}).bind("keydown",function(aj){aj.stopPropagation()});if(ah&&"filters" in ah){var Z=("alpha_filter" in ah?ah.alpha_filter:null),ac=("height_filter" in ah?ah.height_filter:null),ae=ah.filters,aa;for(var af=0;af<ae.length;af++){if(ae[af].type==="number"){aa=new Q(ae[af]);this.add_filter(aa);if(aa.name===Z){this.alpha_filter=aa;aa.transparency_icon.addClass("active").show()}if(aa.name===ac){this.height_filter=aa;aa.height_icon.addClass("active").show()}}else{console.log("ERROR: unsupported filter: ",name,type)}}if("visible" in ah&&ah.visible){this.parent_div.show()}}if(this.filters.length!==0){var ai=$("<div/>").addClass("param-row").appendTo(this.parent_div);var ag=$("<input type='submit'/>").attr("value","Run on complete dataset").appendTo(ai);var ad=this;ag.click(function(){ad.run_on_dataset()})}};o(V.prototype,{show:function(){this.parent_div.show()},hide:function(){this.parent_div.hide()},toggle:function(){this.parent_div.toggle()},visible:function(){return this.parent_div.is(":visible")},to_dict:function(){var ac={},ab=[],aa;for(var Z=0;Z<this.filters.length;Z++){aa=this.filters[Z];ab.push(aa.to_dict())}ac.filters=ab;ac.alpha_filter=(this.alpha_filter?this.alpha_filter.name:null);ac.height_filter=(this.height_filter?this.height_filter.name:null);ac.visible=this.parent_div.is(":visible");return ac},copy:function(aa){var ab=new V(aa);for(var Z=0;Z<this.filters.length;Z++){ab.add_filter(this.filters[Z].copy())}return ab},add_filter:function(Z){Z.manager=this;this.parent_div.append(Z.parent_div);this.filters.push(Z)},remove_all:function(){this.filters=[];this.parent_div.children().remove()},init_filters:function(){for(var Z=0;Z<this.filters.length;Z++){var aa=this.filters[Z];aa.update_ui_elt()}},clear_filters:function(){for(var Z=0;Z<this.filters.length;Z++){var aa=this.filters[Z];aa.slider.slider("option","values",[aa.min,aa.max])}this.alpha_filter=null;this.height_filter=null;this.parent_div.find(".icon-button").hide()},run_on_dataset:function(){var af=function(aj,ah,ai){if(!(ah in aj)){aj[ah]=ai}return aj[ah]};var ae={},ag,Z;for(var ad=0;ad<this.filters.length;ad++){ag=this.filters[ad];if(ag.tool_id){if(ag.min!==ag.low){Z=af(ae,ag.tool_id,[]);Z[Z.length]=ag.tool_exp_name+" >= "+ag.low}if(ag.max!==ag.high){Z=af(ae,ag.tool_id,[]);Z[Z.length]=ag.tool_exp_name+" <= "+ag.high}}}var aa=[];for(var ac in ae){aa[aa.length]=[ac,ae[ac]]}(function ab(an,ak){var ai=ak[0],aj=ai[0],am=ai[1],al="("+am.join(") and (")+")",ah={cond:al,input:an,target_dataset_id:an,tool_id:aj},ak=ak.slice(1);$.getJSON(run_tool_url,ah,function(ao){if(ao.error){show_modal("Filter Dataset","Error running tool "+aj,{Close:hide_modal})}else{if(ak.length===0){show_modal("Filtering Dataset","Filter(s) are running on the complete dataset. Outputs are in dataset's history.",{Close:hide_modal})}else{ab(ao.dataset_id,ak)}}})})(this.track.dataset_id,aa)}});var z=function(Z,aa){I.Scaler.call(this,aa);this.filter=Z};z.prototype.gen_val=function(Z){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(Z[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var C=function(Z){this.track=Z.track;this.params=Z.params;this.values={};this.restore_values((Z.saved_values?Z.saved_values:{}));this.onchange=Z.onchange};o(C.prototype,{restore_values:function(Z){var aa=this;$.each(this.params,function(ab,ac){if(Z[ac.key]!==undefined){aa.values[ac.key]=Z[ac.key]}else{aa.values[ac.key]=ac.default_value}})},build_form:function(){var ac=this;var Z=$("<div />");var ab;function aa(ah,ad){for(var al=0;al<ah.length;al++){ab=ah[al];if(ab.hidden){continue}var af="param_"+al;var ap=ac.values[ab.key];var ar=$("<div class='form-row' />").appendTo(ad);ar.append($("<label />").attr("for",af).text(ab.label+":"));if(ab.type==="bool"){ar.append($('<input type="checkbox" />').attr("id",af).attr("name",af).attr("checked",ap))}else{if(ab.type==="text"){ar.append($('<input type="text"/>').attr("id",af).val(ap).click(function(){$(this).select()}))}else{if(ab.type==="select"){var an=$("<select />").attr("id",af);for(var aj=0;aj<ab.options.length;aj++){$("<option/>").text(ab.options[aj].label).attr("value",ab.options[aj].value).appendTo(an)}an.val(ap);ar.append(an)}else{if(ab.type==="color"){var aq=$("<div/>").appendTo(ar),am=$("<input />").attr("id",af).attr("name",af).val(ap).css("float","left").appendTo(aq).click(function(au){$(".bs-tooltip").removeClass("in");var at=$(this).siblings(".bs-tooltip").addClass("in");at.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(at).height()/2)+($(this).height()/2)}).show();at.click(function(av){av.stopPropagation()});$(document).bind("click.color-picker",function(){at.hide();$(document).unbind("click.color-picker")});au.stopPropagation()}),ak=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(aq).attr("title","Set new random color").tooltip(),ao=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(aq).hide(),ag=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ao),ae=$("<div class='tooltip-arrow'></div>").appendTo(ao),ai=$.farbtastic(ag,{width:100,height:100,callback:am,color:ap});aq.append($("<div/>").css("clear","both"));(function(at){ak.click(function(){at.setColor(get_random_color())})})(ai)}else{ar.append($("<input />").attr("id",af).attr("name",af).val(ap))}}}}if(ab.help){ar.append($("<div class='help'/>").text(ab.help))}}}aa(this.params,Z);return Z},update_from_form:function(Z){var ab=this;var aa=false;$.each(this.params,function(ac,ae){if(!ae.hidden){var af="param_"+ac;var ad=Z.find("#"+af).val();if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad)}else{if(ae.type==="bool"){ad=Z.find("#"+af).is(":checked")}}}if(ad!==ab.values[ae.key]){ab.values[ae.key]=ad;aa=true}}});if(aa){this.onchange();this.track.changed()}}});var b=function(Z,ad,ab,aa,ac){this.track=Z;this.region=ad;this.low=ad.get("start");this.high=ad.get("end");this.resolution=ab;this.html_elt=$("<div class='track-tile'/>").append(aa).height($(aa).attr("height"));this.data=ac;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(Z,ae,ab,aa,ac,ad){b.call(this,Z,ae,ab,aa,ac);this.max_val=ad};o(j.prototype,b.prototype);var L=function(ac,ak,ad,ab,af,am,ag,an,aa,aj){b.call(this,ac,ak,ad,ab,af);this.mode=ag;this.all_slotted=aa;this.feature_mapper=aj;this.has_icons=false;if(an){this.has_icons=true;var ah=this;ab=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:A-1,width:ab.width}).prependTo(this.html_elt);var ai=new GenomeRegion({chrom:ac.view.chrom,start:this.low,end:this.high}),al=af.length,ae=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+al+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),Z=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+al+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ae.click(function(){ah.stale=true;ac.data_manager.get_more_data(ai,ac.mode,ah.resolution,{},ac.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();ac.request_draw(true)}).dblclick(function(ao){ao.stopPropagation()});Z.click(function(){ah.stale=true;ac.data_manager.get_more_data(ai,ac.mode,ah.resolution,{},ac.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();ac.request_draw(true)}).dblclick(function(ao){ao.stopPropagation()})}};o(L.prototype,b.prototype);L.prototype.predisplay_actions=function(){var aa=this,Z={};if(aa.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(al){if(!this.hovered){return}var ag=$(this).offset(),ak=al.pageX-ag.left,aj=al.pageY-ag.top,ap=aa.feature_mapper.get_feature_data(ak,aj),ah=(ap?ap[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ah||$(this).attr("id")!==ah.toString()){$(this).remove()}});if(ap){var ac=Z[ah];if(!ac){var ah=ap[0],am={name:ap[3],start:ap[1],end:ap[2],strand:ap[4]},af=aa.track.filters_manager.filters,ae;for(var ai=0;ai<af.length;ai++){ae=af[ai];am[ae.name]=ap[ae.index]}var ac=$("<div/>").attr("id",ah).addClass("feature-popup"),aq=$("<table/>"),ao,an,ar;for(ao in am){an=am[ao];ar=$("<tr/>").appendTo(aq);$("<th/>").appendTo(ar).text(ao);$("<td/>").attr("align","left").appendTo(ar).text(typeof(an)==="number"?U(an,2):an)}ac.append($("<div class='feature-popup-inner'>").append(aq));Z[ah]=ac}ac.appendTo($(this).parents(".track-content").children(".overlay"));var ad=ak+parseInt(aa.html_elt.css("left"))-ac.width()/2,ab=aj+parseInt(aa.html_elt.css("top"))+7;ac.css("left",ad+"px").css("top",ab+"px")}else{if(!al.isPropagationStopped()){al.stopPropagation();$(this).siblings().each(function(){$(this).trigger(al)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var h=function(ab,aa,ad){o(ad,{drag_handle_class:"draghandle"});p.call(this,ab,aa,ad);this.data_url=("data_url" in ad?ad.data_url:default_data_url);this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ad?ad.data_query_wait:H);this.dataset_check_url=("converted_datasets_state_url" in ad?ad.converted_datasets_state_url:converted_datasets_state_url);this.feature_search_url=("feature_search_url" in ad?ad.feature_search_url:feature_search_url);var Z=this,ac=new Dataset({id:ad.dataset_id,hda_ldda:ad.hda_ldda});this.data_manager=("data_manager" in ad?ad.data_manager:new GenomeDataManager({dataset:ac,data_url:Z.data_url,dataset_state_url:Z.dataset_check_url,feature_search_url:Z.feature_search_url,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 ad)||ad.resize){this.add_resize_handle()}}};o(h.prototype,p.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},p.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(Z){Z.view.set_overview(Z)}},p.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(Z){if(Z.filters_manager.visible()){Z.filters_manager.clear_filters()}else{Z.filters_manager.init_filters()}Z.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(Z){Z.dynamic_tool_div.toggle();if(Z.dynamic_tool_div.is(":visible")){Z.set_name(Z.name+Z.tool_region_and_parameters_str())}else{Z.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(Z){var ac='<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>',ab=_.template(ac,{track:Z});var ae=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},aa=function(){var ag=$('select[name="regions"] option:selected').val(),ai,af=new GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ah=_.map($(".bookmark"),function(aj){return new GenomeRegion({from_str:$(aj).children(".position").text()})});if(ag==="cur"){ai=[af]}else{if(ag==="bookmarks"){ai=ah}else{ai=[af].concat(ah)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:Z.dataset_id,hda_ldda:Z.hda_ldda,regions:JSON.stringify(new Backbone.Collection(ai).toJSON())})},ad=function(af){if((af.keyCode||af.which)===27){ae()}else{if((af.keyCode||af.which)===13){aa()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ab,{No:ae,Yes:aa})}},p.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&p.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 Z=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(Z)}this.name_div=$("<div/>").addClass("track-name").appendTo(Z).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return Z},on_resize:function(){},add_resize_handle:function(){var Z=this;var ac=false;var ab=false;var aa=$("<div class='track-resize'>");$(Z.container_div).hover(function(){if(Z.content_visible){ac=true;aa.show()}},function(){ac=false;if(!ab){aa.hide()}});aa.hide().bind("dragstart",function(ad,ae){ab=true;ae.original_height=$(Z.content_div).height()}).bind("drag",function(ae,af){var ad=Math.min(Math.max(af.original_height+af.deltaY,Z.min_height_px),Z.max_height_px);$(Z.tiles_div).css("height",ad);Z.visible_height_px=(Z.max_height_px===ad?0:ad);Z.on_resize()}).bind("dragend",function(ad,ae){Z.tile_cache.clear();ab=false;if(!ac){aa.hide()}Z.config.values.height=Z.visible_height_px;Z.changed()}).appendTo(Z.container_div)},set_display_modes:function(ac,af){this.display_modes=ac;this.mode=(af?af:(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 aa=this,ad={};for(var ab=0,Z=aa.display_modes.length;ab<Z;ab++){var ae=aa.display_modes[ab];ad[ae]=function(ag){return function(){aa.change_mode(ag);aa.icons_div.show();aa.container_div.mouseleave(function(){aa.icons_div.hide()})}}(ae)}make_popupmenu(this.action_icons.mode_icon,ad)},build_action_icons:function(){p.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 y){return"ReferenceTrack"}else{if(this instanceof i){return"LineTrack"}else{if(this instanceof R){return"ReadTrack"}else{if(this instanceof O){return"VcfTrack"}else{if(this instanceof g){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(){var aa=this;aa.enabled=false;aa.tile_cache.clear();aa.data_manager.clear();aa.content_div.css("height","auto");aa.tiles_div.children().remove();aa.container_div.removeClass("nodata error pending");if(!aa.dataset_id){return}var Z=$.Deferred();$.getJSON(this.dataset_check_url,{hda_ldda:aa.hda_ldda,dataset_id:aa.dataset_id,chrom:aa.view.chrom},function(ab){if(!ab||ab==="error"||ab.kind==="error"){aa.container_div.addClass("error");aa.tiles_div.text(n);if(ab.message){var ac=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ab.message+"</pre>",{Close:hide_modal})});aa.tiles_div.append(ac)}}else{if(ab==="no converter"){aa.container_div.addClass("error");aa.tiles_div.text(G)}else{if(ab==="no data"||(ab.data!==undefined&&(ab.data===null||ab.data.length===0))){aa.container_div.addClass("nodata");aa.tiles_div.text(B)}else{if(ab==="pending"){aa.container_div.addClass("pending");aa.tiles_div.html(t);setTimeout(function(){aa.init()},aa.data_query_wait)}else{if(ab==="data"||ab.status==="data"){if(ab.valid_chroms){aa.valid_chroms=ab.valid_chroms;aa.update_icons()}aa.tiles_div.text(T);if(aa.view.chrom){aa.tiles_div.text("");aa.tiles_div.css("height",aa.visible_height_px+"px");aa.enabled=true;$.when(aa.predraw_init()).done(function(){Z.resolve();aa.container_div.removeClass("nodata error pending");aa.request_draw()})}else{Z.resolve()}}}}}}});this.update_icons();return Z},predraw_init:function(){},get_drawables:function(){return this}});var J=function(ab,aa,ac){h.call(this,ab,aa,ac);var Z=this;l(Z.container_div,Z.drag_handle_class,".group",Z);this.filters_manager=new V(this,("filters" in ac?ac.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in ac&&ac.tool?new q(this,ac.tool,ac.tool_state):null);this.tile_cache=new Cache(N);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(ac.mode){this.change_mode(ac.mode)}};o(J.prototype,p.prototype,h.prototype,{action_icons_def:h.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(Z){$(".bs-tooltip").remove();Z.slotters[Z.view.resolution_px_b].max_rows*=2;Z.request_draw(true)},hide:true}]),copy:function(Z){var aa=this.to_dict();o(aa,{data_manager:this.data_manager});var ab=new this.constructor(this.view,Z,aa);ab.change_mode(this.mode);ab.enabled=this.enabled;return ab},set_filters_manager:function(Z){this.filters_manager=Z;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(aa){var Z=this;Z.mode=aa;Z.config.values.mode=aa;Z.tile_cache.clear();Z.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+Z.mode+")");return Z},update_icons:function(){var Z=this;if(Z.filters_available){Z.action_icons.filters_icon.show()}else{Z.action_icons.filters_icon.hide()}if(Z.tool){Z.action_icons.tools_icon.show();Z.action_icons.param_space_viz_icon.show()}else{Z.action_icons.tools_icon.hide();Z.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(aa,ab,Z){return aa+"_"+ab+"_"+Z},request_draw:function(aa,Z){this.view.request_redraw(false,aa,Z,this)},before_draw:function(){},_draw:function(aa,ak){if(!this.can_draw()){return}var ai=this.view.low,ae=this.view.high,ag=ae-ai,ab=this.view.container.width(),am=this.view.resolution_px_b,ad=this.view.resolution_b_px;if(this.is_overview){ai=this.view.max_low;ae=this.view.max_high;ad=(view.max_high-view.max_low)/ab;am=1/ad}this.before_draw();this.tiles_div.children().addClass("remove");var Z=Math.floor(ai/(ad*P)),ah=true,al=[],af=function(an){return(an&&"track" in an)};while((Z*P*ad)<ae){var aj=this.draw_helper(aa,ab,Z,ad,this.tiles_div,am);if(af(aj)){al.push(aj)}else{ah=false}Z+=1}if(!ak){this.tiles_div.children(".remove").removeClass("remove").remove()}var ac=this;if(ah){this.tiles_div.children(".remove").remove();ac.postdraw_actions(al,ab,am,ak)}},postdraw_actions:function(ab,ac,ae,Z){var ad=false;for(var aa=0;aa<ab.length;aa++){if(ab[aa].has_icons){ad=true;break}}if(ad){for(var aa=0;aa<ab.length;aa++){tile=ab[aa];if(!tile.has_icons){tile.html_elt.css("padding-top",A)}}}},draw_helper:function(Z,al,aq,ao,ae,af,am){var ak=this,au=this._gen_tile_cache_key(al,af,aq),ac=this._get_tile_bounds(aq,ao);if(!am){am={}}var at=(Z?undefined:ak.tile_cache.get_elt(au));if(at){ak.show_tile(at,ae,af);return at}var ai=true;var ap=ak.data_manager.get_data(ac,ak.mode,ao,ak.data_url_extra_params);if(is_deferred(ap)){ai=false}var ag;if(view.reference_track&&af>view.canvas_manager.char_width_px){ag=view.reference_track.data_manager.get_data(ac,ak.mode,ao,view.reference_track.data_url_extra_params);if(is_deferred(ag)){ai=false}}if(ai){o(ap,am.more_tile_data);var ah=ak.mode;if(ah==="Auto"){ah=ak.get_mode(ap);ak.update_auto_mode(ah)}var ab=ak.view.canvas_manager.new_canvas(),ar=ac.get("start"),aa=ac.get("end"),al=Math.ceil((aa-ar)*af)+ak.left_offset,aj=ak.get_canvas_height(ap,ah,af,al);ab.width=al;ab.height=aj;var an=ab.getContext("2d");an.translate(this.left_offset,0);var at=ak.draw_tile(ap,an,ah,ao,ac,af,ag);if(at!==undefined){ak.tile_cache.set_elt(au,at);ak.show_tile(at,ae,af)}return at}var ad=$.Deferred();$.when(ap,ag).then(function(){view.request_redraw(false,false,false,ak);ad.resolve()});return ad},get_canvas_height:function(Z,ab,ac,aa){return this.visible_height_px},draw_tile:function(Z,aa,ae,ac,ad,af,ab){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ab,ad,ae){var aa=this,Z=ab.html_elt;ab.predisplay_actions();var ac=(ab.low-(this.is_overview?this.view.max_low:this.view.low))*ae;if(this.left_offset){ac-=this.left_offset}Z.css({position:"absolute",top:0,left:ac});if(Z.hasClass("remove")){Z.removeClass("remove")}else{ad.append(Z)}aa.after_show_tile(ab)},after_show_tile:function(Z){this.max_height_px=Math.max(this.max_height_px,Z.html_elt.height());Z.html_elt.parent().children().css("height",this.max_height_px+"px");var aa=this.max_height_px;if(this.visible_height_px!==0){aa=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",aa+"px")},_get_tile_bounds:function(Z,aa){var ac=Math.floor(Z*P*aa),ad=Math.ceil(P*aa),ab=(ac+ad<=this.view.max_high?ac+ad:this.view.max_high);return new GenomeRegion({chrom:this.view.chrom,start:ac,end:ab})},tool_region_and_parameters_str:function(ab,Z,ac){var aa=this,ad=(ab!==undefined&&Z!==undefined&&ac!==undefined?ab+":"+Z+"-"+ac:"all");return" - region=["+ad+"], parameters=["+aa.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(Z,aa){return true},can_subset:function(Z){return false},init_for_tool_data:function(){this.data_manager.set("data_url",raw_data_url);this.data_query_wait=1000;this.dataset_check_url=dataset_state_url;this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ab,ac,ae,Z){var aa=this;aa.normal_postdraw_actions(ab,ac,ae,Z);aa.dataset_state_url=converted_datasets_state_url;aa.data_query_wait=H;var ad=new ServerStateDeferred({url:aa.dataset_state_url,url_params:{dataset_id:aa.dataset_id,hda_ldda:aa.hda_ldda},interval:aa.data_query_wait,success_fn:function(af){return af!=="pending"}});$.when(ad.go()).then(function(){aa.data_manager.set("data_url",default_data_url)});aa.postdraw_actions=aa.normal_postdraw_actions}}});var W=function(aa,Z){var ab={resize:false};h.call(this,aa,Z,ab);this.container_div.addClass("label-track")};o(W.prototype,h.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ab=this.view,ac=ab.high-ab.low,af=Math.floor(Math.pow(10,Math.floor(Math.log(ac)/Math.log(10)))),Z=Math.floor(ab.low/af)*af,ad=this.view.container.width(),aa=$("<div style='position: relative; height: 1.3em;'></div>");while(Z<ab.high){var ae=(Z-ab.low)/ac*ad;aa.append($("<div class='label'>"+commatize(Z)+"</div>").css({position:"absolute",left:ae-1}));Z+=af}this.content_div.children(":first").remove();this.content_div.append(aa)}});var g=function(aa,Z,ad){J.call(this,aa,Z,ad);this.drawables=[];this.left_offset=0;if("drawables" in ad){var ac;for(var ab=0;ab<ad.drawables.length;ab++){ac=ad.drawables[ab];this.drawables[ab]=object_from_template(ac,aa,null);if(ac.left_offset>this.left_offset){this.left_offset=ac.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};o(g.prototype,J.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(Z){$(".bs-tooltip").remove();Z.show_group()}}].concat(J.prototype.action_icons_def),to_dict:w.prototype.to_dict,add_drawable:w.prototype.add_drawable,unpack_drawables:w.prototype.unpack_drawables,change_mode:function(Z){J.prototype.change_mode.call(this,Z);for(var aa=0;aa<this.drawables.length;aa++){this.drawables[aa].change_mode(Z)}},init:function(){var ab=[];for(var aa=0;aa<this.drawables.length;aa++){ab.push(this.drawables[aa].init())}var Z=this;$.when.apply($,ab).then(function(){Z.enabled=true;Z.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:p.prototype.can_draw,draw_helper:function(aa,ap,aw,at,ah,aj,aq){var ao=this,aA=this._gen_tile_cache_key(ap,aj,aw),ae=this._get_tile_bounds(aw,at);if(!aq){aq={}}var az=(aa?undefined:ao.tile_cache.get_elt(aA));if(az){ao.show_tile(az,ah,aj);return az}var ai=[],ao,am=true,au,ak;for(var av=0;av<this.drawables.length;av++){ao=this.drawables[av];au=ao.data_manager.get_data(ae,ao.mode,at,ao.data_url_extra_params);if(is_deferred(au)){am=false}ai.push(au);ak=null;if(view.reference_track&&aj>view.canvas_manager.char_width_px){ak=view.reference_track.data_manager.get_data(ae,ao.mode,at,view.reference_track.data_url_extra_params);if(is_deferred(ak)){am=false}}ai.push(ak)}if(am){o(au,aq.more_tile_data);this.tile_predraw_init();var ad=ao.view.canvas_manager.new_canvas(),af=ao._get_tile_bounds(aw,at),ax=ae.get("start"),ab=ae.get("end"),ay=0,ap=Math.ceil((ab-ax)*aj)+this.left_offset,an=0,ac=[],av;var Z=0;for(av=0;av<this.drawables.length;av++,ay+=2){ao=this.drawables[av];au=ai[ay];var al=ao.mode;if(al==="Auto"){al=ao.get_mode(au);ao.update_auto_mode(al)}ac.push(al);Z=ao.get_canvas_height(au,al,aj,ap);if(Z>an){an=Z}}ad.width=ap;ad.height=(aq.height?aq.height:an);ay=0;var ar=ad.getContext("2d");ar.translate(this.left_offset,0);ar.globalAlpha=0.5;ar.globalCompositeOperation="source-over";for(av=0;av<this.drawables.length;av++,ay+=2){ao=this.drawables[av];au=ai[ay];ak=ai[ay+1];az=ao.draw_tile(au,ar,ac[av],at,ae,aj,ak)}this.tile_cache.set_elt(aA,az);this.show_tile(az,ah,aj);return az}var ag=$.Deferred(),ao=this;$.when.apply($,ai).then(function(){view.request_redraw(false,false,false,ao);ag.resolve()});return ag},show_group:function(){var ac=new M(this.view,this.container,{name:this.name}),Z;for(var ab=0;ab<this.drawables.length;ab++){Z=this.drawables[ab];Z.update_icons();ac.add_drawable(Z);Z.container=ac;ac.content_div.append(Z.container_div)}var aa=this.container.replace_drawable(this,ac,true);ac.request_draw()},tile_predraw_init:function(){var ac=Number.MAX_VALUE,Z=-ac,aa;for(var ab=0;ab<this.drawables.length;ab++){aa=this.drawables[ab];if(aa instanceof i){if(aa.prefs.min_value<ac){ac=aa.prefs.min_value}if(aa.prefs.max_value>Z){Z=aa.prefs.max_value}}}for(var ab=0;ab<this.drawables.length;ab++){aa=this.drawables[ab];aa.prefs.min_value=ac;aa.prefs.max_value=Z}},postdraw_actions:function(ab,ae,ag,aa){J.prototype.postdraw_actions.call(this,ab,ae,ag,aa);var ad=-1;for(var ac=0;ac<ab.length;ac++){var Z=ab[ac].html_elt.find("canvas").height();if(Z>ad){ad=Z}}for(var ac=0;ac<ab.length;ac++){var af=ab[ac];if(af.html_elt.find("canvas").height()!==ad){this.draw_helper(true,ae,af.index,af.resolution,af.html_elt.parent(),ag,{height:ad});af.html_elt.remove()}}}});var y=function(Z){J.call(this,Z,{content_div:Z.top_labeltrack},{resize:false});Z.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=reference_url;this.data_url_extra_params={dbkey:Z.dbkey};this.data_manager=new ReferenceTrackDataManager({data_url:reference_url});this.hide_contents()};o(y.prototype,p.prototype,J.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:p.prototype.can_draw,draw_helper:function(ad,ab,Z,aa,ae,af,ac){if(af>this.view.canvas_manager.char_width_px){return J.prototype.draw_helper.call(this,ad,ab,Z,aa,ae,af,ac)}else{this.hide_contents();return null}},draw_tile:function(ah,ai,ad,ac,af,aj){var ab=this;if(aj>this.view.canvas_manager.char_width_px){if(ah.data===null){this.hide_contents();return}var aa=ai.canvas;ai.font=ai.canvas.manager.default_font;ai.textAlign="center";ah=ah.data;for(var ae=0,ag=ah.length;ae<ag;ae++){var Z=Math.floor(ae*aj);ai.fillText(ah[ae],Z,10)}this.show_contents();return new b(ab,af,ac,aa,ah)}this.hide_contents()}});var i=function(ab,aa,ac){var Z=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";J.call(this,ab,aa,ac);this.hda_ldda=ac.hda_ldda;this.dataset_id=ac.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value: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:ac.prefs,onchange:function(){Z.set_name(Z.prefs.name);Z.vertical_range=Z.prefs.max_value-Z.prefs.min_value;Z.set_min_value(Z.prefs.min_value);Z.set_max_value(Z.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};o(i.prototype,p.prototype,J.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(Z){this.prefs.min_value=Z;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(Z){this.prefs.max_value=Z;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var Z=this;Z.vertical_range=undefined;return $.getJSON(Z.data_url,{stats:true,chrom:Z.view.chrom,low:0,high:Z.view.max_high,hda_ldda:Z.hda_ldda,dataset_id:Z.dataset_id},function(aa){Z.container_div.addClass("line-track");var ad=aa.data;if(isNaN(parseFloat(Z.prefs.min_value))||isNaN(parseFloat(Z.prefs.max_value))){var ab=ad.min,af=ad.max;ab=Math.floor(Math.min(0,Math.max(ab,ad.mean-2*ad.sd)));af=Math.ceil(Math.max(0,Math.min(af,ad.mean+2*ad.sd)));Z.prefs.min_value=ab;Z.prefs.max_value=af;$("#track_"+Z.dataset_id+"_minval").val(Z.prefs.min_value);$("#track_"+Z.dataset_id+"_maxval").val(Z.prefs.max_value)}Z.vertical_range=Z.prefs.max_value-Z.prefs.min_value;Z.total_frequency=ad.total_frequency;Z.container_div.find(".yaxislabel").remove();var ae=$("<div/>").text(U(Z.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(ag){$(".bs-tooltip").remove();var ag=parseFloat(ag);if(!isNaN(ag)){Z.set_min_value(ag)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+Z.dataset_id+"_minval").prependTo(Z.container_div),ac=$("<div/>").text(U(Z.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(ag){$(".bs-tooltip").remove();var ag=parseFloat(ag);if(!isNaN(ag)){Z.set_max_value(ag)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+Z.dataset_id+"_maxval").prependTo(Z.container_div)})},draw_tile:function(ai,ag,ab,aa,ad,ah){var Z=ag.canvas,ac=ad.get("start"),af=ad.get("end"),ae=new I.LinePainter(ai.data,ac,af,this.prefs,ab);ae.draw(ag,Z.width,Z.height,ah);return new b(this,ad,aa,Z,ai.data)},can_subset:function(Z){return false}});var r=function(ab,aa,ac){var Z=this;this.display_modes=["Heatmap"];this.mode="Heatmap";J.call(this,ab,aa,ac);this.hda_ldda=ac.hda_ldda;this.dataset_id=ac.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{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:ac.prefs,onchange:function(){Z.set_name(Z.prefs.name);Z.vertical_range=Z.prefs.max_value-Z.prefs.min_value;Z.set_min_value(Z.prefs.min_value);Z.set_max_value(Z.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};o(r.prototype,p.prototype,J.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(Z){this.prefs.min_value=Z;this.tile_cache.clear();this.request_draw()},set_max_value:function(Z){this.prefs.max_value=Z;this.tile_cache.clear();this.request_draw()},draw_tile:function(aj,ah,ae,ac,aa,ai){var ab=ah.canvas,Z=this._get_tile_bounds(aa,ac),ad=Z[0],ag=Z[1],af=new I.DiagonalHeatmapPainter(aj.data,ad,ag,this.prefs,ae);af.draw(ah,ab.width,ab.height,ai);return new b(this,aa,ac,ab,aj.data)}});var c=function(ac,ab,ae){var aa=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];J.call(this,ac,ab,ae);var ad=get_random_color(),Z=get_random_color([ad,"#ffffff"]);this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ad},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:Z},{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:"histogram_max",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:ae.prefs,onchange:function(){aa.set_name(aa.prefs.name);aa.tile_cache.clear();aa.set_painter_from_config();aa.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ae.hda_ldda;this.dataset_id=ae.dataset_id;this.original_dataset_id=ae.dataset_id;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()};o(c.prototype,p.prototype,J.prototype,{set_dataset:function(Z){this.dataset_id=Z.get("id");this.hda_ldda=Z.get("hda_ldda");this.data_manager.set("dataset",Z)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=I.ArcLinkedFeaturePainter}else{this.painter=I.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ao,aj,ae,ad){J.prototype.postdraw_actions.call(this,ao,ad);var ai=this,al;if(ai.mode==="Coverage"){var aa=-1;for(al=0;al<ao.length;al++){var ak=ao[al].max_val;if(ak>aa){aa=ak}}for(al=0;al<ao.length;al++){var aq=ao[al];if(aq.max_val!==aa){aq.html_elt.remove();ai.draw_helper(true,aj,aq.index,aq.resolution,aq.html_elt.parent(),ae,{more_tile_data:{max:aa}})}}}if(ai.filters_manager){var af=ai.filters_manager.filters;for(var an=0;an<af.length;an++){af[an].update_ui_elt()}var ap=false,Z,ag;for(al=0;al<ao.length;al++){if(ao[al].data.length){Z=ao[al].data[0];for(var an=0;an<af.length;an++){ag=af[an];if(ag.applies_to(Z)&&ag.min!==ag.max){ap=true;break}}}}if(ai.filters_available!==ap){ai.filters_available=ap;if(!ai.filters_available){ai.filters_manager.hide()}ai.update_icons()}}this.container_div.find(".yaxislabel").remove();var ac=ao[0];if(ac instanceof j){var ah=(this.prefs.histogram_max?this.prefs.histogram_max:ac.max_val),ab=$("<div/>").text(ah).make_text_editable({num_cols:12,on_finish:function(ar){$(".bs-tooltip").remove();var ar=parseFloat(ar);ai.prefs.histogram_max=(!isNaN(ar)?ar:null);ai.tile_cache.clear();ai.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ab)}if(ac instanceof L){var am=true;for(al=0;al<ao.length;al++){if(!ao[al].all_slotted){am=false;break}}if(!am){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(Z){var Z;if(this.mode==="Auto"){if(Z==="no_detail"){Z="feature spans"}else{if(Z==="summary_tree"){Z="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+Z+")")}},incremental_slots:function(ad,Z,ac){var aa=this.view.canvas_manager.dummy_context,ab=this.slotters[ad];if(!ab||(ab.mode!==ac)){ab=new (s.FeatureSlotter)(ad,ac,x,function(ae){return aa.measureText(ae)});this.slotters[ad]=ab}return ab.slot_features(Z)},get_mode:function(Z){if(Z.dataset_type==="summary_tree"){mode="summary_tree"}else{if(Z.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>F){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(Z,ad,ae,aa){if(ad==="summary_tree"||ad==="Coverage"){return this.summary_draw_height}else{var ac=this.incremental_slots(ae,Z.data,ad);var ab=new (this.painter)(null,null,null,this.prefs,ad);return Math.max(Y,ab.get_required_height(ac,aa))}},draw_tile:function(aj,an,al,ao,ac,ag,ab){var am=this,aa=an.canvas,av=ac.get("start"),Z=ac.get("end"),ad=this.left_offset;if(al==="summary_tree"||al==="Coverage"){var ax=new I.SummaryTreePainter(aj,av,Z,this.prefs);ax.draw(an,aa.width,aa.height,ag);return new j(am,ac,ao,aa,aj.data,aj.max)}var af=[],ak=this.slotters[ag].slots;all_slotted=true;if(aj.data){var ah=this.filters_manager.filters;for(var ap=0,ar=aj.data.length;ap<ar;ap++){var ae=aj.data[ap];var aq=false;var ai;for(var au=0,az=ah.length;au<az;au++){ai=ah[au];ai.update_attrs(ae);if(!ai.keep(ae)){aq=true;break}}if(!aq){af.push(ae);if(!(ae[0] in ak)){all_slotted=false}}}}var ay=(this.filters_manager.alpha_filter?new z(this.filters_manager.alpha_filter):null);var aw=(this.filters_manager.height_filter?new z(this.filters_manager.height_filter):null);var ax=new (this.painter)(af,av,Z,this.prefs,al,ay,aw,ab);var at=null;an.fillStyle=this.prefs.block_color;an.font=an.canvas.manager.default_font;an.textAlign="right";if(aj.data){at=ax.draw(an,aa.width,aa.height,ag,ak);at.translation=-ad}return new L(am,ac,ao,aa,aj.data,ag,al,aj.message,all_slotted,at)},data_and_mode_compatible:function(Z,aa){if(aa==="Auto"){return true}else{if(aa==="Coverage"){return Z.dataset_type==="summary_tree"}else{if(Z.extra_info==="no_detail"||Z.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(Z){if(Z.dataset_type==="summary_tree"||Z.message||Z.extra_info==="no_detail"){return false}return true}});var O=function(aa,Z,ab){c.call(this,aa,Z,ab);this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ab.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=I.ReadPainter};o(O.prototype,p.prototype,J.prototype,c.prototype);var R=function(ab,aa,ad){c.call(this,ab,aa,ad);var ac=get_random_color(),Z=get_random_color([ac,"#ffffff"]);this.config=new C({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:ac},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:Z},{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:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ad.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=I.ReadPainter;this.update_icons()};o(R.prototype,p.prototype,J.prototype,c.prototype);S.View=X;S.DrawableGroup=M;S.LineTrack=i;S.FeatureTrack=c;S.DiagonalHeatmapTrack=r;S.ReadTrack=R;S.VcfTrack=O;S.CompositeTrack=g};var slotting_module=function(c,b){var e=c("class").extend;var d=2,a=5;b.FeatureSlotter=function(i,h,f,g){this.slots={};this.start_end_dct={};this.w_scale=i;this.mode=h;this.include_label=(h==="Pack");this.max_rows=f;this.measureText=g};e(b.FeatureSlotter.prototype,{slot_features:function(m){var p=this.w_scale,h=this.start_end_dct,x=[],z=[],n=0,y=this.max_rows;for(var v=0,w=m.length;v<w;v++){var k=m[v],o=k[0];if(this.slots[o]!==undefined){n=Math.max(n,this.slots[o]);z.push(this.slots[o])}else{x.push(v)}}var q=function(E,F){for(var D=0;D<=y;D++){var B=false,G=h[D];if(G!==undefined){for(var A=0,C=G.length;A<C;A++){var i=G[A];if(F>i[0]&&E<i[1]){B=true;break}}}if(!B){return D}}return -1};for(var v=0,w=x.length;v<w;v++){var k=m[x[v]],o=k[0],t=k[1],f=k[2],r=k[3],g=Math.floor(t*p),l=Math.ceil(f*p),u=this.measureText(r).width,j;if(r!==undefined&&this.include_label){u+=(d+a);if(g-u>=0){g-=u;j="left"}else{l+=u;j="right"}}var s=q(g,l);if(s>=0){if(h[s]===undefined){h[s]=[]}h[s].push([g,l]);this.slots[o]=s;n=Math.max(n,s)}}return n+1}})};var painters_module=function(require,exports){var extend=require("class").extend;var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var SummaryTreePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode)};SummaryTreePainter.prototype.default_prefs={show_counts:false};SummaryTreePainter.prototype.draw=function(ctx,width,height,w_scale){var view_start=this.view_start,points=this.data.data,max=(this.prefs.histogram_max?this.prefs.histogram_max:this.data.max),base_y=height;delta_x_px=Math.ceil(this.data.delta*w_scale);ctx.save();for(var i=0,len=points.length;i<len;i++){var x=Math.floor((points[i][0]-view_start)*w_scale);var y=points[i][1];if(!y){continue}var y_px=y/max*height;if(y!==0&&y_px<1){y_px=1}ctx.fillStyle=this.prefs.block_color;ctx.fillRect(x,base_y-y_px,delta_x_px,y_px);var text_padding_req_x=4;if(this.prefs.show_counts&&(ctx.measureText(y).width+text_padding_req_x)<delta_x_px){ctx.fillStyle=this.prefs.label_color;ctx.textAlign="center";ctx.fillText(y,x+(delta_x_px/2),10)}}ctx.restore()};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][1])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][1])}this.prefs.max_value=max_value}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var pref_color=parseInt(this.prefs.color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=this.prefs.color;x_scaled=Math.round((data[i][0]-view_start-1)*w_scale);y=data[i][1];var top_overflow=false,bot_overflow=false;if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=this.prefs.color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler())};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)+this.get_bottom_padding(width)},get_top_padding:function(width){return 0},get_bottom_padding:function(width){return Math.max(Math.round(this.get_row_height()/2),5)},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords;for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((feature_start<view_end&&feature_end>view_start)&&(this.mode==="Dense"||slot!==null)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1])}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return feature_mapper},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){console.log("WARNING: Unimplemented function.");return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2]-1,feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low)*w_scale))),draw_start=f_start,draw_end=f_end,y_center=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_center+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_center+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_center+1,f_end-f_start,thick_height)}}else{var cur_y_center,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_center=y_center+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_center=y_center;cur_height=thick_height}else{cur_y_center+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_center,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-1-tile_low)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_center+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_center+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_center+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_center)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_center+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_center+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_center+8);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_center+8);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null)};extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},draw_read:function(ctx,mode,w_scale,y_center,tile_low,tile_high,feature_start,cigar,strand,orig_seq){ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=0,char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.block_color:this.prefs.reverse_strand_color);var draw_last=[];if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){gap=Math.round(w_scale/2)}if(!cigar){cigar=[[0,orig_seq.length]]}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];if(cig_op==="H"||cig_op==="S"){base_offset-=cig_len}var seq_start=(feature_start-1)+base_offset,s_start=Math.floor(Math.max(0,(seq_start-tile_low)*w_scale)),s_end=Math.floor(Math.max(0,(seq_start+cig_len-tile_low)*w_scale));if(s_start===s_end){s_end+=1}switch(cig_op){case"H":break;case"S":case"M":case"=":if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=orig_seq.slice(seq_offset,seq_offset+cig_len);if(gap>0){ctx.fillStyle=block_color;ctx.fillRect(s_start-gap,y_center+1,s_end-s_start,9);ctx.fillStyle=CONNECTOR_COLOR;for(var c=0,str_len=seq.length;c<str_len;c++){if(this.prefs.show_differences){if(this.ref_seq){var ref_char=this.ref_seq[seq_start-tile_low+c];if(!ref_char||ref_char.toLowerCase()===seq[c].toLowerCase()){continue}}else{continue}}if(seq_start+c>=tile_low&&seq_start+c<=tile_high){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start,y_center+9)}}}else{ctx.fillStyle=block_color;ctx.fillRect(s_start,y_center+4,s_end-s_start,SQUISH_FEATURE_HEIGHT)}}seq_offset+=cig_len;base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start-gap,y_center+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":ctx.fillStyle="red";ctx.fillRect(s_start-gap,y_center+4,s_end-s_start,3);base_offset+=cig_len;break;case"P":break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=orig_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_center-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_center+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_center)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_center+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_center+9]})}else{}}}seq_offset+=cig_len;break;case"X":seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(0,(feature_start-tile_low)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low)*w_scale))),y_center=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color,gap=0;if((mode==="Pack"||this.mode==="Auto")&&w_scale>ctx.canvas.manager.char_width_px){var gap=Math.round(w_scale/2)}if(feature[5] instanceof Array){var b1_start=Math.floor(Math.max(0,(feature[4][0]-tile_low)*w_scale)),b1_end=Math.ceil(Math.min(width,Math.max(0,(feature[4][1]-tile_low)*w_scale))),b2_start=Math.floor(Math.max(0,(feature[5][0]-tile_low)*w_scale)),b2_end=Math.ceil(Math.min(width,Math.max(0,(feature[5][1]-tile_low)*w_scale))),connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end-gap,y_center+5,b2_start-gap,y_center+5)}}else{this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;var tile_index=1;if(tile_index===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING-gap,y_center+8)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING-gap,y_center+8)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_center){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_center,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"4169E1",neg_color:"FF8C00"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};exports.Scaler=Scaler;exports.SummaryTreePainter=SummaryTreePainter;exports.LinePainter=LinePainter;exports.LinkedFeaturePainter=LinkedFeaturePainter;exports.ReadPainter=ReadPainter;exports.ArcLinkedFeaturePainter=ArcLinkedFeaturePainter;exports.DiagonalHeatmapPainter=DiagonalHeatmapPainter};(function(d){var c={};var b=function(e){return c[e]};var a=function(f,g){var e={};g(b,e);c[f]=e};a("class",class_module);a("slotting",slotting_module);a("painters",painters_module);a("trackster",trackster_module);for(key in c.trackster){d[key]=c.trackster[key]}})(window);
\ No newline at end of file
+var class_module=function(b,a){var c=function(){var g=arguments[0];for(var f=1;f<arguments.length;f++){var d=arguments[f];for(var e in d){g[e]=d[e]}}return g};a.extend=c};var requestAnimationFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(b,a){window.setTimeout(b,1000/60)}})();var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(e,b){var g=e[0],f=e[1],d=b[0],c=b[1],a;if(g<d){if(f<d){a=BEFORE}else{if(f<=c){a=OVERLAP_START}else{a=CONTAINS}}}else{if(g>c){a=AFTER}else{if(f<=c){a=CONTAINED_BY}else{a=OVERLAP_END}}}return a};var is_overlap=function(c,b){var a=compute_overlap(c,b);return(a!==BEFORE&&a!==AFTER)};var is_deferred=function(a){return("isResolved" in a)};var get_random_color=function(a){if(!a){a="#ffffff"}if(typeof(a)==="string"){a=[a]}for(var j=0;j<a.length;j++){a[j]=parseInt(a[j].slice(1),16)}var n=function(t,s,i){return((t*299)+(s*587)+(i*114))/1000};var e=function(v,u,w,s,i,t){return(Math.max(v,s)-Math.min(v,s))+(Math.max(u,i)-Math.min(u,i))+(Math.max(w,t)-Math.min(w,t))};var g,o,f,k,q,h,r,c,d,b,p,m=false,l=0;do{g=Math.round(Math.random()*16777215);o=(g&16711680)>>16;f=(g&65280)>>8;k=g&255;d=n(o,f,k);m=true;for(j=0;j<a.length;j++){q=a[j];h=(q&16711680)>>16;r=(q&65280)>>8;c=q&255;b=n(h,r,c);p=e(o,f,k,h,r,c);if((Math.abs(d-b)<40)||(p<200)){m=false;break}}l++}while(!m&&l<=10);return"#"+(16777216+g).toString(16).substr(1,6)};var create_action_icon=function(c,b,a){return $("<a/>").attr("href","javascript:void(0);").attr("title",c).addClass("icon-button").addClass(b).tooltip().click(a)};var trackster_module=function(d,S){var o=d("class").extend,s=d("slotting"),I=d("painters");var m={};var k=function(Z,aa){m[Z.attr("id")]=aa};var l=function(Z,ab,ad,ac){ad=".group";var aa={};m[Z.attr("id")]=ac;Z.bind("drag",{handle:"."+ab,relative:true},function(al,am){var ak=$(this),ap=$(this).parent(),ah=ap.children(),aj=m[$(this).attr("id")],ag,af,an,ae,ai;af=$(this).parents(ad);if(af.length!==0){an=af.position().top;ae=an+af.outerHeight();if(am.offsetY<an){$(this).insertBefore(af);var ao=m[af.attr("id")];ao.remove_drawable(aj);ao.container.add_drawable_before(aj,ao);return}else{if(am.offsetY>ae){$(this).insertAfter(af);var ao=m[af.attr("id")];ao.remove_drawable(aj);ao.container.add_drawable(aj);return}}}af=null;for(ai=0;ai<ah.length;ai++){ag=$(ah.get(ai));an=ag.position().top;ae=an+ag.outerHeight();if(ag.is(ad)&&this!==ag.get(0)&&am.offsetY>=an&&am.offsetY<=ae){if(am.offsetY-an<ae-am.offsetY){ag.find(".content-div").prepend(this)}else{ag.find(".content-div").append(this)}if(aj.container){aj.container.remove_drawable(aj)}m[ag.attr("id")].add_drawable(aj);return}}for(ai=0;ai<ah.length;ai++){ag=$(ah.get(ai));if(am.offsetY<ag.position().top&&!(ag.hasClass("reference-track")||ag.hasClass("intro"))){break}}if(ai===ah.length){if(this!==ah.get(ai-1)){ap.append(this);m[ap.attr("id")].move_drawable(aj,ai)}}else{if(this!==ah.get(ai)){$(this).insertBefore(ah.get(ai));m[ap.attr("id")].move_drawable(aj,(am.deltaY>0?ai-1:ai))}}}).bind("dragstart",function(){aa["border-top"]=Z.css("border-top");aa["border-bottom"]=Z.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(aa)})};S.moveable=l;var Y=16,D=9,A=20,x=100,F=12000,P=400,H=5000,u=100,n="There was an error in indexing this dataset. ",G="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",B="No data for this chrom/contig.",t="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",v="Tool cannot be rerun: ",a="Loading data...",T="Ready for display",N=10,E=20;function U(aa,Z){if(!Z){Z=0}var ab=Math.pow(10,Z);return Math.round(aa*ab)/ab}var p=function(aa,Z,ac){if(!p.id_counter){p.id_counter=0}this.id=p.id_counter++;this.name=ac.name;this.view=aa;this.container=Z;this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:ac.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=ac.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(ad){ad.stopPropagation()});var ab=this;this.container_div.hover(function(){ab.icons_div.show()},function(){ab.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};p.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(Z){if(Z.content_visible){Z.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");Z.hide_contents();Z.content_visible=false}else{Z.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");Z.content_visible=true;Z.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(aa){var ac=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},Z=function(){aa.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ab=function(ad){if((ad.keyCode||ad.which)===27){ac()}else{if((ad.keyCode||ad.which)===13){Z()}}};$(window).bind("keypress.check_enter_esc",ab);show_modal("Configure",aa.config.build_form(),{Cancel:ac,OK:Z})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(Z){$(".bs-tooltip").remove();Z.remove()}}];o(p.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(){},to_dict:function(){},set_name:function(Z){this.old_name=this.name;this.name=Z;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 Z=this.view;this.container_div.hide(0,function(){$(this).remove();Z.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(aa,af,ae,ad,Z,ac){var ab=this;this.action_icons[aa]=$("<a/>").attr("href","javascript:void(0);").attr("title",af).addClass("icon-button").addClass(ae).tooltip().click(function(){ad(ab)}).appendTo(this.icons_div);if(ac){this.action_icons[aa].hide()}},build_action_icons:function(Z){var ab;for(var aa=0;aa<Z.length;aa++){ab=Z[aa];this.add_action_icon(ab.name,ab.title,ab.css_class,ab.on_click_fn,ab.prepend,ab.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var w=function(aa,Z,ab){p.call(this,aa,Z,ab);this.obj_type=ab.obj_type;this.drawables=[]};o(w.prototype,p.prototype,{unpack_drawables:function(ab){this.drawables=[];var aa;for(var Z=0;Z<ab.length;Z++){aa=object_from_template(ab[Z],this.view,this);this.add_drawable(aa)}},init:function(){for(var Z=0;Z<this.drawables.length;Z++){this.drawables[Z].init()}},_draw:function(){for(var Z=0;Z<this.drawables.length;Z++){this.drawables[Z]._draw()}},to_dict:function(){var aa=[];for(var Z=0;Z<this.drawables.length;Z++){aa.push(this.drawables[Z].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:aa}},add_drawable:function(Z){this.drawables.push(Z);Z.container=this;this.changed()},add_drawable_before:function(ab,Z){this.changed();var aa=this.drawables.indexOf(Z);if(aa!==-1){this.drawables.splice(aa,0,ab);return true}return false},replace_drawable:function(ab,Z,aa){var ac=this.drawables.indexOf(ab);if(ac!==-1){this.drawables[ac]=Z;if(aa){ab.container_div.replaceWith(Z.container_div)}this.changed()}return ac},remove_drawable:function(aa){var Z=this.drawables.indexOf(aa);if(Z!==-1){this.drawables.splice(Z,1);aa.container=null;this.changed();return true}return false},move_drawable:function(aa,ab){var Z=this.drawables.indexOf(aa);if(Z!==-1){this.drawables.splice(Z,1);this.drawables.splice(ab,0,aa);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var M=function(aa,Z,ac){o(ac,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});w.call(this,aa,Z,ac);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);l(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new V(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ac){this.unpack_drawables(ac.drawables)}if("filters" in ac){var ab=this.filters_manager;this.filters_manager=new V(this,ac.filters);ab.parent_div.replaceWith(this.filters_manager.parent_div);if(ac.filters.visible){this.setup_multitrack_filtering()}}};o(M.prototype,p.prototype,w.prototype,{action_icons_def:[p.prototype.action_icons_def[0],p.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(Z){$(".bs-tooltip").remove();Z.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(Z){if(Z.filters_manager.visible()){Z.filters_manager.clear_filters();Z._restore_filter_managers()}else{Z.setup_multitrack_filtering();Z.request_draw(true)}Z.filters_manager.toggle()}},p.prototype.action_icons_def[2]],build_container_div:function(){var Z=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(Z)}return Z},build_header_div:function(){var Z=$("<div/>").addClass("track-header");Z.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(Z);return Z},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ab=this.drawables.length;if(ab===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ab===1){if(this.drawables[0] instanceof g){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var ai,ah,af,al=true,ad=this.drawables[0].get_type(),Z=0;for(ai=0;ai<ab;ai++){af=this.drawables[ai];if(af.get_type()!==ad){can_composite=false;break}if(af instanceof c){Z++}}if(al||Z===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(Z>1&&Z===this.drawables.length){var am={},aa;af=this.drawables[0];for(ah=0;ah<af.filters_manager.filters.length;ah++){aa=af.filters_manager.filters[ah];am[aa.name]=[aa]}for(ai=1;ai<this.drawables.length;ai++){af=this.drawables[ai];for(ah=0;ah<af.filters_manager.filters.length;ah++){aa=af.filters_manager.filters[ah];if(aa.name in am){am[aa.name].push(aa)}}}this.filters_manager.remove_all();var ac,ae,ag,aj;for(var ak in am){ac=am[ak];if(ac.length===Z){ae=new Q({name:ac[0].name,index:ac[0].index});this.filters_manager.add_filter(ae)}}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 Z=0;Z<this.drawables.length;Z++){this.drawables[Z].filters_manager=this.saved_filters_managers[Z]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var Z=0;Z<this.drawables.length;Z++){drawable=this.drawables[Z];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=[];for(var aa=0;aa<this.drawables.length;aa++){ad.push(this.drawables[aa].name)}var ab="Composite Track of "+this.drawables.length+" tracks ("+ad.join(", ")+")";var ac=new g(this.view,this.view,{name:ab,drawables:this.drawables});var Z=this.container.replace_drawable(this,ac,true);ac.request_draw()},add_drawable:function(Z){w.prototype.add_drawable.call(this,Z);this.update_icons()},remove_drawable:function(Z){w.prototype.remove_drawable.call(this,Z);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var Z=o(w.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return Z},request_draw:function(Z,ab){for(var aa=0;aa<this.drawables.length;aa++){this.drawables[aa].request_draw(Z,ab)}}});var X=function(Z){o(Z,{obj_type:"View"});w.call(this,"View",Z.container,Z);this.chrom=null;this.vis_id=Z.vis_id;this.dbkey=Z.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.init();this.canvas_manager=new CanvasManager(this.container.get(0).ownerDocument);this.reset()};_.extend(X.prototype,Backbone.Events);o(X.prototype,w.prototype,{init:function(){this.requested_redraw=false;var ab=this.container,Z=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ab);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ab);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ab);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;k(this.viewport_container,Z);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ac=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){add_datasets(add_datasets_url,add_track_async_url,function(ad){_.each(ad,function(ae){Z.add_drawable(object_from_template(ae,Z,Z))})})});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 aa=function(ad){if(ad.type==="focusout"||(ad.keyCode||ad.which)===13||(ad.keyCode||ad.which)===27){if((ad.keyCode||ad.which)!==27){Z.go_to($(this).val())}$(this).hide();$(this).val("");Z.location_span.show();Z.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",aa).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(){Z.location_span.hide();Z.chrom_select.hide();Z.nav_input.val(Z.chrom+":"+Z.low+"-"+Z.high);Z.nav_input.css("display","inline-block");Z.nav_input.select();Z.nav_input.focus();Z.nav_input.autocomplete({source:function(af,ad){var ag=[],ae=$.map(Z.get_drawables(),function(ah){return ah.data_manager.search_features(af.term).success(function(ai){ag=ag.concat(ai)})});$.when.apply($,ae).done(function(){ad($.map(ag,function(ah){return{label:ah[0],value:ah[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(){Z.zoom_out();Z.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){Z.zoom_in();Z.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){Z.change_chrom(Z.chrom_select.val())});this.browser_content_div.click(function(ad){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ad){Z.zoom_in(ad.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ad,ae){this.current_x=ae.offsetX}).bind("drag",function(ad,af){var ag=af.offsetX-this.current_x;this.current_x=af.offsetX;var ae=Math.round(ag/Z.viewport_container.width()*(Z.max_high-Z.max_low));Z.move_delta(-ae)});this.overview_close.click(function(){Z.reset_overview()});this.viewport_container.bind("draginit",function(ad,ae){if(ad.clientX>Z.viewport_container.width()-16){return false}}).bind("dragstart",function(ad,ae){ae.original_low=Z.low;ae.current_height=ad.clientY;ae.current_x=ae.offsetX}).bind("drag",function(af,ah){var ad=$(this);var ai=ah.offsetX-ah.current_x;var ae=ad.scrollTop()-(af.clientY-ah.current_height);ad.scrollTop(ae);ah.current_height=af.clientY;ah.current_x=ah.offsetX;var ag=Math.round(ai/Z.viewport_container.width()*(Z.high-Z.low));Z.move_delta(ag)}).bind("mousewheel",function(af,ah,ae,ad){if(ae){ae*=50;var ag=Math.round(-ae/Z.viewport_container.width()*(Z.high-Z.low));Z.move_delta(ag)}});this.top_labeltrack.bind("dragstart",function(ad,ae){return $("<div />").css({height:Z.browser_content_div.height()+Z.top_labeltrack.height()+Z.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ah,ai){$(ai.proxy).css({left:Math.min(ah.pageX,ai.startX)-Z.container.offset().left,width:Math.abs(ah.pageX-ai.startX)});var ae=Math.min(ah.pageX,ai.startX)-Z.container.offset().left,ad=Math.max(ah.pageX,ai.startX)-Z.container.offset().left,ag=(Z.high-Z.low),af=Z.viewport_container.width();Z.update_location(Math.round(ae/af*ag)+Z.low,Math.round(ad/af*ag)+Z.low)}).bind("dragend",function(ai,aj){var ae=Math.min(ai.pageX,aj.startX),ad=Math.max(ai.pageX,aj.startX),ag=(Z.high-Z.low),af=Z.viewport_container.width(),ah=Z.low;Z.low=Math.round(ae/af*ag)+ah;Z.high=Math.round(ad/af*ag)+ah;$(aj.proxy).remove();Z.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(){Z.resize_window()},500)});$(document).bind("redraw",function(){Z.redraw()});this.reset();$(window).trigger("resize")},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(aa,ac,Z,ad){if(this.timer){clearTimeout(this.timer)}if(ad){var ab=this;this.timer=setTimeout(function(){ab.trigger("navigate",aa+":"+ac+"-"+Z)},500)}else{view.trigger("navigate",aa+":"+ac+"-"+Z)}},update_location:function(Z,ab){this.location_span.text(commatize(Z)+" - "+commatize(ab));this.nav_input.val(this.chrom+":"+commatize(Z)+"-"+commatize(ab));var aa=view.chrom_select.val();if(aa!==""){this.trigger_navigate(aa,view.low,view.high,true)}},load_chroms:function(ab){ab.num=u;var Z=this,aa=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ab,dataType:"json",success:function(ad){if(ad.chrom_info.length===0){return}if(ad.reference){Z.add_label_track(new y(Z))}Z.chrom_data=ad.chrom_info;var ag='<option value="">Select Chrom/Contig</option>';for(var af=0,ac=Z.chrom_data.length;af<ac;af++){var ae=Z.chrom_data[af].chrom;ag+='<option value="'+ae+'">'+ae+"</option>"}if(ad.prev_chroms){ag+='<option value="previous">Previous '+u+"</option>"}if(ad.next_chroms){ag+='<option value="next">Next '+u+"</option>"}Z.chrom_select.html(ag);Z.chrom_start_index=ad.start_index;aa.resolve(ad)},error:function(){alert("Could not load chroms for this dbkey:",Z.dbkey)}});return aa},change_chrom:function(ae,aa,ag){var ab=this;if(!ab.chrom_data){ab.load_chroms_deferred.then(function(){ab.change_chrom(ae,aa,ag)});return}if(!ae||ae==="None"){return}if(ae==="previous"){ab.load_chroms({low:this.chrom_start_index-u});return}if(ae==="next"){ab.load_chroms({low:this.chrom_start_index+u});return}var af=$.grep(ab.chrom_data,function(ah,ai){return ah.chrom===ae})[0];if(af===undefined){ab.load_chroms({chrom:ae},function(){ab.change_chrom(ae,aa,ag)});return}else{if(ae!==ab.chrom){ab.chrom=ae;ab.chrom_select.val(ab.chrom);ab.max_high=af.len-1;ab.reset();ab.request_redraw(true);for(var ad=0,Z=ab.drawables.length;ad<Z;ad++){var ac=ab.drawables[ad];if(ac.init){ac.init()}}if(ab.reference_track){ab.reference_track.init()}}if(aa!==undefined&&ag!==undefined){ab.low=Math.max(aa,0);ab.high=Math.min(ag,ab.max_high)}else{ab.low=0;ab.high=ab.max_high}ab.reset_overview();ab.request_redraw()}},go_to:function(ad){ad=ad.replace(/ |,/g,"");var ah=this,Z,ac,aa=ad.split(":"),af=aa[0],ag=aa[1];if(ag!==undefined){try{var ae=ag.split("-");Z=parseInt(ae[0],10);ac=parseInt(ae[1],10)}catch(ab){return false}}ah.change_chrom(af,Z,ac)},move_fraction:function(ab){var Z=this;var aa=Z.high-Z.low;this.move_delta(ab*aa)},move_delta:function(ac){var Z=this;var ab=Z.high-Z.low;if(Z.low-ac<Z.max_low){Z.low=Z.max_low;Z.high=Z.max_low+ab}else{if(Z.high-ac>Z.max_high){Z.high=Z.max_high;Z.low=Z.max_high-ab}else{Z.high-=ac;Z.low-=ac}}Z.request_redraw();var aa=Z.chrom_select.val();this.trigger_navigate(aa,Z.low,Z.high,true)},add_drawable:function(Z){w.prototype.add_drawable.call(this,Z);Z.init();this.changed();this.update_intro_div()},add_label_track:function(Z){Z.view=this;Z.init();this.label_tracks.push(Z)},remove_drawable:function(ab,aa){w.prototype.remove_drawable.call(this,ab);if(aa){var Z=this;ab.container_div.hide(0,function(){$(this).remove();Z.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ah,Z,ag,ai){var af=this,ae=(ai?[ai]:af.drawables),ab;var aa;for(var ad=0;ad<ae.length;ad++){aa=ae[ad];ab=-1;for(var ac=0;ac<af.tracks_to_be_redrawn.length;ac++){if(af.tracks_to_be_redrawn[ac][0]===aa){ab=ac;break}}if(ab<0){af.tracks_to_be_redrawn.push([aa,Z,ag])}else{af.tracks_to_be_redrawn[ad][1]=Z;af.tracks_to_be_redrawn[ad][2]=ag}}if(!this.requested_redraw){requestAnimationFrame(function(){af._redraw(ah)});this.requested_redraw=true}},_redraw:function(aj){this.requested_redraw=false;var ag=this.low,ac=this.high;if(ag<this.max_low){ag=this.max_low}if(ac>this.max_high){ac=this.max_high}var ai=this.high-this.low;if(this.high!==0&&ai<this.min_separation){ac=ag+this.min_separation}this.low=Math.floor(ag);this.high=Math.ceil(ac);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var Z=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var af=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ak=13;this.overview_box.css({left:Z,width:Math.max(ak,af)}).show();if(af<ak){this.overview_box.css("left",Z-(ak-af)/2)}if(this.overview_highlight){this.overview_highlight.css({left:Z,width:af})}if(!aj){var ab,aa,ah;for(var ad=0,ae=this.tracks_to_be_redrawn.length;ad<ae;ad++){ab=this.tracks_to_be_redrawn[ad][0];aa=this.tracks_to_be_redrawn[ad][1];ah=this.tracks_to_be_redrawn[ad][2];if(ab){ab._draw(aa,ah)}}this.tracks_to_be_redrawn=[];for(ad=0,ae=this.label_tracks.length;ad<ae;ad++){this.label_tracks[ad]._draw()}}},zoom_in:function(aa,ab){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ac=this.high-this.low,ad=ac/2+this.low,Z=(ac/this.zoom_factor)/2;if(aa){ad=aa/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ad-Z);this.high=Math.round(ad+Z);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var aa=this.high-this.low,ab=aa/2+this.low,Z=(aa*this.zoom_factor)/2;this.low=Math.round(ab-Z);this.high=Math.round(ab+Z);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(ab){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ab.dataset_id){return}this.overview_viewport.find(".track").remove()}var aa=ab.copy({content_div:this.overview_viewport}),Z=this;aa.header_div.hide();aa.is_overview=true;Z.overview_drawable=aa;this.overview_drawable.postdraw_actions=function(){Z.overview_highlight.show().height(Z.overview_drawable.content_div.height());Z.overview_viewport.height(Z.overview_drawable.content_div.height()+Z.overview_box.outerHeight());Z.overview_close.show();Z.resize_window()};Z.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 q=function(ab,ag,ac){this.track=ab;this.name=ag.name;this.params=[];var an=ag.params;for(var ad=0;ad<an.length;ad++){var ai=an[ad],aa=ai.name,am=ai.label,ae=unescape(ai.html),ao=ai.value,ak=ai.type;if(ak==="number"){this.params.push(new e(aa,am,ae,(aa in ac?ac[aa]:ao),ai.min,ai.max))}else{if(ak==="select"){this.params.push(new K(aa,am,ae,(aa in ac?ac[aa]:ao)))}else{console.log("WARNING: unrecognized tool parameter type:",aa,ak)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(aq){aq.stopPropagation()}).click(function(aq){aq.stopPropagation()}).bind("dblclick",function(aq){aq.stopPropagation()});var al=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var aj=this.params;var ah=this;$.each(this.params,function(ar,av){var au=$("<div>").addClass("param-row").appendTo(ah.parent_div);var aq=$("<div>").addClass("param-label").text(av.label).appendTo(au);var at=$("<div/>").addClass("param-input").html(av.html).appendTo(au);at.find(":input").val(av.value);$("<div style='clear: both;'/>").appendTo(au)});this.parent_div.find("input").click(function(){$(this).select()});var ap=$("<div>").addClass("param-row").appendTo(this.parent_div);var af=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(ap);var Z=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(ap);Z.click(function(){ah.run_on_region()});af.click(function(){ah.run_on_dataset()});if("visible" in ac&&ac.visible){this.parent_div.show()}};o(q.prototype,{update_params:function(){for(var Z=0;Z<this.params.length;Z++){this.params[Z].update_value()}},state_dict:function(){var aa={};for(var Z=0;Z<this.params.length;Z++){aa[this.params[Z].name]=this.params[Z].value}aa.visible=this.parent_div.is(":visible");return aa},get_param_values_dict:function(){var Z={};this.parent_div.find(":input").each(function(){var aa=$(this).attr("name"),ab=$(this).val();Z[aa]=ab});return Z},get_param_values:function(){var Z=[];this.parent_div.find(":input").each(function(){var aa=$(this).attr("name"),ab=$(this).val();if(aa){Z[Z.length]=ab}});return Z},run_on_dataset:function(){var Z=this;Z.run({target_dataset_id:this.track.original_dataset_id,tool_id:Z.name},null,function(aa){show_modal(Z.name+" is Running",Z.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var aa={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[{chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}]},ae=this.track,ab=aa.tool_id+ae.tool_region_and_parameters_str(aa.chrom,aa.low,aa.high),Z;if(ae.container===view){var ad=new M(view,view,{name:this.name});var ac=ae.container.replace_drawable(ae,ad,false);ad.container_div.insertBefore(ae.view.content_div.children()[ac]);ad.add_drawable(ae);ae.container_div.appendTo(ad.content_div);Z=ad}else{Z=ae.container}var af=new ae.constructor(view,Z,{name:ab,hda_ldda:"hda"});af.init_for_tool_data();af.change_mode(ae.mode);af.set_filters_manager(ae.filters_manager.copy(af));af.update_icons();Z.add_drawable(af);af.tiles_div.text("Starting job.");this.update_params();this.run(aa,af,function(ag){af.set_dataset(new Dataset(ag));af.tiles_div.text("Running job.");af.init()})},run:function(Z,ab,ac){Z.inputs=this.get_param_values_dict();var aa=new ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(Z),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ad){return ad!=="pending"}});$.when(aa.go()).then(function(ad){if(ad==="no converter"){ab.container_div.addClass("error");ab.content_div.text(G)}else{if(ad.error){ab.container_div.addClass("error");ab.content_div.text(v+ad.message)}else{ac(ad)}}})}});var K=function(aa,Z,ab,ac){this.name=aa;this.label=Z;this.html=$(ab);this.value=ac};o(K.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ab,aa,ad,ae,ac,Z){K.call(this,ab,aa,ad,ae);this.min=ac;this.max=Z};o(e.prototype,K.prototype,{update_value:function(){K.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var f=function(Z){this.manager=null;this.name=Z.name;this.index=Z.index;this.tool_id=Z.tool_id;this.tool_exp_name=Z.tool_exp_name};o(f.prototype,{to_dict:function(){return{name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name}}});var Q=function(ah){f.call(this,ah);this.low=("low" in ah?ah.low:-Number.MAX_VALUE);this.high=("high" in ah?ah.high:Number.MAX_VALUE);this.min=("min" in ah?ah.min:Number.MAX_VALUE);this.max=("max" in ah?ah.max:-Number.MAX_VALUE);this.container=null;this.slider=null;this.slider_label=null;var ad=function(ai,aj,ak){ai.click(function(){var ap=aj.text(),an=parseFloat(ak.slider("option","max")),am=(an<=1?4:an<=1000000?an.toString().length:6),ao=false,al=$(this).parents(".slider-row");al.addClass("input");if(ak.slider("option","values")){am=2*am+1;ao=true}aj.text("");$("<input type='text'/>").attr("size",am).attr("maxlength",am).attr("value",ap).appendTo(aj).focus().select().click(function(aq){aq.stopPropagation()}).blur(function(){$(this).remove();aj.text(ap);al.removeClass("input")}).keyup(function(av){if(av.keyCode===27){$(this).trigger("blur")}else{if(av.keyCode===13){var at=ak.slider("option","min"),aq=ak.slider("option","max"),au=function(aw){return(isNaN(aw)||aw>aq||aw<at)},ar=$(this).val();if(!ao){ar=parseFloat(ar);if(au(ar)){alert("Parameter value must be in the range ["+at+"-"+aq+"]");return $(this)}}else{ar=ar.split("-");ar=[parseFloat(ar[0]),parseFloat(ar[1])];if(au(ar[0])||au(ar[1])){alert("Parameter value must be in the range ["+at+"-"+aq+"]");return $(this)}}ak.slider((ao?"values":"value"),ar);al.removeClass("input")}}})})};var aa=this;aa.parent_div=$("<div/>").addClass("filter-row slider-row");var Z=$("<div/>").addClass("elt-label").appendTo(aa.parent_div),af=$("<span/>").addClass("slider-name").text(aa.name+" ").appendTo(Z),ab=$("<span/>").text(this.low+"-"+this.high),ac=$("<span/>").addClass("slider-value").appendTo(Z).append("[").append(ab).append("]");aa.values_span=ab;var ae=$("<div/>").addClass("slider").appendTo(aa.parent_div);aa.control_element=$("<div/>").attr("id",aa.name+"-filter-control").appendTo(ae);aa.control_element.slider({range:true,min:this.min,max:this.max,step:this.get_slider_step(this.min,this.max),values:[this.low,this.high],slide:function(ai,aj){aa.slide(ai,aj)},change:function(ai,aj){aa.control_element.slider("option","slide").call(aa.control_element,ai,aj)}});aa.slider=aa.control_element;aa.slider_label=ab;ad(ac,ab,aa.control_element);var ag=$("<div/>").addClass("display-controls").appendTo(aa.parent_div);this.transparency_icon=create_action_icon("Use filter for data transparency","layer-transparent",function(){if(aa.manager.alpha_filter!==aa){aa.manager.alpha_filter=aa;aa.manager.parent_div.find(".layer-transparent").removeClass("active").hide();aa.transparency_icon.addClass("active").show()}else{aa.manager.alpha_filter=null;aa.transparency_icon.removeClass("active")}aa.manager.track.request_draw(true,true)}).appendTo(ag).hide();this.height_icon=create_action_icon("Use filter for data height","arrow-resize-090",function(){if(aa.manager.height_filter!==aa){aa.manager.height_filter=aa;aa.manager.parent_div.find(".arrow-resize-090").removeClass("active").hide();aa.height_icon.addClass("active").show()}else{aa.manager.height_filter=null;aa.height_icon.removeClass("active")}aa.manager.track.request_draw(true,true)}).appendTo(ag).hide();aa.parent_div.hover(function(){aa.transparency_icon.show();aa.height_icon.show()},function(){if(aa.manager.alpha_filter!==aa){aa.transparency_icon.hide()}if(aa.manager.height_filter!==aa){aa.height_icon.hide()}});$("<div style='clear: both;'/>").appendTo(aa.parent_div)};o(Q.prototype,{to_dict:function(){var Z=f.prototype.to_dict.call(this);return o(Z,{type:"number",min:this.min,max:this.max,low:this.low,high:this.high})},copy:function(){return new Q({name:this.name,index:this.index,tool_id:this.tool_id,tool_exp_name:this.tool_exp_name})},get_slider_step:function(ab,Z){var aa=Z-ab;return(aa<=2?0.01:1)},slide:function(ab,ac){var aa=ac.values;this.values_span.text(aa[0]+"-"+aa[1]);this.low=aa[0];this.high=aa[1];var Z=this;setTimeout(function(){if(aa[0]===Z.low&&aa[1]===Z.high){Z.manager.track.request_draw(true,true)}},25)},applies_to:function(Z){if(Z.length>this.index){return true}return false},_keep_val:function(Z){return(isNaN(Z)||(Z>=this.low&&Z<=this.high))},keep:function(aa){if(!this.applies_to(aa)){return true}var ac=this;var ad=aa[this.index];if(ad instanceof Array){var ab=true;for(var Z=0;Z<ad.length;Z++){if(!this._keep_val(ad[Z])){ab=false;break}}return ab}else{return this._keep_val(aa[this.index])}},update_attrs:function(ac){var Z=false;if(!this.applies_to(ac)){return Z}var aa=ac[this.index];if(!(aa instanceof Array)){aa=[aa]}for(var ab=0;ab<aa.length;ab++){var ad=aa[ab];if(ad<this.min){this.min=Math.floor(ad);Z=true}if(ad>this.max){this.max=Math.ceil(ad);Z=true}}return Z},update_ui_elt:function(){if(this.min<this.max){this.parent_div.show()}else{this.parent_div.hide()}var aa=this.slider.slider("option","min"),Z=this.slider.slider("option","max");if(this.min<aa||this.max>Z){this.slider.slider("option","min",this.min);this.slider.slider("option","max",this.max);this.slider.slider("option","step",this.get_slider_step(this.min,this.max));this.slider.slider("option","values",[this.min,this.max])}}});var V=function(ab,ah){this.track=ab;this.alpha_filter=null;this.height_filter=null;this.filters=[];this.parent_div=$("<div/>").addClass("filters").hide();this.parent_div.bind("drag",function(aj){aj.stopPropagation()}).click(function(aj){aj.stopPropagation()}).bind("dblclick",function(aj){aj.stopPropagation()}).bind("keydown",function(aj){aj.stopPropagation()});if(ah&&"filters" in ah){var Z=("alpha_filter" in ah?ah.alpha_filter:null),ac=("height_filter" in ah?ah.height_filter:null),ae=ah.filters,aa;for(var af=0;af<ae.length;af++){if(ae[af].type==="number"){aa=new Q(ae[af]);this.add_filter(aa);if(aa.name===Z){this.alpha_filter=aa;aa.transparency_icon.addClass("active").show()}if(aa.name===ac){this.height_filter=aa;aa.height_icon.addClass("active").show()}}else{console.log("ERROR: unsupported filter: ",name,type)}}if("visible" in ah&&ah.visible){this.parent_div.show()}}if(this.filters.length!==0){var ai=$("<div/>").addClass("param-row").appendTo(this.parent_div);var ag=$("<input type='submit'/>").attr("value","Run on complete dataset").appendTo(ai);var ad=this;ag.click(function(){ad.run_on_dataset()})}};o(V.prototype,{show:function(){this.parent_div.show()},hide:function(){this.parent_div.hide()},toggle:function(){this.parent_div.toggle()},visible:function(){return this.parent_div.is(":visible")},to_dict:function(){var ac={},ab=[],aa;for(var Z=0;Z<this.filters.length;Z++){aa=this.filters[Z];ab.push(aa.to_dict())}ac.filters=ab;ac.alpha_filter=(this.alpha_filter?this.alpha_filter.name:null);ac.height_filter=(this.height_filter?this.height_filter.name:null);ac.visible=this.parent_div.is(":visible");return ac},copy:function(aa){var ab=new V(aa);for(var Z=0;Z<this.filters.length;Z++){ab.add_filter(this.filters[Z].copy())}return ab},add_filter:function(Z){Z.manager=this;this.parent_div.append(Z.parent_div);this.filters.push(Z)},remove_all:function(){this.filters=[];this.parent_div.children().remove()},init_filters:function(){for(var Z=0;Z<this.filters.length;Z++){var aa=this.filters[Z];aa.update_ui_elt()}},clear_filters:function(){for(var Z=0;Z<this.filters.length;Z++){var aa=this.filters[Z];aa.slider.slider("option","values",[aa.min,aa.max])}this.alpha_filter=null;this.height_filter=null;this.parent_div.find(".icon-button").hide()},run_on_dataset:function(){var af=function(aj,ah,ai){if(!(ah in aj)){aj[ah]=ai}return aj[ah]};var ae={},ag,Z;for(var ad=0;ad<this.filters.length;ad++){ag=this.filters[ad];if(ag.tool_id){if(ag.min!==ag.low){Z=af(ae,ag.tool_id,[]);Z[Z.length]=ag.tool_exp_name+" >= "+ag.low}if(ag.max!==ag.high){Z=af(ae,ag.tool_id,[]);Z[Z.length]=ag.tool_exp_name+" <= "+ag.high}}}var aa=[];for(var ac in ae){aa[aa.length]=[ac,ae[ac]]}(function ab(an,ak){var ai=ak[0],aj=ai[0],am=ai[1],al="("+am.join(") and (")+")",ah={cond:al,input:an,target_dataset_id:an,tool_id:aj},ak=ak.slice(1);$.getJSON(run_tool_url,ah,function(ao){if(ao.error){show_modal("Filter Dataset","Error running tool "+aj,{Close:hide_modal})}else{if(ak.length===0){show_modal("Filtering Dataset","Filter(s) are running on the complete dataset. Outputs are in dataset's history.",{Close:hide_modal})}else{ab(ao.dataset_id,ak)}}})})(this.track.dataset_id,aa)}});var z=function(Z,aa){I.Scaler.call(this,aa);this.filter=Z};z.prototype.gen_val=function(Z){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(Z[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var C=function(Z){this.track=Z.track;this.params=Z.params;this.values={};this.restore_values((Z.saved_values?Z.saved_values:{}));this.onchange=Z.onchange};o(C.prototype,{restore_values:function(Z){var aa=this;$.each(this.params,function(ab,ac){if(Z[ac.key]!==undefined){aa.values[ac.key]=Z[ac.key]}else{aa.values[ac.key]=ac.default_value}})},build_form:function(){var ac=this;var Z=$("<div />");var ab;function aa(ah,ad){for(var al=0;al<ah.length;al++){ab=ah[al];if(ab.hidden){continue}var af="param_"+al;var ap=ac.values[ab.key];var ar=$("<div class='form-row' />").appendTo(ad);ar.append($("<label />").attr("for",af).text(ab.label+":"));if(ab.type==="bool"){ar.append($('<input type="checkbox" />').attr("id",af).attr("name",af).attr("checked",ap))}else{if(ab.type==="text"){ar.append($('<input type="text"/>').attr("id",af).val(ap).click(function(){$(this).select()}))}else{if(ab.type==="select"){var an=$("<select />").attr("id",af);for(var aj=0;aj<ab.options.length;aj++){$("<option/>").text(ab.options[aj].label).attr("value",ab.options[aj].value).appendTo(an)}an.val(ap);ar.append(an)}else{if(ab.type==="color"){var aq=$("<div/>").appendTo(ar),am=$("<input />").attr("id",af).attr("name",af).val(ap).css("float","left").appendTo(aq).click(function(au){$(".bs-tooltip").removeClass("in");var at=$(this).siblings(".bs-tooltip").addClass("in");at.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(at).height()/2)+($(this).height()/2)}).show();at.click(function(av){av.stopPropagation()});$(document).bind("click.color-picker",function(){at.hide();$(document).unbind("click.color-picker")});au.stopPropagation()}),ak=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(aq).attr("title","Set new random color").tooltip(),ao=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(aq).hide(),ag=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ao),ae=$("<div class='tooltip-arrow'></div>").appendTo(ao),ai=$.farbtastic(ag,{width:100,height:100,callback:am,color:ap});aq.append($("<div/>").css("clear","both"));(function(at){ak.click(function(){at.setColor(get_random_color())})})(ai)}else{ar.append($("<input />").attr("id",af).attr("name",af).val(ap))}}}}if(ab.help){ar.append($("<div class='help'/>").text(ab.help))}}}aa(this.params,Z);return Z},update_from_form:function(Z){var ab=this;var aa=false;$.each(this.params,function(ac,ae){if(!ae.hidden){var af="param_"+ac;var ad=Z.find("#"+af).val();if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad)}else{if(ae.type==="bool"){ad=Z.find("#"+af).is(":checked")}}}if(ad!==ab.values[ae.key]){ab.values[ae.key]=ad;aa=true}}});if(aa){this.onchange();this.track.changed()}}});var b=function(Z,ad,ab,aa,ac){this.track=Z;this.region=ad;this.low=ad.get("start");this.high=ad.get("end");this.resolution=ab;this.html_elt=$("<div class='track-tile'/>").append(aa).height($(aa).attr("height"));this.data=ac;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(Z,ae,ab,aa,ac,ad){b.call(this,Z,ae,ab,aa,ac);this.max_val=ad};o(j.prototype,b.prototype);var L=function(ac,ak,ad,ab,af,am,ag,an,aa,aj){b.call(this,ac,ak,ad,ab,af);this.mode=ag;this.all_slotted=aa;this.feature_mapper=aj;this.has_icons=false;if(an){this.has_icons=true;var ah=this;ab=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:A-1,width:ab.width}).prependTo(this.html_elt);var ai=new GenomeRegion({chrom:ac.view.chrom,start:this.low,end:this.high}),al=af.length,ae=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+al+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),Z=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+al+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ae.click(function(){ah.stale=true;ac.data_manager.get_more_data(ai,ac.mode,ah.resolution,{},ac.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();ac.request_draw(true)}).dblclick(function(ao){ao.stopPropagation()});Z.click(function(){ah.stale=true;ac.data_manager.get_more_data(ai,ac.mode,ah.resolution,{},ac.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();ac.request_draw(true)}).dblclick(function(ao){ao.stopPropagation()})}};o(L.prototype,b.prototype);L.prototype.predisplay_actions=function(){var aa=this,Z={};if(aa.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(al){if(!this.hovered){return}var ag=$(this).offset(),ak=al.pageX-ag.left,aj=al.pageY-ag.top,ap=aa.feature_mapper.get_feature_data(ak,aj),ah=(ap?ap[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ah||$(this).attr("id")!==ah.toString()){$(this).remove()}});if(ap){var ac=Z[ah];if(!ac){var ah=ap[0],am={name:ap[3],start:ap[1],end:ap[2],strand:ap[4]},af=aa.track.filters_manager.filters,ae;for(var ai=0;ai<af.length;ai++){ae=af[ai];am[ae.name]=ap[ae.index]}var ac=$("<div/>").attr("id",ah).addClass("feature-popup"),aq=$("<table/>"),ao,an,ar;for(ao in am){an=am[ao];ar=$("<tr/>").appendTo(aq);$("<th/>").appendTo(ar).text(ao);$("<td/>").attr("align","left").appendTo(ar).text(typeof(an)==="number"?U(an,2):an)}ac.append($("<div class='feature-popup-inner'>").append(aq));Z[ah]=ac}ac.appendTo($(this).parents(".track-content").children(".overlay"));var ad=ak+parseInt(aa.html_elt.css("left"))-ac.width()/2,ab=aj+parseInt(aa.html_elt.css("top"))+7;ac.css("left",ad+"px").css("top",ab+"px")}else{if(!al.isPropagationStopped()){al.stopPropagation();$(this).siblings().each(function(){$(this).trigger(al)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var h=function(aa,Z,ab){o(ab,{drag_handle_class:"draghandle"});p.call(this,aa,Z,ab);this.dataset=new Dataset({id:ab.dataset_id,hda_ldda:ab.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ab?ab.data_query_wait:H);this.data_manager=("data_manager" in ab?ab.data_manager:new GenomeDataManager({dataset:this.dataset,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 ab)||ab.resize){this.add_resize_handle()}}};o(h.prototype,p.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},p.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(Z){Z.view.set_overview(Z)}},p.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(Z){if(Z.filters_manager.visible()){Z.filters_manager.clear_filters()}else{Z.filters_manager.init_filters()}Z.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(Z){Z.dynamic_tool_div.toggle();if(Z.dynamic_tool_div.is(":visible")){Z.set_name(Z.name+Z.tool_region_and_parameters_str())}else{Z.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(Z){var ac='<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>',ab=_.template(ac,{track:Z});var ae=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},aa=function(){var ag=$('select[name="regions"] option:selected').val(),ai,af=new GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ah=_.map($(".bookmark"),function(aj){return new GenomeRegion({from_str:$(aj).children(".position").text()})});if(ag==="cur"){ai=[af]}else{if(ag==="bookmarks"){ai=ah}else{ai=[af].concat(ah)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:Z.dataset_id,hda_ldda:Z.hda_ldda,regions:JSON.stringify(new Backbone.Collection(ai).toJSON())})},ad=function(af){if((af.keyCode||af.which)===27){ae()}else{if((af.keyCode||af.which)===13){aa()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ab,{No:ae,Yes:aa})}},p.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&p.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 Z=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(Z)}this.name_div=$("<div/>").addClass("track-name").appendTo(Z).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return Z},on_resize:function(){},add_resize_handle:function(){var Z=this;var ac=false;var ab=false;var aa=$("<div class='track-resize'>");$(Z.container_div).hover(function(){if(Z.content_visible){ac=true;aa.show()}},function(){ac=false;if(!ab){aa.hide()}});aa.hide().bind("dragstart",function(ad,ae){ab=true;ae.original_height=$(Z.content_div).height()}).bind("drag",function(ae,af){var ad=Math.min(Math.max(af.original_height+af.deltaY,Z.min_height_px),Z.max_height_px);$(Z.tiles_div).css("height",ad);Z.visible_height_px=(Z.max_height_px===ad?0:ad);Z.on_resize()}).bind("dragend",function(ad,ae){Z.tile_cache.clear();ab=false;if(!ac){aa.hide()}Z.config.values.height=Z.visible_height_px;Z.changed()}).appendTo(Z.container_div)},set_display_modes:function(ac,af){this.display_modes=ac;this.mode=(af?af:(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 aa=this,ad={};for(var ab=0,Z=aa.display_modes.length;ab<Z;ab++){var ae=aa.display_modes[ab];ad[ae]=function(ag){return function(){aa.change_mode(ag);aa.icons_div.show();aa.container_div.mouseleave(function(){aa.icons_div.hide()})}}(ae)}make_popupmenu(this.action_icons.mode_icon,ad)},build_action_icons:function(){p.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 y){return"ReferenceTrack"}else{if(this instanceof i){return"LineTrack"}else{if(this instanceof R){return"ReadTrack"}else{if(this instanceof O){return"VcfTrack"}else{if(this instanceof g){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(){var aa=this;aa.enabled=false;aa.tile_cache.clear();aa.data_manager.clear();aa.content_div.css("height","auto");aa.tiles_div.children().remove();aa.container_div.removeClass("nodata error pending");if(!aa.dataset_id){return}var Z=$.Deferred(),ab={hda_ldda:aa.hda_ldda,data_type:this.dataset_check_type,chrom:aa.view.chrom};$.getJSON(this.dataset.url(),ab,function(ac){if(!ac||ac==="error"||ac.kind==="error"){aa.container_div.addClass("error");aa.tiles_div.text(n);if(ac.message){var ad=$(" <a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ac.message+"</pre>",{Close:hide_modal})});aa.tiles_div.append(ad)}}else{if(ac==="no converter"){aa.container_div.addClass("error");aa.tiles_div.text(G)}else{if(ac==="no data"||(ac.data!==undefined&&(ac.data===null||ac.data.length===0))){aa.container_div.addClass("nodata");aa.tiles_div.text(B)}else{if(ac==="pending"){aa.container_div.addClass("pending");aa.tiles_div.html(t);setTimeout(function(){aa.init()},aa.data_query_wait)}else{if(ac==="data"||ac.status==="data"){if(ac.valid_chroms){aa.valid_chroms=ac.valid_chroms;aa.update_icons()}aa.tiles_div.text(T);if(aa.view.chrom){aa.tiles_div.text("");aa.tiles_div.css("height",aa.visible_height_px+"px");aa.enabled=true;$.when(aa.predraw_init()).done(function(){Z.resolve();aa.container_div.removeClass("nodata error pending");aa.request_draw()})}else{Z.resolve()}}}}}}});this.update_icons();return Z},predraw_init:function(){},get_drawables:function(){return this}});var J=function(ab,aa,ac){h.call(this,ab,aa,ac);var Z=this;l(Z.container_div,Z.drag_handle_class,".group",Z);this.filters_manager=new V(this,("filters" in ac?ac.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in ac&&ac.tool?new q(this,ac.tool,ac.tool_state):null);this.tile_cache=new Cache(N);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(ac.mode){this.change_mode(ac.mode)}};o(J.prototype,p.prototype,h.prototype,{action_icons_def:h.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(Z){$(".bs-tooltip").remove();Z.slotters[Z.view.resolution_px_b].max_rows*=2;Z.request_draw(true)},hide:true}]),copy:function(Z){var aa=this.to_dict();o(aa,{data_manager:this.data_manager});var ab=new this.constructor(this.view,Z,aa);ab.change_mode(this.mode);ab.enabled=this.enabled;return ab},set_filters_manager:function(Z){this.filters_manager=Z;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(aa){var Z=this;Z.mode=aa;Z.config.values.mode=aa;Z.tile_cache.clear();Z.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+Z.mode+")");return Z},update_icons:function(){var Z=this;if(Z.filters_available){Z.action_icons.filters_icon.show()}else{Z.action_icons.filters_icon.hide()}if(Z.tool){Z.action_icons.tools_icon.show();Z.action_icons.param_space_viz_icon.show()}else{Z.action_icons.tools_icon.hide();Z.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(aa,ab,Z){return aa+"_"+ab+"_"+Z},request_draw:function(aa,Z){this.view.request_redraw(false,aa,Z,this)},before_draw:function(){},_draw:function(aa,ak){if(!this.can_draw()){return}var ai=this.view.low,ae=this.view.high,ag=ae-ai,ab=this.view.container.width(),am=this.view.resolution_px_b,ad=this.view.resolution_b_px;if(this.is_overview){ai=this.view.max_low;ae=this.view.max_high;ad=(view.max_high-view.max_low)/ab;am=1/ad}this.before_draw();this.tiles_div.children().addClass("remove");var Z=Math.floor(ai/(ad*P)),ah=true,al=[],af=function(an){return(an&&"track" in an)};while((Z*P*ad)<ae){var aj=this.draw_helper(aa,ab,Z,ad,this.tiles_div,am);if(af(aj)){al.push(aj)}else{ah=false}Z+=1}if(!ak){this.tiles_div.children(".remove").removeClass("remove").remove()}var ac=this;if(ah){this.tiles_div.children(".remove").remove();ac.postdraw_actions(al,ab,am,ak)}},postdraw_actions:function(ab,ac,ae,Z){var ad=false;for(var aa=0;aa<ab.length;aa++){if(ab[aa].has_icons){ad=true;break}}if(ad){for(var aa=0;aa<ab.length;aa++){tile=ab[aa];if(!tile.has_icons){tile.html_elt.css("padding-top",A)}}}},draw_helper:function(Z,al,aq,ao,ae,af,am){var ak=this,au=this._gen_tile_cache_key(al,af,aq),ac=this._get_tile_bounds(aq,ao);if(!am){am={}}var at=(Z?undefined:ak.tile_cache.get_elt(au));if(at){ak.show_tile(at,ae,af);return at}var ai=true;var ap=ak.data_manager.get_data(ac,ak.mode,ao,ak.data_url_extra_params);if(is_deferred(ap)){ai=false}var ag;if(view.reference_track&&af>view.canvas_manager.char_width_px){ag=view.reference_track.data_manager.get_data(ac,ak.mode,ao,view.reference_track.data_url_extra_params);if(is_deferred(ag)){ai=false}}if(ai){o(ap,am.more_tile_data);var ah=ak.mode;if(ah==="Auto"){ah=ak.get_mode(ap);ak.update_auto_mode(ah)}var ab=ak.view.canvas_manager.new_canvas(),ar=ac.get("start"),aa=ac.get("end"),al=Math.ceil((aa-ar)*af)+ak.left_offset,aj=ak.get_canvas_height(ap,ah,af,al);ab.width=al;ab.height=aj;var an=ab.getContext("2d");an.translate(this.left_offset,0);var at=ak.draw_tile(ap,an,ah,ao,ac,af,ag);if(at!==undefined){ak.tile_cache.set_elt(au,at);ak.show_tile(at,ae,af)}return at}var ad=$.Deferred();$.when(ap,ag).then(function(){view.request_redraw(false,false,false,ak);ad.resolve()});return ad},get_canvas_height:function(Z,ab,ac,aa){return this.visible_height_px},draw_tile:function(Z,aa,ae,ac,ad,af,ab){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ab,ad,ae){var aa=this,Z=ab.html_elt;ab.predisplay_actions();var ac=(ab.low-(this.is_overview?this.view.max_low:this.view.low))*ae;if(this.left_offset){ac-=this.left_offset}Z.css({position:"absolute",top:0,left:ac});if(Z.hasClass("remove")){Z.removeClass("remove")}else{ad.append(Z)}aa.after_show_tile(ab)},after_show_tile:function(Z){this.max_height_px=Math.max(this.max_height_px,Z.html_elt.height());Z.html_elt.parent().children().css("height",this.max_height_px+"px");var aa=this.max_height_px;if(this.visible_height_px!==0){aa=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",aa+"px")},_get_tile_bounds:function(Z,aa){var ac=Math.floor(Z*P*aa),ad=Math.ceil(P*aa),ab=(ac+ad<=this.view.max_high?ac+ad:this.view.max_high);return new GenomeRegion({chrom:this.view.chrom,start:ac,end:ab})},tool_region_and_parameters_str:function(ab,Z,ac){var aa=this,ad=(ab!==undefined&&Z!==undefined&&ac!==undefined?ab+":"+Z+"-"+ac:"all");return" - region=["+ad+"], parameters=["+aa.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(Z,aa){return true},can_subset:function(Z){return false},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(ab,ac,ae,Z){var aa=this;aa.normal_postdraw_actions(ab,ac,ae,Z);aa.dataset_state_url=converted_datasets_state_url;aa.data_query_wait=H;var ad=new ServerStateDeferred({url:aa.dataset_state_url,url_params:{dataset_id:aa.dataset_id,hda_ldda:aa.hda_ldda},interval:aa.data_query_wait,success_fn:function(af){return af!=="pending"}});$.when(ad.go()).then(function(){aa.data_manager.set("data_type","data");aa.dataset_check_type="converted_datasets_state";this.data_query_wait=5000});aa.postdraw_actions=aa.normal_postdraw_actions}}});var W=function(aa,Z){var ab={resize:false};h.call(this,aa,Z,ab);this.container_div.addClass("label-track")};o(W.prototype,h.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ab=this.view,ac=ab.high-ab.low,af=Math.floor(Math.pow(10,Math.floor(Math.log(ac)/Math.log(10)))),Z=Math.floor(ab.low/af)*af,ad=this.view.container.width(),aa=$("<div style='position: relative; height: 1.3em;'></div>");while(Z<ab.high){var ae=(Z-ab.low)/ac*ad;aa.append($("<div class='label'>"+commatize(Z)+"</div>").css({position:"absolute",left:ae-1}));Z+=af}this.content_div.children(":first").remove();this.content_div.append(aa)}});var g=function(aa,Z,ad){J.call(this,aa,Z,ad);this.drawables=[];this.left_offset=0;if("drawables" in ad){var ac;for(var ab=0;ab<ad.drawables.length;ab++){ac=ad.drawables[ab];this.drawables[ab]=object_from_template(ac,aa,null);if(ac.left_offset>this.left_offset){this.left_offset=ac.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};o(g.prototype,J.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(Z){$(".bs-tooltip").remove();Z.show_group()}}].concat(J.prototype.action_icons_def),to_dict:w.prototype.to_dict,add_drawable:w.prototype.add_drawable,unpack_drawables:w.prototype.unpack_drawables,change_mode:function(Z){J.prototype.change_mode.call(this,Z);for(var aa=0;aa<this.drawables.length;aa++){this.drawables[aa].change_mode(Z)}},init:function(){var ab=[];for(var aa=0;aa<this.drawables.length;aa++){ab.push(this.drawables[aa].init())}var Z=this;$.when.apply($,ab).then(function(){Z.enabled=true;Z.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:p.prototype.can_draw,draw_helper:function(aa,ap,aw,at,ah,aj,aq){var ao=this,aA=this._gen_tile_cache_key(ap,aj,aw),ae=this._get_tile_bounds(aw,at);if(!aq){aq={}}var az=(aa?undefined:ao.tile_cache.get_elt(aA));if(az){ao.show_tile(az,ah,aj);return az}var ai=[],ao,am=true,au,ak;for(var av=0;av<this.drawables.length;av++){ao=this.drawables[av];au=ao.data_manager.get_data(ae,ao.mode,at,ao.data_url_extra_params);if(is_deferred(au)){am=false}ai.push(au);ak=null;if(view.reference_track&&aj>view.canvas_manager.char_width_px){ak=view.reference_track.data_manager.get_data(ae,ao.mode,at,view.reference_track.data_url_extra_params);if(is_deferred(ak)){am=false}}ai.push(ak)}if(am){o(au,aq.more_tile_data);this.tile_predraw_init();var ad=ao.view.canvas_manager.new_canvas(),af=ao._get_tile_bounds(aw,at),ax=ae.get("start"),ab=ae.get("end"),ay=0,ap=Math.ceil((ab-ax)*aj)+this.left_offset,an=0,ac=[],av;var Z=0;for(av=0;av<this.drawables.length;av++,ay+=2){ao=this.drawables[av];au=ai[ay];var al=ao.mode;if(al==="Auto"){al=ao.get_mode(au);ao.update_auto_mode(al)}ac.push(al);Z=ao.get_canvas_height(au,al,aj,ap);if(Z>an){an=Z}}ad.width=ap;ad.height=(aq.height?aq.height:an);ay=0;var ar=ad.getContext("2d");ar.translate(this.left_offset,0);ar.globalAlpha=0.5;ar.globalCompositeOperation="source-over";for(av=0;av<this.drawables.length;av++,ay+=2){ao=this.drawables[av];au=ai[ay];ak=ai[ay+1];az=ao.draw_tile(au,ar,ac[av],at,ae,aj,ak)}this.tile_cache.set_elt(aA,az);this.show_tile(az,ah,aj);return az}var ag=$.Deferred(),ao=this;$.when.apply($,ai).then(function(){view.request_redraw(false,false,false,ao);ag.resolve()});return ag},show_group:function(){var ac=new M(this.view,this.container,{name:this.name}),Z;for(var ab=0;ab<this.drawables.length;ab++){Z=this.drawables[ab];Z.update_icons();ac.add_drawable(Z);Z.container=ac;ac.content_div.append(Z.container_div)}var aa=this.container.replace_drawable(this,ac,true);ac.request_draw()},tile_predraw_init:function(){var ac=Number.MAX_VALUE,Z=-ac,aa;for(var ab=0;ab<this.drawables.length;ab++){aa=this.drawables[ab];if(aa instanceof i){if(aa.prefs.min_value<ac){ac=aa.prefs.min_value}if(aa.prefs.max_value>Z){Z=aa.prefs.max_value}}}for(var ab=0;ab<this.drawables.length;ab++){aa=this.drawables[ab];aa.prefs.min_value=ac;aa.prefs.max_value=Z}},postdraw_actions:function(ab,ae,ag,aa){J.prototype.postdraw_actions.call(this,ab,ae,ag,aa);var ad=-1;for(var ac=0;ac<ab.length;ac++){var Z=ab[ac].html_elt.find("canvas").height();if(Z>ad){ad=Z}}for(var ac=0;ac<ab.length;ac++){var af=ab[ac];if(af.html_elt.find("canvas").height()!==ad){this.draw_helper(true,ae,af.index,af.resolution,af.html_elt.parent(),ag,{height:ad});af.html_elt.remove()}}}});var y=function(Z){J.call(this,Z,{content_div:Z.top_labeltrack},{resize:false});Z.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=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};o(y.prototype,p.prototype,J.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:p.prototype.can_draw,draw_helper:function(ad,ab,Z,aa,ae,af,ac){if(af>this.view.canvas_manager.char_width_px){return J.prototype.draw_helper.call(this,ad,ab,Z,aa,ae,af,ac)}else{this.hide_contents();return null}},draw_tile:function(ah,ai,ad,ac,af,aj){var ab=this;if(aj>this.view.canvas_manager.char_width_px){if(ah.data===null){this.hide_contents();return}var aa=ai.canvas;ai.font=ai.canvas.manager.default_font;ai.textAlign="center";ah=ah.data;for(var ae=0,ag=ah.length;ae<ag;ae++){var Z=Math.floor(ae*aj);ai.fillText(ah[ae],Z,10)}this.show_contents();return new b(ab,af,ac,aa,ah)}this.hide_contents()}});var i=function(ab,aa,ac){var Z=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";J.call(this,ab,aa,ac);this.hda_ldda=ac.hda_ldda;this.dataset_id=ac.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value: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:ac.prefs,onchange:function(){Z.set_name(Z.prefs.name);Z.vertical_range=Z.prefs.max_value-Z.prefs.min_value;Z.set_min_value(Z.prefs.min_value);Z.set_max_value(Z.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};o(i.prototype,p.prototype,J.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(Z){this.prefs.min_value=Z;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(Z){this.prefs.max_value=Z;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var Z=this;Z.vertical_range=undefined;return $.getJSON(Z.dataset.url(),{data_type:"data",stats:true,chrom:Z.view.chrom,low:0,high:Z.view.max_high,hda_ldda:Z.hda_ldda,dataset_id:Z.dataset_id},function(aa){Z.container_div.addClass("line-track");var ad=aa.data;if(isNaN(parseFloat(Z.prefs.min_value))||isNaN(parseFloat(Z.prefs.max_value))){var ab=ad.min,af=ad.max;ab=Math.floor(Math.min(0,Math.max(ab,ad.mean-2*ad.sd)));af=Math.ceil(Math.max(0,Math.min(af,ad.mean+2*ad.sd)));Z.prefs.min_value=ab;Z.prefs.max_value=af;$("#track_"+Z.dataset_id+"_minval").val(Z.prefs.min_value);$("#track_"+Z.dataset_id+"_maxval").val(Z.prefs.max_value)}Z.vertical_range=Z.prefs.max_value-Z.prefs.min_value;Z.total_frequency=ad.total_frequency;Z.container_div.find(".yaxislabel").remove();var ae=$("<div/>").text(U(Z.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(ag){$(".bs-tooltip").remove();var ag=parseFloat(ag);if(!isNaN(ag)){Z.set_min_value(ag)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+Z.dataset_id+"_minval").prependTo(Z.container_div),ac=$("<div/>").text(U(Z.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(ag){$(".bs-tooltip").remove();var ag=parseFloat(ag);if(!isNaN(ag)){Z.set_max_value(ag)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+Z.dataset_id+"_maxval").prependTo(Z.container_div)})},draw_tile:function(ai,ag,ab,aa,ad,ah){var Z=ag.canvas,ac=ad.get("start"),af=ad.get("end"),ae=new I.LinePainter(ai.data,ac,af,this.prefs,ab);ae.draw(ag,Z.width,Z.height,ah);return new b(this,ad,aa,Z,ai.data)},can_subset:function(Z){return false}});var r=function(ab,aa,ac){var Z=this;this.display_modes=["Heatmap"];this.mode="Heatmap";J.call(this,ab,aa,ac);this.hda_ldda=ac.hda_ldda;this.dataset_id=ac.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"4169E1"},{key:"negative_color",label:"Negative Color",type:"color",default_value:"FF8C00"},{key:"min_value",label:"Min Value",type:"float",default_value:0},{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:ac.prefs,onchange:function(){Z.set_name(Z.prefs.name);Z.vertical_range=Z.prefs.max_value-Z.prefs.min_value;Z.set_min_value(Z.prefs.min_value);Z.set_max_value(Z.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};o(r.prototype,p.prototype,J.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(Z){this.prefs.min_value=Z;this.tile_cache.clear();this.request_draw()},set_max_value:function(Z){this.prefs.max_value=Z;this.tile_cache.clear();this.request_draw()},draw_tile:function(aj,ah,ae,ac,aa,ai){var ab=ah.canvas,Z=this._get_tile_bounds(aa,ac),ad=Z[0],ag=Z[1],af=new I.DiagonalHeatmapPainter(aj.data,ad,ag,this.prefs,ae);af.draw(ah,ab.width,ab.height,ai);return new b(this,aa,ac,ab,aj.data)}});var c=function(ac,ab,ae){var aa=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];J.call(this,ac,ab,ae);var ad=get_random_color(),Z=get_random_color([ad,"#ffffff"]);this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ad},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:Z},{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:"histogram_max",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:ae.prefs,onchange:function(){aa.set_name(aa.prefs.name);aa.tile_cache.clear();aa.set_painter_from_config();aa.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ae.hda_ldda;this.dataset_id=ae.dataset_id;this.original_dataset_id=ae.dataset_id;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()};o(c.prototype,p.prototype,J.prototype,{set_dataset:function(Z){this.dataset_id=Z.get("id");this.hda_ldda=Z.get("hda_ldda");this.dataset=Z;this.data_manager.set("dataset",Z)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=I.ArcLinkedFeaturePainter}else{this.painter=I.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ao,aj,ae,ad){J.prototype.postdraw_actions.call(this,ao,ad);var ai=this,al;if(ai.mode==="Coverage"){var aa=-1;for(al=0;al<ao.length;al++){var ak=ao[al].max_val;if(ak>aa){aa=ak}}for(al=0;al<ao.length;al++){var aq=ao[al];if(aq.max_val!==aa){aq.html_elt.remove();ai.draw_helper(true,aj,aq.index,aq.resolution,aq.html_elt.parent(),ae,{more_tile_data:{max:aa}})}}}if(ai.filters_manager){var af=ai.filters_manager.filters;for(var an=0;an<af.length;an++){af[an].update_ui_elt()}var ap=false,Z,ag;for(al=0;al<ao.length;al++){if(ao[al].data.length){Z=ao[al].data[0];for(var an=0;an<af.length;an++){ag=af[an];if(ag.applies_to(Z)&&ag.min!==ag.max){ap=true;break}}}}if(ai.filters_available!==ap){ai.filters_available=ap;if(!ai.filters_available){ai.filters_manager.hide()}ai.update_icons()}}this.container_div.find(".yaxislabel").remove();var ac=ao[0];if(ac instanceof j){var ah=(this.prefs.histogram_max?this.prefs.histogram_max:ac.max_val),ab=$("<div/>").text(ah).make_text_editable({num_cols:12,on_finish:function(ar){$(".bs-tooltip").remove();var ar=parseFloat(ar);ai.prefs.histogram_max=(!isNaN(ar)?ar:null);ai.tile_cache.clear();ai.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ab)}if(ac instanceof L){var am=true;for(al=0;al<ao.length;al++){if(!ao[al].all_slotted){am=false;break}}if(!am){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(Z){var Z;if(this.mode==="Auto"){if(Z==="no_detail"){Z="feature spans"}else{if(Z==="summary_tree"){Z="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+Z+")")}},incremental_slots:function(ad,Z,ac){var aa=this.view.canvas_manager.dummy_context,ab=this.slotters[ad];if(!ab||(ab.mode!==ac)){ab=new (s.FeatureSlotter)(ad,ac,x,function(ae){return aa.measureText(ae)});this.slotters[ad]=ab}return ab.slot_features(Z)},get_mode:function(Z){if(Z.dataset_type==="summary_tree"){mode="summary_tree"}else{if(Z.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>F){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(Z,ad,ae,aa){if(ad==="summary_tree"||ad==="Coverage"){return this.summary_draw_height}else{var ac=this.incremental_slots(ae,Z.data,ad);var ab=new (this.painter)(null,null,null,this.prefs,ad);return Math.max(Y,ab.get_required_height(ac,aa))}},draw_tile:function(aj,an,al,ao,ac,ag,ab){var am=this,aa=an.canvas,av=ac.get("start"),Z=ac.get("end"),ad=this.left_offset;if(al==="summary_tree"||al==="Coverage"){var ax=new I.SummaryTreePainter(aj,av,Z,this.prefs);ax.draw(an,aa.width,aa.height,ag);return new j(am,ac,ao,aa,aj.data,aj.max)}var af=[],ak=this.slotters[ag].slots;all_slotted=true;if(aj.data){var ah=this.filters_manager.filters;for(var ap=0,ar=aj.data.length;ap<ar;ap++){var ae=aj.data[ap];var aq=false;var ai;for(var au=0,az=ah.length;au<az;au++){ai=ah[au];ai.update_attrs(ae);if(!ai.keep(ae)){aq=true;break}}if(!aq){af.push(ae);if(!(ae[0] in ak)){all_slotted=false}}}}var ay=(this.filters_manager.alpha_filter?new z(this.filters_manager.alpha_filter):null);var aw=(this.filters_manager.height_filter?new z(this.filters_manager.height_filter):null);var ax=new (this.painter)(af,av,Z,this.prefs,al,ay,aw,ab);var at=null;an.fillStyle=this.prefs.block_color;an.font=an.canvas.manager.default_font;an.textAlign="right";if(aj.data){at=ax.draw(an,aa.width,aa.height,ag,ak);at.translation=-ad}return new L(am,ac,ao,aa,aj.data,ag,al,aj.message,all_slotted,at)},data_and_mode_compatible:function(Z,aa){if(aa==="Auto"){return true}else{if(aa==="Coverage"){return Z.dataset_type==="summary_tree"}else{if(Z.extra_info==="no_detail"||Z.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(Z){if(Z.dataset_type==="summary_tree"||Z.message||Z.extra_info==="no_detail"){return false}return true}});var O=function(aa,Z,ab){c.call(this,aa,Z,ab);this.config=new C({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ab.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=I.ReadPainter};o(O.prototype,p.prototype,J.prototype,c.prototype);var R=function(ab,aa,ad){c.call(this,ab,aa,ad);var ac=get_random_color(),Z=get_random_color([ac,"#ffffff"]);this.config=new C({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:ac},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:Z},{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:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ad.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=I.ReadPainter;this.update_icons()};o(R.prototype,p.prototype,J.prototype,c.prototype);S.View=X;S.DrawableGroup=M;S.LineTrack=i;S.FeatureTrack=c;S.DiagonalHeatmapTrack=r;S.ReadTrack=R;S.VcfTrack=O;S.CompositeTrack=g};var slotting_module=function(c,b){var e=c("class").extend;var d=2,a=5;b.FeatureSlotter=function(i,h,f,g){this.slots={};this.start_end_dct={};this.w_scale=i;this.mode=h;this.include_label=(h==="Pack");this.max_rows=f;this.measureText=g};e(b.FeatureSlotter.prototype,{slot_features:function(m){var p=this.w_scale,h=this.start_end_dct,x=[],z=[],n=0,y=this.max_rows;for(var v=0,w=m.length;v<w;v++){var k=m[v],o=k[0];if(this.slots[o]!==undefined){n=Math.max(n,this.slots[o]);z.push(this.slots[o])}else{x.push(v)}}var q=function(E,F){for(var D=0;D<=y;D++){var B=false,G=h[D];if(G!==undefined){for(var A=0,C=G.length;A<C;A++){var i=G[A];if(F>i[0]&&E<i[1]){B=true;break}}}if(!B){return D}}return -1};for(var v=0,w=x.length;v<w;v++){var k=m[x[v]],o=k[0],t=k[1],f=k[2],r=k[3],g=Math.floor(t*p),l=Math.ceil(f*p),u=this.measureText(r).width,j;if(r!==undefined&&this.include_label){u+=(d+a);if(g-u>=0){g-=u;j="left"}else{l+=u;j="right"}}var s=q(g,l);if(s>=0){if(h[s]===undefined){h[s]=[]}h[s].push([g,l]);this.slots[o]=s;n=Math.max(n,s)}}return n+1}})};var painters_module=function(require,exports){var extend=require("class").extend;var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var SummaryTreePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode)};SummaryTreePainter.prototype.default_prefs={show_counts:false};SummaryTreePainter.prototype.draw=function(ctx,width,height,w_scale){var view_start=this.view_start,points=this.data.data,max=(this.prefs.histogram_max?this.prefs.histogram_max:this.data.max),base_y=height;delta_x_px=Math.ceil(this.data.delta*w_scale);ctx.save();for(var i=0,len=points.length;i<len;i++){var x=Math.floor((points[i][0]-view_start)*w_scale);var y=points[i][1];if(!y){continue}var y_px=y/max*height;if(y!==0&&y_px<1){y_px=1}ctx.fillStyle=this.prefs.block_color;ctx.fillRect(x,base_y-y_px,delta_x_px,y_px);var text_padding_req_x=4;if(this.prefs.show_counts&&(ctx.measureText(y).width+text_padding_req_x)<delta_x_px){ctx.fillStyle=this.prefs.label_color;ctx.textAlign="center";ctx.fillText(y,x+(delta_x_px/2),10)}}ctx.restore()};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][1])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][1])}this.prefs.max_value=max_value}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var pref_color=parseInt(this.prefs.color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=this.prefs.color;x_scaled=Math.round((data[i][0]-view_start-1)*w_scale);y=data[i][1];var top_overflow=false,bot_overflow=false;if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=this.prefs.color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler())};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)+this.get_bottom_padding(width)},get_top_padding:function(width){return 0},get_bottom_padding:function(width){return Math.max(Math.round(this.get_row_height()/2),5)},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords;for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((feature_start<view_end&&feature_end>view_start)&&(this.mode==="Dense"||slot!==null)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1])}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return feature_mapper},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){console.log("WARNING: Unimplemented function.");return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2]-1,feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low)*w_scale))),draw_start=f_start,draw_end=f_end,y_center=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_center+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_center+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_center+1,f_end-f_start,thick_height)}}else{var cur_y_center,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_center=y_center+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_center=y_center;cur_height=thick_height}else{cur_y_center+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_center,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-1-tile_low)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_center+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_center+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_center+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_center)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_center+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_center+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_center+8);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_center+8);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null)};extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},draw_read:function(ctx,mode,w_scale,y_center,tile_low,tile_high,feature_start,cigar,strand,orig_seq){ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=0,char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.block_color:this.prefs.reverse_strand_color);var draw_last=[];if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){gap=Math.round(w_scale/2)}if(!cigar){cigar=[[0,orig_seq.length]]}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];if(cig_op==="H"||cig_op==="S"){base_offset-=cig_len}var seq_start=(feature_start-1)+base_offset,s_start=Math.floor(Math.max(0,(seq_start-tile_low)*w_scale)),s_end=Math.floor(Math.max(0,(seq_start+cig_len-tile_low)*w_scale));if(s_start===s_end){s_end+=1}switch(cig_op){case"H":break;case"S":case"M":case"=":if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=orig_seq.slice(seq_offset,seq_offset+cig_len);if(gap>0){ctx.fillStyle=block_color;ctx.fillRect(s_start-gap,y_center+1,s_end-s_start,9);ctx.fillStyle=CONNECTOR_COLOR;for(var c=0,str_len=seq.length;c<str_len;c++){if(this.prefs.show_differences){if(this.ref_seq){var ref_char=this.ref_seq[seq_start-tile_low+c];if(!ref_char||ref_char.toLowerCase()===seq[c].toLowerCase()){continue}}else{continue}}if(seq_start+c>=tile_low&&seq_start+c<=tile_high){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start,y_center+9)}}}else{ctx.fillStyle=block_color;ctx.fillRect(s_start,y_center+4,s_end-s_start,SQUISH_FEATURE_HEIGHT)}}seq_offset+=cig_len;base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start-gap,y_center+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":ctx.fillStyle="red";ctx.fillRect(s_start-gap,y_center+4,s_end-s_start,3);base_offset+=cig_len;break;case"P":break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=orig_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_center-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_center+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_center)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_center+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&orig_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_center+9]})}else{}}}seq_offset+=cig_len;break;case"X":seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(0,(feature_start-tile_low)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low)*w_scale))),y_center=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color,gap=0;if((mode==="Pack"||this.mode==="Auto")&&w_scale>ctx.canvas.manager.char_width_px){var gap=Math.round(w_scale/2)}if(feature[5] instanceof Array){var b1_start=Math.floor(Math.max(0,(feature[4][0]-tile_low)*w_scale)),b1_end=Math.ceil(Math.min(width,Math.max(0,(feature[4][1]-tile_low)*w_scale))),b2_start=Math.floor(Math.max(0,(feature[5][0]-tile_low)*w_scale)),b2_end=Math.ceil(Math.min(width,Math.max(0,(feature[5][1]-tile_low)*w_scale))),connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end-gap,y_center+5,b2_start-gap,y_center+5)}}else{this.draw_read(ctx,mode,w_scale,y_center,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;var tile_index=1;if(tile_index===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING-gap,y_center+8)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING-gap,y_center+8)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_center){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_center,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"4169E1",neg_color:"FF8C00"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};exports.Scaler=Scaler;exports.SummaryTreePainter=SummaryTreePainter;exports.LinePainter=LinePainter;exports.LinkedFeaturePainter=LinkedFeaturePainter;exports.ReadPainter=ReadPainter;exports.ArcLinkedFeaturePainter=ArcLinkedFeaturePainter;exports.DiagonalHeatmapPainter=DiagonalHeatmapPainter};(function(d){var c={};var b=function(e){return c[e]};var a=function(f,g){var e={};g(b,e);c[f]=e};a("class",class_module);a("slotting",slotting_module);a("painters",painters_module);a("trackster",trackster_module);for(key in c.trackster){d[key]=c.trackster[key]}})(window);
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-(function(){var f=Backbone.Model.extend({defaults:{ajax_settings:{},interval:1000,success_fn:function(t){return true}},go:function(){var w=$.Deferred(),v=this,y=v.get("ajax_settings"),x=v.get("success_fn"),u=v.get("interval"),t=function(){$.ajax(y).success(function(z){if(x(z)){w.resolve(z)}else{setTimeout(t,u)}})};t();return w}});var g=function(t){this.default_font=t!==undefined?t:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};_.extend(g.prototype,{load_pattern:function(t,x){var u=this.patterns,v=this.dummy_context,w=new Image();w.src=galaxy_paths.attributes.image_path+x;w.onload=function(){u[t]=v.createPattern(w,"repeat")}},get_pattern:function(t){return this.patterns[t]},new_canvas:function(){var t=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(t)}t.manager=this;return t}});var p=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(t){this.clear()},get_elt:function(u){var v=this.attributes.obj_cache,w=this.attributes.key_ary,t=w.indexOf(u);if(t!==-1){if(v[u].stale){w.splice(t,1);delete v[u]}else{this.move_key_to_end(u,t)}}return v[u]},set_elt:function(u,w){var x=this.attributes.obj_cache,y=this.attributes.key_ary,v=this.attributes.num_elements;if(!x[u]){if(y.length>=v){var t=y.shift();delete x[t]}y.push(u)}x[u]=w;return w},move_key_to_end:function(u,t){this.attributes.key_ary.splice(t,1);this.attributes.key_ary.push(u)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=p.extend({defaults:_.extend({},p.prototype.defaults,{dataset:null,filters_manager:null,data_url:null,dataset_state_url:null,feature_search_url:null,genome_wide_summary_data:null,data_mode_compatible:function(t,u){return true},can_subset:function(t){return false}}),data_is_ready:function(){var v=this.get("dataset"),u=$.Deferred(),t=new f({ajax_settings:{url:this.get("dataset_state_url"),data:{dataset_id:v.id,hda_ldda:v.get("hda_ldda")},dataType:"json"},interval:5000,success_fn:function(w){return w!=="pending"}});$.when(t.go()).then(function(w){u.resolve(w==="ok"||w==="data")});return u},search_features:function(t){var u=this.get("dataset"),v={query:t,dataset_id:u.id,hda_ldda:u.get("hda_ldda")};return $.getJSON(this.get("feature_search_url"),v)},load_data:function(B,A,u,z){var w={chrom:B.get("chrom"),low:B.get("start"),high:B.get("end"),mode:A,resolution:u},x=this.get("dataset");if(x){w.dataset_id=x.id;w.hda_ldda=x.get("hda_ldda")}$.extend(w,z);var C=this.get("filters_manager");if(C){var D=[];var t=C.filters;for(var y=0;y<t.length;y++){D.push(t[y].name)}w.filter_cols=JSON.stringify(D)}var v=this;return $.getJSON(this.get("data_url"),w,function(E){v.set_data(B,E)})},get_data:function(z,y,v,x){var A=this.get_elt(z);if(A&&(is_deferred(A)||this.get("data_mode_compatible")(A,y))){return A}var B=this.get("key_ary"),u=this.get("obj_cache"),C,t;for(var w=0;w<B.length;w++){C=B[w];t=new h({from_str:C});if(t.contains(z)){A=u[C];if(is_deferred(A)||(this.get("data_mode_compatible")(A,y)&&this.get("can_subset")(A))){this.move_key_to_end(C,w);return A}}}A=this.load_data(z,y,v,x);this.set_data(z,A);return A},set_data:function(u,t){this.set_elt(u,t)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(B,A,w,z,x){var D=this.get_elt(B);if(!(D&&this.get("data_mode_compatible")(D,A))){console.log("ERROR: no current data for: ",dataset,B.toString(),A,w,z);return}D.stale=true;var v=B.get("start");if(x===this.DEEP_DATA_REQ){$.extend(z,{start_val:D.data.length+1})}else{if(x===this.BROAD_DATA_REQ){v=(D.max_high?D.max_high:D.data[D.data.length-1][2])+1}}var C=B.copy().set("start",v);var u=this,y=this.load_data(C,A,w,z),t=$.Deferred();this.set_data(B,t);$.when(y).then(function(E){if(E.data){E.data=D.data.concat(E.data);if(E.max_low){E.max_low=D.max_low}if(E.message){E.message=E.message.replace(/[0-9]+/,E.data.length)}}u.set_data(B,E);t.resolve(E)});return t},get_elt:function(t){return p.prototype.get_elt.call(this,t.toString())},set_elt:function(u,t){return p.prototype.set_elt.call(this,u.toString(),t)}});var n=d.extend({load_data:function(t,w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,t,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info}});var h=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006},initialize:function(u){if(u.from_str){var w=u.from_str.split(":"),v=w[0],t=w[1].split("-");this.set({chrom:v,start:parseInt(t[0],10),end:parseInt(t[1],10)})}},copy:function(){return new h({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(A){var u=this.get("chrom"),z=A.get("chrom"),y=this.get("start"),w=A.get("start"),x=this.get("end"),v=A.get("end"),t;if(u&&z&&u!==z){return this.get("DIF_CHROMS")}if(y<w){if(x<w){t=this.get("BEFORE")}else{if(x<=v){t=this.get("OVERLAP_START")}else{t=this.get("CONTAINS")}}}else{if(y>v){t=this.get("AFTER")}else{if(x<=v){t=this.get("CONTAINED_BY")}else{t=this.get("OVERLAP_END")}}}return t},contains:function(t){return this.compute_overlap(t)===this.get("CONTAINS")},overlaps:function(t){return _.intersection([this.compute_overlap(t)],[this.get("DIF_CHROMS"),this.get("BEFORE"),this.get("AFTER")]).length===0}});var l=Backbone.Collection.extend({model:h});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:h}]});var q=Backbone.Collection.extend({model:e});var b=Backbone.Model.extend({defaults:{data:null,min:0,max:0},initialize:function(u){var t=_.flatten(_.map(this.get("data"),function(v){if(v.data.length!==0){return _.map(v.data,function(w){return w[1]})}else{return 0}}));this.set("max",_.max(t));this.set("min",_.min(t))}});var m=Backbone.RelationalModel.extend({defaults:{data:null,min:0,max:0},initialize:function(u){var t=_.max(this.get("data"),function(v){if(!v||typeof v==="string"){return 0}return v[1]});this.attributes.max=(t&&typeof t!=="string"?t[1]:0)}});var s=Dataset.extend({initialize:function(t){this.set("id",t.dataset_id);var v=this.get("genome_wide_data");if(v){var u=(this.get("track_type")==="LineTrack"?b:m);this.set("genome_wide_data",new u(v))}}});var o=Backbone.RelationalModel.extend({defaults:{id:"",title:"",type:"",dbkey:"",tracks:null},relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:s}],url:function(){return galaxy_paths.get("visualization_url")},save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:_.extend({},o.prototype.defaults,{bookmarks:null,viewport:null})});var a=Backbone.Model.extend({});var i=Backbone.Router.extend({initialize:function(u){this.view=u.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var t=this;t.view.on("navigate",function(v){t.navigate(v)})},change_location:function(t){this.view.go_to(t)}});var j=function(t,v,u){$.ajax({url:t,data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(w){show_modal("Select datasets for new tracks",w,{Cancel:function(){hide_modal()},Add:function(){var x=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var y,z=$(this).val();if($(this).attr("name")==="id"){y={hda_id:z}}else{y={ldda_id:z}}x[x.length]=$.ajax({url:v,data:y,dataType:"json"})});$.when.apply($,x).then(function(){var y=(arguments[0] instanceof Array?$.map(arguments,function(z){return z[0]}):[arguments[0]]);u(y)});hide_modal()}})}})};var r=(function(){if(typeof module!=="undefined"&&module.exports){return module.exports}else{if(typeof define==="function"&&define.amd){r={};define(function(){return r});return r}else{return window}}})();r.BrowserBookmark=e;r.BrowserBookmarkCollection=q;r.Cache=p;r.CanvasManager=g;r.Genome=c;r.GenomeDataManager=d;r.GenomeRegion=h;r.GenomeRegionCollection=l;r.GenomeVisualization=k;r.GenomeWideBigWigData=b;r.GenomeWideSummaryTreeData=m;r.ReferenceTrackDataManager=n;r.ServerStateDeferred=f;r.TrackBrowserRouter=i;r.TrackConfig=a;r.Visualization=o;r.add_datasets=j}).call(this);
\ No newline at end of file
+(function(){var f=Backbone.Model.extend({defaults:{ajax_settings:{},interval:1000,success_fn:function(t){return true}},go:function(){var w=$.Deferred(),v=this,y=v.get("ajax_settings"),x=v.get("success_fn"),u=v.get("interval"),t=function(){$.ajax(y).success(function(z){if(x(z)){w.resolve(z)}else{setTimeout(t,u)}})};t();return w}});var g=function(t){this.default_font=t!==undefined?t:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};_.extend(g.prototype,{load_pattern:function(t,x){var u=this.patterns,v=this.dummy_context,w=new Image();w.src=galaxy_paths.attributes.image_path+x;w.onload=function(){u[t]=v.createPattern(w,"repeat")}},get_pattern:function(t){return this.patterns[t]},new_canvas:function(){var t=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(t)}t.manager=this;return t}});var p=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(t){this.clear()},get_elt:function(u){var v=this.attributes.obj_cache,w=this.attributes.key_ary,t=w.indexOf(u);if(t!==-1){if(v[u].stale){w.splice(t,1);delete v[u]}else{this.move_key_to_end(u,t)}}return v[u]},set_elt:function(u,w){var x=this.attributes.obj_cache,y=this.attributes.key_ary,v=this.attributes.num_elements;if(!x[u]){if(y.length>=v){var t=y.shift();delete x[t]}y.push(u)}x[u]=w;return w},move_key_to_end:function(u,t){this.attributes.key_ary.splice(t,1);this.attributes.key_ary.push(u)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=p.extend({defaults:_.extend({},p.prototype.defaults,{dataset:null,filters_manager:null,data_type:"data",genome_wide_summary_data:null,data_mode_compatible:function(t,u){return true},can_subset:function(t){return false}}),data_is_ready:function(){var v=this.get("dataset"),u=$.Deferred(),t=new f({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:v.get("hda_ldda"),data_type:"state"},dataType:"json"},interval:5000,success_fn:function(w){return w!=="pending"}});$.when(t.go()).then(function(w){u.resolve(w==="ok"||w==="data")});return u},search_features:function(t){var u=this.get("dataset"),v={query:t,dataset_id:u.id,hda_ldda:u.get("hda_ldda"),data_type:"features"};return $.getJSON(u.url(),v)},load_data:function(B,A,u,z){var w={data_type:this.get("data_type"),chrom:B.get("chrom"),low:B.get("start"),high:B.get("end"),mode:A,resolution:u},x=this.get("dataset");if(x){w.dataset_id=x.id;w.hda_ldda=x.get("hda_ldda")}$.extend(w,z);var C=this.get("filters_manager");if(C){var D=[];var t=C.filters;for(var y=0;y<t.length;y++){D.push(t[y].name)}w.filter_cols=JSON.stringify(D)}var v=this;return $.getJSON(x.url(),w,function(E){v.set_data(B,E)})},get_data:function(z,y,v,x){var A=this.get_elt(z);if(A&&(is_deferred(A)||this.get("data_mode_compatible")(A,y))){return A}var B=this.get("key_ary"),u=this.get("obj_cache"),C,t;for(var w=0;w<B.length;w++){C=B[w];t=new h({from_str:C});if(t.contains(z)){A=u[C];if(is_deferred(A)||(this.get("data_mode_compatible")(A,y)&&this.get("can_subset")(A))){this.move_key_to_end(C,w);return A}}}A=this.load_data(z,y,v,x);this.set_data(z,A);return A},set_data:function(u,t){this.set_elt(u,t)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(B,A,w,z,x){var D=this.get_elt(B);if(!(D&&this.get("data_mode_compatible")(D,A))){console.log("ERROR: no current data for: ",dataset,B.toString(),A,w,z);return}D.stale=true;var v=B.get("start");if(x===this.DEEP_DATA_REQ){$.extend(z,{start_val:D.data.length+1})}else{if(x===this.BROAD_DATA_REQ){v=(D.max_high?D.max_high:D.data[D.data.length-1][2])+1}}var C=B.copy().set("start",v);var u=this,y=this.load_data(C,A,w,z),t=$.Deferred();this.set_data(B,t);$.when(y).then(function(E){if(E.data){E.data=D.data.concat(E.data);if(E.max_low){E.max_low=D.max_low}if(E.message){E.message=E.message.replace(/[0-9]+/,E.data.length)}}u.set_data(B,E);t.resolve(E)});return t},get_elt:function(t){return p.prototype.get_elt.call(this,t.toString())},set_elt:function(u,t){return p.prototype.set_elt.call(this,u.toString(),t)}});var n=d.extend({load_data:function(t,w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,t,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info}});var h=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006},initialize:function(u){if(u.from_str){var w=u.from_str.split(":"),v=w[0],t=w[1].split("-");this.set({chrom:v,start:parseInt(t[0],10),end:parseInt(t[1],10)})}},copy:function(){return new h({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(A){var u=this.get("chrom"),z=A.get("chrom"),y=this.get("start"),w=A.get("start"),x=this.get("end"),v=A.get("end"),t;if(u&&z&&u!==z){return this.get("DIF_CHROMS")}if(y<w){if(x<w){t=this.get("BEFORE")}else{if(x<=v){t=this.get("OVERLAP_START")}else{t=this.get("CONTAINS")}}}else{if(y>v){t=this.get("AFTER")}else{if(x<=v){t=this.get("CONTAINED_BY")}else{t=this.get("OVERLAP_END")}}}return t},contains:function(t){return this.compute_overlap(t)===this.get("CONTAINS")},overlaps:function(t){return _.intersection([this.compute_overlap(t)],[this.get("DIF_CHROMS"),this.get("BEFORE"),this.get("AFTER")]).length===0}});var l=Backbone.Collection.extend({model:h});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:h}]});var q=Backbone.Collection.extend({model:e});var b=Backbone.Model.extend({defaults:{data:null,min:0,max:0},initialize:function(u){var t=_.flatten(_.map(this.get("data"),function(v){if(v.data.length!==0){return _.map(v.data,function(w){return w[1]})}else{return 0}}));this.set("max",_.max(t));this.set("min",_.min(t))}});var m=Backbone.RelationalModel.extend({defaults:{data:null,min:0,max:0},initialize:function(u){var t=_.max(this.get("data"),function(v){if(!v||typeof v==="string"){return 0}return v[1]});this.attributes.max=(t&&typeof t!=="string"?t[1]:0)}});var s=Dataset.extend({initialize:function(t){this.set("id",t.dataset_id);var v=this.get("genome_wide_data");if(v){var u=(this.get("track_type")==="LineTrack"?b:m);this.set("genome_wide_data",new u(v))}}});var o=Backbone.RelationalModel.extend({defaults:{id:"",title:"",type:"",dbkey:"",tracks:null},relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:s}],url:function(){return galaxy_paths.get("visualization_url")},save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:_.extend({},o.prototype.defaults,{bookmarks:null,viewport:null})});var a=Backbone.Model.extend({});var i=Backbone.Router.extend({initialize:function(u){this.view=u.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var t=this;t.view.on("navigate",function(v){t.navigate(v)})},change_location:function(t){this.view.go_to(t)}});var j=function(t,v,u){$.ajax({url:t,data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(w){show_modal("Select datasets for new tracks",w,{Cancel:function(){hide_modal()},Add:function(){var x=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var y={data_type:"track_config",hda_ldda:"hda"},z=$(this).val();if($(this).attr("name")!=="id"){y.hda_ldda="ldda"}x[x.length]=$.ajax({url:v+"/"+z,data:y,dataType:"json"})});$.when.apply($,x).then(function(){var y=(arguments[0] instanceof Array?$.map(arguments,function(z){return z[0]}):[arguments[0]]);u(y)});hide_modal()}})}})};var r=(function(){if(typeof module!=="undefined"&&module.exports){return module.exports}else{if(typeof define==="function"&&define.amd){r={};define(function(){return r});return r}else{return window}}})();r.BrowserBookmark=e;r.BrowserBookmarkCollection=q;r.Cache=p;r.CanvasManager=g;r.Genome=c;r.GenomeDataManager=d;r.GenomeRegion=h;r.GenomeRegionCollection=l;r.GenomeVisualization=k;r.GenomeWideBigWigData=b;r.GenomeWideSummaryTreeData=m;r.ReferenceTrackDataManager=n;r.ServerStateDeferred=f;r.TrackBrowserRouter=i;r.TrackConfig=a;r.Visualization=o;r.add_datasets=j}).call(this);
\ No newline at end of file
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/viz/trackster.js
--- a/static/scripts/viz/trackster.js
+++ b/static/scripts/viz/trackster.js
@@ -2974,21 +2974,18 @@
//
// Attribute init.
//
- var url_base = datasets_url + '/' + obj_dict.dataset_id;
- this.data_url = ('data_url' in obj_dict ? obj_dict.data_url : url_base);
+ this.dataset = new Dataset({
+ id: obj_dict.dataset_id,
+ hda_ldda: obj_dict.hda_ldda
+ });
+ this.dataset_check_type = 'converted_datasets_state';
this.data_url_extra_params = {};
this.data_query_wait = ('data_query_wait' in obj_dict ? obj_dict.data_query_wait : DEFAULT_DATA_QUERY_WAIT);
// A little ugly creating data manager right now due to transition to Backbone-based objects.
- var track = this,
- dataset = new Dataset({
- id: obj_dict.dataset_id,
- hda_ldda: obj_dict.hda_ldda
- });
this.data_manager = ('data_manager' in obj_dict ?
obj_dict.data_manager :
new GenomeDataManager({
- dataset: dataset,
- data_url: track.data_url,
+ dataset: this.dataset,
data_mode_compatible: this.data_and_mode_compatible,
can_subset: this.can_subset
}));
@@ -3311,9 +3308,9 @@
var init_deferred = $.Deferred(),
params = {
hda_ldda: track.hda_ldda,
- data_type: 'converted_datasets_state',
- chrom: track.view.chrom}
- $.getJSON(this.data_url, params, function (result) {
+ data_type: this.dataset_check_type,
+ chrom: track.view.chrom };
+ $.getJSON(this.dataset.url(), params, function (result) {
if (!result || result === "error" || result.kind === "error") {
track.container_div.addClass("error");
track.tiles_div.text(DATA_ERROR);
@@ -3829,11 +3826,10 @@
* Set up track to receive tool data.
*/
init_for_tool_data: function() {
- // Set up track to fetch initial data from raw data URL when the dataset--not the converted datasets--
- // is ready.
- this.data_manager.set('data_url', raw_data_url);
+ // Set up track to fetch raw data rather than converted data.
+ this.data_manager.set('data_type', 'raw_data');
this.data_query_wait = 1000;
- this.dataset_check_url = dataset_state_url;
+ this.dataset_check_type = 'state';
//
// Set up one-time, post-draw to clear tool execution settings.
@@ -3860,8 +3856,10 @@
success_fn: function(result) { return result !== "pending"; }
});
$.when(ss_deferred.go()).then(function() {
- // Dataset is indexed, so use default data URL.
- self.data_manager.set('data_url', default_data_url);
+ // Dataset is indexed, so use converted data.
+ self.data_manager.set('data_type', 'data');
+ self.dataset_check_type = 'converted_datasets_state';
+ this.data_query_wait = 5000;
});
// Reset post-draw actions function.
@@ -4319,7 +4317,7 @@
predraw_init: function() {
var track = this;
track.vertical_range = undefined;
- return $.getJSON( track.data_url,
+ return $.getJSON( track.dataset.url(),
{ data_type: 'data', stats: true, chrom: track.view.chrom, low: 0,
high: track.view.max_high, hda_ldda: track.hda_ldda, dataset_id:
track.dataset_id }, function(result) {
@@ -4541,6 +4539,7 @@
set_dataset: function(dataset) {
this.dataset_id = dataset.get('id');
this.hda_ldda = dataset.get('hda_ldda');
+ this.dataset = dataset;
this.data_manager.set('dataset', dataset);
},
diff -r 6243b992762c3f90abda948e081d266ca63e1db0 -r 2f63df92248894e78f9113fb79107fcbd6e12ff7 static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -169,8 +169,7 @@
defaults: _.extend({}, Cache.prototype.defaults, {
dataset: null,
filters_manager: null,
- data_url: null,
- feature_search_url: null,
+ data_type: "data",
genome_wide_summary_data: null,
data_mode_compatible: function(entry, mode) { return true; },
can_subset: function(entry) { return false; }
@@ -185,9 +184,8 @@
ready_deferred = $.Deferred(),
ss_deferred = new ServerStateDeferred({
ajax_settings: {
- url: this.get('data_url'),
+ url: this.get('dataset').url(),
data: {
- dataset_id: dataset.id,
hda_ldda: dataset.get('hda_ldda'),
data_type: 'state'
},
@@ -214,7 +212,7 @@
hda_ldda: dataset.get('hda_ldda'),
data_type: 'features'
};
- return $.getJSON(this.get('data_url'), params);
+ return $.getJSON(dataset.url(), params);
},
/**
@@ -223,7 +221,7 @@
load_data: function(region, mode, resolution, extra_params) {
// Setup data request params.
var params = {
- "data_type": "data",
+ "data_type": this.get('data_type'),
"chrom": region.get('chrom'),
"low": region.get('start'),
"high": region.get('end'),
@@ -253,7 +251,7 @@
// Do request.
var manager = this;
- return $.getJSON(this.get('data_url'), params, function (result) {
+ return $.getJSON(dataset.url(), params, function (result) {
manager.set_data(region, result);
});
},
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: Viz framework refactoring: move visualization view methods into base class and move chromosome/reference data methods to API.
by Bitbucket 14 Sep '12
by Bitbucket 14 Sep '12
14 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/0d077bcf9ab7/
changeset: 0d077bcf9ab7
user: jgoecks
date: 2012-09-14 23:57:07
summary: Viz framework refactoring: move visualization view methods into base class and move chromosome/reference data methods to API.
affected #: 8 files
diff -r 81e32d70ee2daf03228752992b1765904f7e93fa -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 lib/galaxy/web/api/genomes.py
--- a/lib/galaxy/web/api/genomes.py
+++ b/lib/galaxy/web/api/genomes.py
@@ -2,13 +2,16 @@
from galaxy.web.base.controller import BaseController, BaseAPIController
from galaxy.util.bunch import Bunch
+def is_true ( a_str ):
+ return is_true == True or a_str in [ 'True', 'true', 'T', 't' ]
+
class GenomesController( BaseAPIController ):
"""
RESTful controller for interactions with genome data.
"""
@web.expose_api
- def index( self, trans, **kwds ):
+ def index( self, trans, **kwd ):
"""
GET /api/genomes: returns a list of installed genomes
"""
@@ -16,13 +19,23 @@
return []
@web.json
- def show( self, trans, id, num=None, chrom=None, low=None ):
+ def show( self, trans, id, num=None, chrom=None, low=None, high=None, **kwd ):
"""
GET /api/genomes/{id}
Returns information about build <id>
"""
- return self.app.genomes.chroms( trans, dbkey=id, num=num, chrom=chrom, low=low )
+
+ # Process kwds.
+ reference = is_true( kwd.get( 'reference', False ) )
+
+ # Return info.
+ rval = None
+ if reference:
+ rval = self.app.genomes.reference( trans, dbkey=id, chrom=chrom, low=low, high=high, **kwd )
+ else:
+ rval = self.app.genomes.chroms( trans, dbkey=id, num=num, chrom=chrom, low=low )
+ return rval
@web.expose_api
def create( self, trans, payload, **kwd ):
diff -r 81e32d70ee2daf03228752992b1765904f7e93fa -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -626,6 +626,29 @@
return visualization
+ def _get_datasources( self, trans, dataset ):
+ """
+ Returns datasources for dataset; if datasources are not available
+ due to indexing, indexing is started. Return value is a dictionary
+ with entries of type
+ (<datasource_type> : {<datasource_name>, <indexing_message>}).
+ """
+ track_type, data_sources = dataset.datatype.get_track_type()
+ data_sources_dict = {}
+ msg = None
+ for source_type, data_source in data_sources.iteritems():
+ if source_type == "data_standalone":
+ # Nothing to do.
+ msg = None
+ else:
+ # Convert.
+ msg = self.convert_dataset( trans, dataset, data_source )
+
+ # Store msg.
+ data_sources_dict[ source_type ] = { "name" : data_source, "message": msg }
+
+ return data_sources_dict
+
class UsesStoredWorkflowMixin( SharableItemSecurityMixin ):
""" Mixin for controllers that use StoredWorkflow objects. """
def get_stored_workflow( self, trans, id, check_ownership=True, check_accessible=False ):
diff -r 81e32d70ee2daf03228752992b1765904f7e93fa -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py
+++ b/lib/galaxy/web/controllers/tracks.py
@@ -17,7 +17,7 @@
from galaxy.visualization.genomes import decode_dbkey, Genomes
from galaxy.visualization.genome.visual_analytics import get_dataset_job
-class TracksController( BaseUIController, UsesVisualizationMixin, UsesHistoryDatasetAssociationMixin, SharableMixin ):
+class TracksController( BaseUIController, UsesVisualizationMixin, SharableMixin ):
"""
Controller for track browser interface. Handles building a new browser from
datasets in the current history, and display of the resulting browser.
@@ -34,28 +34,6 @@
@web.require_login()
def new_browser( self, trans, **kwargs ):
return trans.fill_template( "tracks/new_browser.mako", dbkeys=trans.app.genomes.get_dbkeys_with_chrom_info( trans ), default_dbkey=kwargs.get("default_dbkey", None) )
-
- @web.json
- def bookmarks_from_dataset( self, trans, hda_id=None, ldda_id=None ):
- if hda_id:
- hda_ldda = "hda"
- dataset_id = hda_id
- elif ldda_id:
- hda_ldda = "ldda"
- dataset_id = ldda_id
- dataset = self.get_hda_or_ldda( trans, hda_ldda, dataset_id )
-
- rows = []
- if isinstance( dataset.datatype, Bed ):
- data = RawBedDataProvider( original_dataset=dataset ).get_iterator()
- for i, line in enumerate( data ):
- if ( i > 500 ): break
- fields = line.split()
- location = name = "%s:%s-%s" % ( fields[0], fields[1], fields[2] )
- if len( fields ) > 3:
- name = fields[4]
- rows.append( [location, name] )
- return { 'data': rows }
@web.json
def save( self, trans, vis_json ):
@@ -92,14 +70,6 @@
if trans.security.decode_id(new_dataset) in [ d["dataset_id"] for d in viz_config.get("tracks") ]:
new_dataset = None # Already in browser, so don't add
return trans.fill_template( 'tracks/browser.mako', config=viz_config, add_dataset=new_dataset )
-
- @web.json
- def chroms( self, trans, dbkey=None, num=None, chrom=None, low=None ):
- return self.app.genomes.chroms( trans, dbkey=dbkey, num=num, chrom=chrom, low=low )
-
- @web.json
- def reference( self, trans, dbkey, chrom, low, high, **kwargs ):
- return self.app.genomes.reference( trans, dbkey, chrom, low, high, **kwargs )
@web.json
def raw_data( self, trans, dataset_id, chrom, low, high, **kwargs ):
@@ -137,9 +107,7 @@
@web.json
def dataset_state( self, trans, dataset_id, **kwargs ):
""" Returns state of dataset. """
- # TODO: this code is copied from data() -- should refactor.
-
- # Dataset check.
+
dataset = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True )
msg = self.check_dataset_state( trans, dataset )
if not msg:
@@ -288,91 +256,3 @@
result = data_provider.get_data( chrom, int( low ), int( high ), int( start_val ), int( max_vals ), **kwargs )
result.update( { 'dataset_type': tracks_dataset_type, 'extra_info': extra_info } )
return result
-
- @web.expose
- def sweepster( self, trans, id=None, hda_ldda=None, dataset_id=None, regions=None ):
- """
- Creates a sweepster visualization using the incoming parameters. If id is available,
- get the visualization with the given id; otherwise, create a new visualization using
- a given dataset and regions.
- """
- # Need to create history if necessary in order to create tool form.
- trans.get_history( create=True )
-
- if id:
- # Loading a shared visualization.
- viz = self.get_visualization( trans, id )
- viz_config = self.get_visualization_config( trans, viz )
- dataset = self.get_dataset( trans, viz_config[ 'dataset_id' ] )
- else:
- # Loading new visualization.
- dataset = self.get_hda_or_ldda( trans, hda_ldda, dataset_id )
- job = get_dataset_job( dataset )
- viz_config = {
- 'dataset_id': dataset_id,
- 'tool_id': job.tool_id,
- 'regions': from_json_string( regions )
- }
-
- # Add tool, dataset attributes to config based on id.
- tool = trans.app.toolbox.get_tool( viz_config[ 'tool_id' ] )
- viz_config[ 'tool' ] = tool.to_dict( trans, for_display=True )
- viz_config[ 'dataset' ] = dataset.get_api_value()
-
- return trans.fill_template_mako( "visualization/sweepster.mako", config=viz_config )
-
- @web.expose
- def circster( self, trans, id, **kwargs ):
- vis = self.get_visualization( trans, id, check_ownership=False, check_accessible=True )
- viz_config = self.get_visualization_config( trans, vis )
-
- # Get genome info.
- dbkey = viz_config[ 'dbkey' ]
- chroms_info = self.app.genomes.chroms( trans, dbkey=dbkey )
- genome = { 'dbkey': dbkey, 'chroms_info': chroms_info }
-
- # Add genome-wide summary tree data to each track in viz.
- tracks = viz_config[ 'tracks' ]
- for track in tracks:
- # Get dataset and indexed datatype.
- dataset = self.get_hda_or_ldda( trans, track[ 'hda_ldda'], track[ 'dataset_id' ] )
- data_sources = self._get_datasources( trans, dataset )
- if 'data_standalone' in data_sources:
- indexed_type = data_sources['data_standalone']['name']
- data_provider = get_data_provider( indexed_type )( dataset )
- else:
- indexed_type = data_sources['index']['name']
- # Get converted dataset and append track's genome data.
- converted_dataset = dataset.get_converted_dataset( trans, indexed_type )
- data_provider = get_data_provider( indexed_type )( converted_dataset, dataset )
- # HACK: pass in additional params, which are only used for summary tree data, not BBI data.
- track[ 'genome_wide_data' ] = { 'data': data_provider.get_genome_data( chroms_info, level=4, detail_cutoff=0, draw_cutoff=0 ) }
-
- return trans.fill_template( 'visualization/circster.mako', viz_config=viz_config, genome=genome )
-
- # -----------------
- # Helper methods.
- # -----------------
-
- def _get_datasources( self, trans, dataset ):
- """
- Returns datasources for dataset; if datasources are not available
- due to indexing, indexing is started. Return value is a dictionary
- with entries of type
- (<datasource_type> : {<datasource_name>, <indexing_message>}).
- """
- track_type, data_sources = dataset.datatype.get_track_type()
- data_sources_dict = {}
- msg = None
- for source_type, data_source in data_sources.iteritems():
- if source_type == "data_standalone":
- # Nothing to do.
- msg = None
- else:
- # Convert.
- msg = self.convert_dataset( trans, dataset, data_source )
-
- # Store msg.
- data_sources_dict[ source_type ] = { "name" : data_source, "message": msg }
-
- return data_sources_dict
\ No newline at end of file
diff -r 81e32d70ee2daf03228752992b1765904f7e93fa -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py
+++ b/lib/galaxy/web/controllers/visualization.py
@@ -232,6 +232,73 @@
_histories_grid = HistorySelectionGrid()
_history_datasets_grid = HistoryDatasetsSelectionGrid()
_tracks_grid = TracksterSelectionGrid()
+
+ #
+ # -- Functions for listing visualizations. --
+ #
+
+ @web.expose
+ @web.require_login( "see all available libraries" )
+ def list_libraries( self, trans, **kwargs ):
+ """List all libraries that can be used for selecting datasets."""
+
+ # Render the list view
+ return self._libraries_grid( trans, **kwargs )
+
+ @web.expose
+ @web.require_login( "see a library's datasets that can added to this visualization" )
+ def list_library_datasets( self, trans, **kwargs ):
+ """List a library's datasets that can be added to a visualization."""
+
+ library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( kwargs.get('f-library') ) )
+ return trans.fill_template( '/tracks/library_datasets_select_grid.mako',
+ cntrller="library",
+ use_panels=False,
+ library=library,
+ created_ldda_ids='',
+ hidden_folder_ids='',
+ show_deleted=False,
+ comptypes=[],
+ current_user_roles=trans.get_current_user_roles(),
+ message='',
+ status="done" )
+
+ @web.expose
+ @web.require_login( "see all available histories" )
+ def list_histories( self, trans, **kwargs ):
+ """List all histories that can be used for selecting datasets."""
+
+ # Render the list view
+ return self._histories_grid( trans, **kwargs )
+
+ @web.expose
+ @web.require_login( "see current history's datasets that can added to this visualization" )
+ def list_current_history_datasets( self, trans, **kwargs ):
+ """ List a history's datasets that can be added to a visualization. """
+
+ kwargs[ 'f-history' ] = trans.security.encode_id( trans.get_history().id )
+ kwargs[ 'show_item_checkboxes' ] = 'True'
+ return self.list_history_datasets( trans, **kwargs )
+
+ @web.expose
+ @web.require_login( "see a history's datasets that can added to this visualization" )
+ def list_history_datasets( self, trans, **kwargs ):
+ """List a history's datasets that can be added to a visualization."""
+
+ # Render the list view
+ return self._history_datasets_grid( trans, **kwargs )
+
+ @web.expose
+ @web.require_login( "see all available datasets" )
+ def list_datasets( self, trans, **kwargs ):
+ """List all datasets that can be added as tracks"""
+
+ # Render the list view
+ return self._data_grid( trans, **kwargs )
+
+ @web.expose
+ def list_tracks( self, trans, **kwargs ):
+ return self._tracks_grid( trans, **kwargs )
@web.expose
def list_published( self, trans, *args, **kwargs ):
@@ -244,6 +311,38 @@
@web.expose
@web.require_login( "use Galaxy visualizations", use_panels=True )
+ def list( self, trans, *args, **kwargs ):
+ # Handle operation
+ if 'operation' in kwargs and 'id' in kwargs:
+ session = trans.sa_session
+ operation = kwargs['operation'].lower()
+ ids = util.listify( kwargs['id'] )
+ for id in ids:
+ item = session.query( model.Visualization ).get( trans.security.decode_id( id ) )
+ if operation == "delete":
+ item.deleted = True
+ if operation == "share or publish":
+ return self.sharing( trans, **kwargs )
+ session.flush()
+
+ # Build list of visualizations shared with user.
+ shared_by_others = trans.sa_session \
+ .query( model.VisualizationUserShareAssociation ) \
+ .filter_by( user=trans.get_user() ) \
+ .join( model.Visualization.table ) \
+ .filter( model.Visualization.deleted == False ) \
+ .order_by( desc( model.Visualization.update_time ) ) \
+ .all()
+
+ return trans.fill_template( "visualization/list.mako", grid=self._user_list_grid( trans, *args, **kwargs ), shared_by_others=shared_by_others )
+
+
+ #
+ # -- Functions for operating on visualizations. --
+ #
+
+ @web.expose
+ @web.require_login( "use Galaxy visualizations", use_panels=True )
def index( self, trans, *args, **kwargs ):
""" Lists user's saved visualizations. """
return self.list( trans, *args, **kwargs )
@@ -268,34 +367,7 @@
# Display the management page
trans.set_message( 'Copy created with name "%s"' % cloned_visualization.title )
return self.list( trans )
-
- @web.expose
- @web.require_login( "use Galaxy visualizations", use_panels=True )
- def list( self, trans, *args, **kwargs ):
- # Handle operation
- if 'operation' in kwargs and 'id' in kwargs:
- session = trans.sa_session
- operation = kwargs['operation'].lower()
- ids = util.listify( kwargs['id'] )
- for id in ids:
- item = session.query( model.Visualization ).get( trans.security.decode_id( id ) )
- if operation == "delete":
- item.deleted = True
- if operation == "share or publish":
- return self.sharing( trans, **kwargs )
- session.flush()
- # Build list of visualizations shared with user.
- shared_by_others = trans.sa_session \
- .query( model.VisualizationUserShareAssociation ) \
- .filter_by( user=trans.get_user() ) \
- .join( model.Visualization.table ) \
- .filter( model.Visualization.deleted == False ) \
- .order_by( desc( model.Visualization.update_time ) ) \
- .all()
-
- return trans.fill_template( "visualization/list.mako", grid=self._user_list_grid( trans, *args, **kwargs ), shared_by_others=shared_by_others )
-
@web.expose
@web.require_login( "modify Galaxy visualizations" )
def set_slug_async( self, trans, id, new_slug ):
@@ -608,68 +680,91 @@
template="visualization/create.mako" )
@web.expose
- @web.require_login( "see all available libraries" )
- def list_libraries( self, trans, **kwargs ):
- """List all libraries that can be used for selecting datasets."""
+ def circster( self, trans, id, **kwargs ):
+ """
+ Display a circster visualization.
+ """
+ vis = self.get_visualization( trans, id, check_ownership=False, check_accessible=True )
+ viz_config = self.get_visualization_config( trans, vis )
- # Render the list view
- return self._libraries_grid( trans, **kwargs )
+ # Get genome info.
+ dbkey = viz_config[ 'dbkey' ]
+ chroms_info = self.app.genomes.chroms( trans, dbkey=dbkey )
+ genome = { 'dbkey': dbkey, 'chroms_info': chroms_info }
+
+ # Add genome-wide summary tree data to each track in viz.
+ tracks = viz_config[ 'tracks' ]
+ for track in tracks:
+ # Get dataset and indexed datatype.
+ dataset = self.get_hda_or_ldda( trans, track[ 'hda_ldda'], track[ 'dataset_id' ] )
+ data_sources = self._get_datasources( trans, dataset )
+ if 'data_standalone' in data_sources:
+ indexed_type = data_sources['data_standalone']['name']
+ data_provider = get_data_provider( indexed_type )( dataset )
+ else:
+ indexed_type = data_sources['index']['name']
+ # Get converted dataset and append track's genome data.
+ converted_dataset = dataset.get_converted_dataset( trans, indexed_type )
+ data_provider = get_data_provider( indexed_type )( converted_dataset, dataset )
+ # HACK: pass in additional params, which are only used for summary tree data, not BBI data.
+ track[ 'genome_wide_data' ] = { 'data': data_provider.get_genome_data( chroms_info, level=4, detail_cutoff=0, draw_cutoff=0 ) }
+
+ return trans.fill_template( 'visualization/circster.mako', viz_config=viz_config, genome=genome )
@web.expose
- @web.require_login( "see a library's datasets that can added to this visualization" )
- def list_library_datasets( self, trans, **kwargs ):
- """List a library's datasets that can be added to a visualization."""
-
- library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( kwargs.get('f-library') ) )
- return trans.fill_template( '/tracks/library_datasets_select_grid.mako',
- cntrller="library",
- use_panels=False,
- library=library,
- created_ldda_ids='',
- hidden_folder_ids='',
- show_deleted=False,
- comptypes=[],
- current_user_roles=trans.get_current_user_roles(),
- message='',
- status="done" )
-
- @web.expose
- @web.require_login( "see all available histories" )
- def list_histories( self, trans, **kwargs ):
- """List all histories that can be used for selecting datasets."""
-
- # Render the list view
- return self._histories_grid( trans, **kwargs )
-
- @web.expose
- @web.require_login( "see current history's datasets that can added to this visualization" )
- def list_current_history_datasets( self, trans, **kwargs ):
- """ List a history's datasets that can be added to a visualization. """
-
- kwargs[ 'f-history' ] = trans.security.encode_id( trans.get_history().id )
- kwargs[ 'show_item_checkboxes' ] = 'True'
- return self.list_history_datasets( trans, **kwargs )
-
- @web.expose
- @web.require_login( "see a history's datasets that can added to this visualization" )
- def list_history_datasets( self, trans, **kwargs ):
- """List a history's datasets that can be added to a visualization."""
+ def sweepster( self, trans, id=None, hda_ldda=None, dataset_id=None, regions=None ):
+ """
+ Displays a sweepster visualization using the incoming parameters. If id is available,
+ get the visualization with the given id; otherwise, create a new visualization using
+ a given dataset and regions.
+ """
+ # Need to create history if necessary in order to create tool form.
+ trans.get_history( create=True )
- # Render the list view
- return self._history_datasets_grid( trans, **kwargs )
-
- @web.expose
- @web.require_login( "see all available datasets" )
- def list_datasets( self, trans, **kwargs ):
- """List all datasets that can be added as tracks"""
-
- # Render the list view
- return self._data_grid( trans, **kwargs )
-
- @web.expose
- def list_tracks( self, trans, **kwargs ):
- return self._tracks_grid( trans, **kwargs )
+ if id:
+ # Loading a shared visualization.
+ viz = self.get_visualization( trans, id )
+ viz_config = self.get_visualization_config( trans, viz )
+ dataset = self.get_dataset( trans, viz_config[ 'dataset_id' ] )
+ else:
+ # Loading new visualization.
+ dataset = self.get_hda_or_ldda( trans, hda_ldda, dataset_id )
+ job = get_dataset_job( dataset )
+ viz_config = {
+ 'dataset_id': dataset_id,
+ 'tool_id': job.tool_id,
+ 'regions': from_json_string( regions )
+ }
+
+ # Add tool, dataset attributes to config based on id.
+ tool = trans.app.toolbox.get_tool( viz_config[ 'tool_id' ] )
+ viz_config[ 'tool' ] = tool.to_dict( trans, for_display=True )
+ viz_config[ 'dataset' ] = dataset.get_api_value()
+
+ return trans.fill_template_mako( "visualization/sweepster.mako", config=viz_config )
def get_item( self, trans, id ):
return self.get_visualization( trans, id )
+
+ @web.json
+ def bookmarks_from_dataset( self, trans, hda_id=None, ldda_id=None ):
+ if hda_id:
+ hda_ldda = "hda"
+ dataset_id = hda_id
+ elif ldda_id:
+ hda_ldda = "ldda"
+ dataset_id = ldda_id
+ dataset = self.get_hda_or_ldda( trans, hda_ldda, dataset_id )
+
+ rows = []
+ if isinstance( dataset.datatype, Bed ):
+ data = RawBedDataProvider( original_dataset=dataset ).get_iterator()
+ for i, line in enumerate( data ):
+ if ( i > 500 ): break
+ fields = line.split()
+ location = name = "%s:%s-%s" % ( fields[0], fields[1], fields[2] )
+ if len( fields ) > 3:
+ name = fields[4]
+ rows.append( [location, name] )
+ return { 'data': rows }
diff -r 81e32d70ee2daf03228752992b1765904f7e93fa -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 static/scripts/viz/trackster.js
--- a/static/scripts/viz/trackster.js
+++ b/static/scripts/viz/trackster.js
@@ -1320,13 +1320,12 @@
*/
load_chroms: function(url_parms) {
url_parms.num = MAX_CHROMS_SELECTABLE;
- url_parms.dbkey = this.dbkey;
var
view = this,
chrom_data = $.Deferred();
$.ajax({
- url: chrom_url,
+ url: chrom_url + "/" + this.dbkey,
data: url_parms,
dataType: "json",
success: function (result) {
@@ -4198,10 +4197,10 @@
this.content_div.css("background", "none");
this.content_div.css("min-height", "0px");
this.content_div.css("border", "none");
- this.data_url = reference_url;
- this.data_url_extra_params = {dbkey: view.dbkey};
+ this.data_url = reference_url + "/" + this.view.dbkey;
+ this.data_url_extra_params = {reference: true};
this.data_manager = new ReferenceTrackDataManager({
- data_url: reference_url
+ data_url: this.data_url
});
this.hide_contents();
};
diff -r 81e32d70ee2daf03228752992b1765904f7e93fa -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 templates/base_panels.mako
--- a/templates/base_panels.mako
+++ b/templates/base_panels.mako
@@ -62,8 +62,7 @@
raw_data_url: '${h.url_for( controller="/tracks", action="raw_data" )}',
converted_datasets_state_url: '${h.url_for( controller="/tracks", action="converted_datasets_state" )}',
dataset_state_url: '${h.url_for( controller="/tracks", action="dataset_state" )}',
- sweepster_url: '${h.url_for( controller="/tracks", action="sweepster" )}',
-
+ sweepster_url: '${h.url_for( controller="/visualization", action="sweepster" )}',
visualization_url: '${h.url_for( controller="/visualization", action="save" )}',
});
</script>
diff -r 81e32d70ee2daf03228752992b1765904f7e93fa -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -113,7 +113,7 @@
title: 'Circster',
on_click: function() {
// Add viz id dynamically so that newly saved visualizations work as well.
- window.location = "${h.url_for( controller='tracks', action='circster' )}?id=" + view.vis_id;
+ window.location = "${h.url_for( controller='visualization', action='circster' )}?id=" + view.vis_id;
}
},
{ icon_class: 'disk--arrow', title: 'Save', on_click: function() {
diff -r 81e32d70ee2daf03228752992b1765904f7e93fa -r 0d077bcf9ab71ea928fb832cf85a9f7f4f20b5f8 templates/visualization/trackster_common.mako
--- a/templates/visualization/trackster_common.mako
+++ b/templates/visualization/trackster_common.mako
@@ -20,8 +20,8 @@
add_datasets_url = "${h.url_for( controller='/visualization', action='list_current_history_datasets' )}",
default_data_url = "${h.url_for( controller='/tracks', action='data' )}",
raw_data_url = "${h.url_for( controller='/tracks', action='raw_data' )}",
- reference_url = "${h.url_for( controller='/tracks', action='reference' )}",
- chrom_url = "${h.url_for( controller='/tracks', action='chroms' )}",
+ reference_url = "${h.url_for( controller='/api/genomes' )}",
+ chrom_url = "${h.url_for( controller='/api/genomes' )}",
dataset_state_url = "${h.url_for( controller='/tracks', action='dataset_state' )}",
converted_datasets_state_url = "${h.url_for( controller='/tracks', action='converted_datasets_state' )}",
feature_search_url = "${h.url_for( controller='/tracks', action='search_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: jgoecks: Fixes for controller mixin hierarchy. Move track config response from tracks controller to API datasets controller.
by Bitbucket 14 Sep '12
by Bitbucket 14 Sep '12
14 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/81e32d70ee2d/
changeset: 81e32d70ee2d
user: jgoecks
date: 2012-09-14 23:03:11
summary: Fixes for controller mixin hierarchy. Move track config response from tracks controller to API datasets controller.
affected #: 9 files
diff -r 034a27f9c6c687803b337024c526d9b42c6a25b2 -r 81e32d70ee2daf03228752992b1765904f7e93fa lib/galaxy/web/api/datasets.py
--- a/lib/galaxy/web/api/datasets.py
+++ b/lib/galaxy/web/api/datasets.py
@@ -10,10 +10,13 @@
log = logging.getLogger( __name__ )
-class DatasetsController( BaseAPIController, UsesHistoryDatasetAssociationMixin ):
+def is_true ( a_str ):
+ return is_true == True or a_str in [ 'True', 'true', 'T', 't' ]
+
+class DatasetsController( BaseAPIController, UsesVisualizationMixin ):
@web.expose_api
- def index( self, trans, hda_id, **kwd ):
+ def index( self, trans, **kwd ):
"""
GET /api/datasets
Lists datasets.
@@ -21,24 +24,31 @@
pass
@web.expose_api
- def show( self, trans, id, deleted='False', **kwd ):
+ def show( self, trans, id, hda_ldda='hda', deleted='False', **kwd ):
"""
GET /api/datasets/{encoded_dataset_id}
Displays information about and/or content of a dataset.
"""
+
+ # Process arguments.
+ track_config = is_true( kwd.get( 'track_config', False ) )
- # Get HDA.
+ # Get dataset.
try:
- hda = self.get_dataset( trans, id, check_ownership=True, check_accessible=True )
+ dataset = self.get_hda_or_ldda( trans, hda_ldda=hda_ldda, dataset_id=id )
except Exception, e:
return str( e )
-
- # Return information about HDA.
+
+ # Return info.
rval = None
- try:
- rval = hda.get_api_value()
- except Exception, e:
- rval = "Error in dataset API at listing contents"
- log.error( rval + ": %s" % str(e) )
- trans.response.status = 500
+ if track_config:
+ rval = self.get_new_track_config( trans, dataset )
+ else:
+ # Default: return dataset as API value.
+ try:
+ rval = dataset.get_api_value()
+ except Exception, e:
+ rval = "Error in dataset API at listing contents"
+ log.error( rval + ": %s" % str(e) )
+ trans.response.status = 500
return rval
diff -r 034a27f9c6c687803b337024c526d9b42c6a25b2 -r 81e32d70ee2daf03228752992b1765904f7e93fa lib/galaxy/web/api/tools.py
--- a/lib/galaxy/web/api/tools.py
+++ b/lib/galaxy/web/api/tools.py
@@ -5,7 +5,7 @@
from galaxy.util.json import to_json_string, from_json_string
from galaxy.visualization.genome.data_providers import *
-class ToolsController( BaseAPIController, UsesHistoryDatasetAssociationMixin, UsesVisualizationMixin ):
+class ToolsController( BaseAPIController, UsesVisualizationMixin ):
"""
RESTful controller for interactions with tools.
"""
diff -r 034a27f9c6c687803b337024c526d9b42c6a25b2 -r 81e32d70ee2daf03228752992b1765904f7e93fa lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -357,7 +357,8 @@
def get_library_dataset( self, trans, id, check_ownership=False, check_accessible=True ):
return self.get_object( trans, id, 'LibraryDataset', check_ownership=False, check_accessible=check_accessible )
-class UsesVisualizationMixin( SharableItemSecurityMixin, UsesLibraryMixinItems ):
+class UsesVisualizationMixin( UsesHistoryDatasetAssociationMixin,
+ UsesLibraryMixinItems ):
""" Mixin for controllers that use Visualization objects. """
viz_types = [ "trackster", "circster" ]
diff -r 034a27f9c6c687803b337024c526d9b42c6a25b2 -r 81e32d70ee2daf03228752992b1765904f7e93fa lib/galaxy/web/controllers/page.py
--- a/lib/galaxy/web/controllers/page.py
+++ b/lib/galaxy/web/controllers/page.py
@@ -273,7 +273,7 @@
_BaseHTMLProcessor.unknown_endtag( self, tag )
class PageController( BaseUIController, SharableMixin, UsesAnnotations, UsesHistoryMixin,
- UsesStoredWorkflowMixin, UsesHistoryDatasetAssociationMixin, UsesVisualizationMixin, UsesItemRatings ):
+ UsesStoredWorkflowMixin, UsesVisualizationMixin, UsesItemRatings ):
_page_list = PageListGrid()
_all_published_list = PageAllPublishedGrid()
diff -r 034a27f9c6c687803b337024c526d9b42c6a25b2 -r 81e32d70ee2daf03228752992b1765904f7e93fa lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py
+++ b/lib/galaxy/web/controllers/tracks.py
@@ -36,19 +36,6 @@
return trans.fill_template( "tracks/new_browser.mako", dbkeys=trans.app.genomes.get_dbkeys_with_chrom_info( trans ), default_dbkey=kwargs.get("default_dbkey", None) )
@web.json
- def add_track_async(self, trans, hda_id=None, ldda_id=None):
- # Get dataset.
- if hda_id:
- hda_ldda = "hda"
- dataset_id = hda_id
- elif ldda_id:
- hda_ldda = "ldda"
- dataset_id = ldda_id
- dataset = self.get_hda_or_ldda( trans, hda_ldda, dataset_id )
-
- return self.get_new_track_config( trans, dataset )
-
- @web.json
def bookmarks_from_dataset( self, trans, hda_id=None, ldda_id=None ):
if hda_id:
hda_ldda = "hda"
diff -r 034a27f9c6c687803b337024c526d9b42c6a25b2 -r 81e32d70ee2daf03228752992b1765904f7e93fa lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py
+++ b/lib/galaxy/web/controllers/visualization.py
@@ -224,7 +224,7 @@
class VisualizationController( BaseUIController, SharableMixin, UsesAnnotations,
- UsesHistoryDatasetAssociationMixin, UsesVisualizationMixin,
+ UsesVisualizationMixin,
UsesItemRatings ):
_user_list_grid = VisualizationListGrid()
_published_list_grid = VisualizationAllPublishedGrid()
diff -r 034a27f9c6c687803b337024c526d9b42c6a25b2 -r 81e32d70ee2daf03228752992b1765904f7e93fa static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -742,15 +742,16 @@
"Add": function() {
var requests = [];
$('input[name=id]:checked,input[name=ldda_ids]:checked').each(function() {
- var data,
+ var data = {
+ 'track_config': true,
+ 'hda_ldda': 'hda'
+ },
id = $(this).val();
- if ($(this).attr("name") === "id") {
- data = { hda_id: id };
- } else {
- data = { ldda_id: id};
+ if ($(this).attr("name") !== "id") {
+ data['hda_ldda'] = 'ldda';
}
requests[requests.length] = $.ajax({
- url: add_track_async_url,
+ url: add_track_async_url + "/" + id,
data: data,
dataType: "json"
});
diff -r 034a27f9c6c687803b337024c526d9b42c6a25b2 -r 81e32d70ee2daf03228752992b1765904f7e93fa templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -233,8 +233,8 @@
%if add_dataset is not None:
$.ajax({
- url: "${h.url_for( action='add_track_async' )}",
- data: { hda_id: "${add_dataset}" },
+ url: add_track_async_url + "/${add_dataset}",
+ data: { hda_ldda: 'hda', 'track_config': true },
dataType: "json",
success: function(track_data) { view.add_drawable( object_from_template(track_data, view, view) ) }
});
diff -r 034a27f9c6c687803b337024c526d9b42c6a25b2 -r 81e32d70ee2daf03228752992b1765904f7e93fa templates/visualization/trackster_common.mako
--- a/templates/visualization/trackster_common.mako
+++ b/templates/visualization/trackster_common.mako
@@ -16,7 +16,7 @@
## Render a block of JavaScript that contains all necessary variables for Trackster.
<%def name="render_trackster_js_vars()">
- var add_track_async_url = "${h.url_for( controller='/tracks', action='add_track_async' )}",
+ var add_track_async_url = "${h.url_for( controller='/api/datasets' )}",
add_datasets_url = "${h.url_for( controller='/visualization', action='list_current_history_datasets' )}",
default_data_url = "${h.url_for( controller='/tracks', action='data' )}",
raw_data_url = "${h.url_for( controller='/tracks', action='raw_data' )}",
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: Fix for fastq filter tests of paired_end boolean.
by Bitbucket 14 Sep '12
by Bitbucket 14 Sep '12
14 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/034a27f9c6c6/
changeset: 034a27f9c6c6
user: dan
date: 2012-09-14 21:50:38
summary: Fix for fastq filter tests of paired_end boolean.
affected #: 1 file
diff -r be38ea1ed21376549a244cf29bb6d1b0bd73059f -r 034a27f9c6c687803b337024c526d9b42c6a25b2 tools/fastq/fastq_filter.xml
--- a/tools/fastq/fastq_filter.xml
+++ b/tools/fastq/fastq_filter.xml
@@ -111,7 +111,7 @@
<param name="min_quality" value="0"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="0"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_absolute"/><param name="left_column_offset" value="0"/><param name="right_column_offset" value="0"/>
@@ -127,7 +127,7 @@
<param name="min_quality" value="-5"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="0"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_absolute"/><param name="left_column_offset" value="0"/><param name="right_column_offset" value="0"/>
@@ -144,7 +144,7 @@
<param name="min_quality" value="0"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="0"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_absolute"/><param name="left_column_offset" value="0"/><param name="right_column_offset" value="0"/>
@@ -161,7 +161,7 @@
<param name="min_quality" value="1"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="0"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_absolute"/><param name="left_column_offset" value="0"/><param name="right_column_offset" value="0"/>
@@ -177,7 +177,7 @@
<param name="min_quality" value="-4"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="0"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_absolute"/><param name="left_column_offset" value="0"/><param name="right_column_offset" value="0"/>
@@ -194,7 +194,7 @@
<param name="min_quality" value="1"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="1"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_absolute"/><param name="left_column_offset" value="0"/><param name="right_column_offset" value="0"/>
@@ -210,7 +210,7 @@
<param name="min_quality" value="-5"/><param name="max_quality" value="61"/><param name="max_num_deviants" value="1"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_absolute"/><param name="left_column_offset" value="0"/><param name="right_column_offset" value="0"/>
@@ -227,7 +227,7 @@
<param name="min_quality" value="0"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="0"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_absolute"/><param name="left_column_offset" value="1"/><param name="right_column_offset" value="1"/>
@@ -243,7 +243,7 @@
<param name="min_quality" value="0"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="0"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_absolute"/><param name="left_column_offset" value="1"/><param name="right_column_offset" value="1"/>
@@ -260,7 +260,7 @@
<param name="min_quality" value="0"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="0"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="False"/><param name="base_offset_type" value="offsets_percent"/><param name="left_column_offset" value="1.075"/><param name="right_column_offset" value="1.075"/>
@@ -276,7 +276,7 @@
<param name="min_quality" value="0"/><param name="max_quality" value="0"/><param name="max_num_deviants" value="0"/>
- <param name="paired_end" value="single_end"/>
+ <param name="paired_end" value="True"/><param name="base_offset_type" value="offsets_percent"/><param name="left_column_offset" value="1"/><param name="right_column_offset" value="1"/>
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

14 Sep '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/be38ea1ed213/
changeset: be38ea1ed213
user: dan
date: 2012-09-14 20:50:27
summary: Fix for unit tests in galaxy.tools.deps
affected #: 1 file
diff -r f8ea04e7bbff4acbc14f95e14fd6f955c307f906 -r be38ea1ed21376549a244cf29bb6d1b0bd73059f lib/galaxy/tools/deps/__init__.py
--- a/lib/galaxy/tools/deps/__init__.py
+++ b/lib/galaxy/tools/deps/__init__.py
@@ -73,13 +73,14 @@
else:
return None, None, None
def _get_installed_dependency( self, installed_tool_dependencies, name, type, version=None ):
- for installed_tool_dependency in installed_tool_dependencies:
- if version:
- if installed_tool_dependency.name==name and installed_tool_dependency.type==type and installed_tool_dependency.version==version:
- return installed_tool_dependency
- else:
- if installed_tool_dependency.name==name and installed_tool_dependency.type==type:
- return installed_tool_dependency
+ if installed_tool_dependencies:
+ for installed_tool_dependency in installed_tool_dependencies:
+ if version:
+ if installed_tool_dependency.name==name and installed_tool_dependency.type==type and installed_tool_dependency.version==version:
+ return installed_tool_dependency
+ else:
+ if installed_tool_dependency.name==name and installed_tool_dependency.type==type:
+ return installed_tool_dependency
return None
def _get_package_installed_dependency_path( self, installed_tool_dependency, base_path, name, version ):
tool_shed_repository = installed_tool_dependency.tool_shed_repository
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/changeset/bc56358a5c51/
changeset: bc56358a5c51
user: jgoecks
date: 2012-09-14 20:40:53
summary: Visualization framework: (a) put summary tree back in tracks module because pickling requires it not move modules and (b) move grids from tracks controller to visualization controller.
affected #: 14 files
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/datatypes/converters/interval_to_interval_index_converter.py
--- a/lib/galaxy/datatypes/converters/interval_to_interval_index_converter.py
+++ b/lib/galaxy/datatypes/converters/interval_to_interval_index_converter.py
@@ -14,7 +14,7 @@
import sys, fileinput, optparse
from galaxy import eggs
import pkg_resources; pkg_resources.require( "bx-python" )
-from galaxy.visualization.genome.summary import *
+from galaxy.visualization.tracks.summary import *
from galaxy.datatypes.util.gff_util import convert_gff_coords_to_bed
from bx.interval_index_file import Indexes
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.py
--- a/lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.py
+++ b/lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.py
@@ -15,7 +15,7 @@
import sys, fileinput, optparse
from galaxy import eggs
import pkg_resources; pkg_resources.require( "bx-python" )
-from galaxy.visualization.genome.summary import *
+from galaxy.visualization.tracks.summary import *
from bx.intervals.io import *
from galaxy.datatypes.util.gff_util import *
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/datatypes/converters/sam_or_bam_to_summary_tree_converter.py
--- a/lib/galaxy/datatypes/converters/sam_or_bam_to_summary_tree_converter.py
+++ b/lib/galaxy/datatypes/converters/sam_or_bam_to_summary_tree_converter.py
@@ -14,7 +14,7 @@
pkg_resources.require( "pysam" )
from pysam import csamtools
-from galaxy.visualization.genome.summary import *
+from galaxy.visualization.tracks.summary import *
def main():
parser = optparse.OptionParser()
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.py
--- a/lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.py
+++ b/lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.py
@@ -9,7 +9,7 @@
import optparse
import galaxy_utils.sequence.vcf
-from galaxy.visualization.genome.summary import SummaryTree
+from galaxy.visualization.tracks.summary import SummaryTree
def main():
# Read options, args.
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/visualization/genome/data_providers.py
--- a/lib/galaxy/visualization/genome/data_providers.py
+++ b/lib/galaxy/visualization/genome/data_providers.py
@@ -16,7 +16,7 @@
from bx.interval_index_file import Indexes
from bx.bbi.bigwig_file import BigWigFile
from galaxy.util.lrucache import LRUCache
-from galaxy.visualization.genome.summary import *
+from galaxy.visualization.tracks.summary import *
from galaxy.visualization.data_providers import BaseDataProvider
import galaxy_utils.sequence.vcf
from galaxy.datatypes.tabular import Tabular, Vcf
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/visualization/genome/summary.py
--- a/lib/galaxy/visualization/genome/summary.py
+++ /dev/null
@@ -1,111 +0,0 @@
-'''
-Summary tree data structure for feature aggregation across large genomic regions.
-'''
-
-import sys, os
-import cPickle
-
-# TODO: What are the performance implications of setting min level to 1? Data
-# structure size and/or query speed? It would be nice to have level 1 data
-# so that client does not have to compute it.
-MIN_LEVEL = 2
-
-class SummaryTree:
- def __init__( self, block_size=25, levels=6, draw_cutoff=150, detail_cutoff=30 ):
- self.chrom_blocks = {}
- self.levels = levels
- self.draw_cutoff = draw_cutoff
- self.detail_cutoff = detail_cutoff
- self.block_size = block_size
- self.chrom_stats = {}
-
- def find_block( self, num, level ):
- """ Returns block that num is in for level. """
- return ( num / self.block_size ** level )
-
- def insert_range( self, chrom, start, end ):
- """ Inserts a feature at chrom:start-end into the tree. """
-
- # Get or set up chrom blocks.
- if chrom in self.chrom_blocks:
- blocks = self.chrom_blocks[ chrom ]
- else:
- blocks = self.chrom_blocks[ chrom ] = {}
- self.chrom_stats[ chrom ] = {}
- for level in range( MIN_LEVEL, self.levels + 1 ):
- blocks[ level ] = {}
-
- # Insert feature into all matching blocks at all levels.
- for level in range( MIN_LEVEL, self.levels + 1 ):
- block_level = blocks[ level ]
- starting_block = self.find_block( start, level )
- ending_block = self.find_block( end, level )
- for block in range( starting_block, ending_block + 1 ):
- if block in block_level:
- block_level[ block ] += 1
- else:
- block_level[ block ] = 1
-
- def finish( self ):
- """ Compute stats for levels. """
-
- for chrom, blocks in self.chrom_blocks.iteritems():
- for level in range( self.levels, MIN_LEVEL - 1, -1 ):
- # Set level's stats.
- max_val = max( blocks[ level ].values() )
- self.chrom_stats[ chrom ][ level ] = {}
- self.chrom_stats[ chrom ][ level ][ "delta" ] = self.block_size ** level
- self.chrom_stats[ chrom ][ level ][ "max" ] = max_val
- self.chrom_stats[ chrom ][ level ][ "avg" ] = float( max_val ) / len( blocks[ level ] )
-
- self.chrom_blocks[ chrom ] = dict( [ ( key, value ) for key, value in blocks.iteritems() ] )
-
- def query( self, chrom, start, end, level, draw_cutoff=None, detail_cutoff=None ):
- """ Queries tree for data. """
-
- # Set cutoffs to self's attributes if not defined.
- if draw_cutoff != 0:
- draw_cutoff = self.draw_cutoff
- if detail_cutoff != 0:
- detail_cutoff = self.detail_cutoff
-
- # Get data.
- if chrom in self.chrom_blocks:
- stats = self.chrom_stats[ chrom ]
-
- # For backwards compatibility:
- if "detail_level" in stats and level <= stats[ "detail_level" ]:
- return "detail"
- elif "draw_level" in stats and level <= stats[ "draw_level" ]:
- return "draw"
-
- # If below draw, detail level, return string to denote this.
- max = stats[ level ][ "max" ]
- if max < detail_cutoff:
- return "detail"
- if max < draw_cutoff:
- return "draw"
-
- # Return block data.
- blocks = self.chrom_blocks[ chrom ]
- results = []
- multiplier = self.block_size ** level
- starting_block = self.find_block( start, level )
- ending_block = self.find_block( end, level )
- for block in range( starting_block, ending_block + 1 ):
- val = 0
- if block in blocks[ level ]:
- val = blocks[ level ][ block ]
- results.append( ( block * multiplier, val ) )
- return results
-
- return None
-
- def write( self, filename ):
- """ Writes tree to file. """
- self.finish()
- cPickle.dump( self, open( filename, 'wb' ), 2 )
-
-def summary_tree_from_file( filename ):
- return cPickle.load( open( filename, "rb" ) )
-
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/visualization/tracks/__init__.py
--- /dev/null
+++ b/lib/galaxy/visualization/tracks/__init__.py
@@ -0,0 +1,1 @@
+""" Summary.py required to be in this module due to pickling. """
\ No newline at end of file
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/visualization/tracks/summary.py
--- /dev/null
+++ b/lib/galaxy/visualization/tracks/summary.py
@@ -0,0 +1,111 @@
+'''
+Summary tree data structure for feature aggregation across large genomic regions.
+'''
+
+import sys, os
+import cPickle
+
+# TODO: What are the performance implications of setting min level to 1? Data
+# structure size and/or query speed? It would be nice to have level 1 data
+# so that client does not have to compute it.
+MIN_LEVEL = 2
+
+class SummaryTree:
+ def __init__( self, block_size=25, levels=6, draw_cutoff=150, detail_cutoff=30 ):
+ self.chrom_blocks = {}
+ self.levels = levels
+ self.draw_cutoff = draw_cutoff
+ self.detail_cutoff = detail_cutoff
+ self.block_size = block_size
+ self.chrom_stats = {}
+
+ def find_block( self, num, level ):
+ """ Returns block that num is in for level. """
+ return ( num / self.block_size ** level )
+
+ def insert_range( self, chrom, start, end ):
+ """ Inserts a feature at chrom:start-end into the tree. """
+
+ # Get or set up chrom blocks.
+ if chrom in self.chrom_blocks:
+ blocks = self.chrom_blocks[ chrom ]
+ else:
+ blocks = self.chrom_blocks[ chrom ] = {}
+ self.chrom_stats[ chrom ] = {}
+ for level in range( MIN_LEVEL, self.levels + 1 ):
+ blocks[ level ] = {}
+
+ # Insert feature into all matching blocks at all levels.
+ for level in range( MIN_LEVEL, self.levels + 1 ):
+ block_level = blocks[ level ]
+ starting_block = self.find_block( start, level )
+ ending_block = self.find_block( end, level )
+ for block in range( starting_block, ending_block + 1 ):
+ if block in block_level:
+ block_level[ block ] += 1
+ else:
+ block_level[ block ] = 1
+
+ def finish( self ):
+ """ Compute stats for levels. """
+
+ for chrom, blocks in self.chrom_blocks.iteritems():
+ for level in range( self.levels, MIN_LEVEL - 1, -1 ):
+ # Set level's stats.
+ max_val = max( blocks[ level ].values() )
+ self.chrom_stats[ chrom ][ level ] = {}
+ self.chrom_stats[ chrom ][ level ][ "delta" ] = self.block_size ** level
+ self.chrom_stats[ chrom ][ level ][ "max" ] = max_val
+ self.chrom_stats[ chrom ][ level ][ "avg" ] = float( max_val ) / len( blocks[ level ] )
+
+ self.chrom_blocks[ chrom ] = dict( [ ( key, value ) for key, value in blocks.iteritems() ] )
+
+ def query( self, chrom, start, end, level, draw_cutoff=None, detail_cutoff=None ):
+ """ Queries tree for data. """
+
+ # Set cutoffs to self's attributes if not defined.
+ if draw_cutoff != 0:
+ draw_cutoff = self.draw_cutoff
+ if detail_cutoff != 0:
+ detail_cutoff = self.detail_cutoff
+
+ # Get data.
+ if chrom in self.chrom_blocks:
+ stats = self.chrom_stats[ chrom ]
+
+ # For backwards compatibility:
+ if "detail_level" in stats and level <= stats[ "detail_level" ]:
+ return "detail"
+ elif "draw_level" in stats and level <= stats[ "draw_level" ]:
+ return "draw"
+
+ # If below draw, detail level, return string to denote this.
+ max = stats[ level ][ "max" ]
+ if max < detail_cutoff:
+ return "detail"
+ if max < draw_cutoff:
+ return "draw"
+
+ # Return block data.
+ blocks = self.chrom_blocks[ chrom ]
+ results = []
+ multiplier = self.block_size ** level
+ starting_block = self.find_block( start, level )
+ ending_block = self.find_block( end, level )
+ for block in range( starting_block, ending_block + 1 ):
+ val = 0
+ if block in blocks[ level ]:
+ val = blocks[ level ][ block ]
+ results.append( ( block * multiplier, val ) )
+ return results
+
+ return None
+
+ def write( self, filename ):
+ """ Writes tree to file. """
+ self.finish()
+ cPickle.dump( self, open( filename, 'wb' ), 2 )
+
+def summary_tree_from_file( filename ):
+ return cPickle.load( open( filename, "rb" ) )
+
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py
+++ b/lib/galaxy/web/controllers/tracks.py
@@ -8,7 +8,6 @@
from galaxy import model
from galaxy.util.json import to_json_string, from_json_string
from galaxy.web.base.controller import *
-from galaxy.web.controllers.library import LibraryListGrid
from galaxy.web.framework import simplejson
from galaxy.web.framework.helpers import time_ago, grids
from galaxy.util.bunch import Bunch
@@ -16,152 +15,13 @@
from galaxy.model import NoConverterException, ConverterDependencyException
from galaxy.visualization.genome.data_providers import *
from galaxy.visualization.genomes import decode_dbkey, Genomes
-from galaxy.visualization.genome.visual_analytics import get_dataset_job
-
-
-class NameColumn( grids.TextColumn ):
- def get_value( self, trans, grid, history ):
- return history.get_display_name()
- def get_link( self, trans, grid, history ):
- # Provide link to list all datasets in history that have a given dbkey.
- # Right now, only dbkey needs to be passed through, but pass through
- # all for now since it's cleaner.
- d = dict( action=grid.datasets_action, show_item_checkboxes=True )
- d[ grid.datasets_param ] = trans.security.encode_id( history.id )
- for filter, value in grid.cur_filter_dict.iteritems():
- d[ "f-" + filter ] = value
- return d
-
-class DbKeyPlaceholderColumn( grids.GridColumn ):
- """ Placeholder to keep track of dbkey. """
- def filter( self, trans, user, query, dbkey ):
- return query
-
-class HistorySelectionGrid( grids.Grid ):
- """
- Grid enables user to select a history, which is then used to display
- datasets from the history.
- """
- title = "Add Track: Select History"
- model_class = model.History
- template='/tracks/history_select_grid.mako'
- default_sort_key = "-update_time"
- datasets_action = 'list_history_datasets'
- datasets_param = "f-history"
- columns = [
- NameColumn( "History Name", key="name", filterable="standard" ),
- grids.GridColumn( "Last Updated", key="update_time", format=time_ago, visible=False ),
- DbKeyPlaceholderColumn( "Dbkey", key="dbkey", model_class=model.HistoryDatasetAssociation, visible=False )
- ]
- num_rows_per_page = 10
- use_async = True
- use_paging = True
- def apply_query_filter( self, trans, query, **kwargs ):
- return query.filter_by( user=trans.user, purged=False, deleted=False, importing=False )
-
-class LibrarySelectionGrid( LibraryListGrid ):
- """
- Grid enables user to select a Library, which is then used to display
- datasets from the history.
- """
- title = "Add Track: Select Library"
- template='/tracks/history_select_grid.mako'
- model_class = model.Library
- datasets_action = 'list_library_datasets'
- datasets_param = "f-library"
- columns = [
- NameColumn( "Library Name", key="name", filterable="standard" )
- ]
- num_rows_per_page = 10
- use_async = True
- use_paging = True
-
-class DbKeyColumn( grids.GridColumn ):
- """ Column for filtering by and displaying dataset dbkey. """
- def filter( self, trans, user, query, dbkey ):
- """ Filter by dbkey; datasets without a dbkey are returned as well. """
- # use raw SQL b/c metadata is a BLOB
- dbkey_user, dbkey = decode_dbkey( dbkey )
- dbkey = dbkey.replace("'", "\\'")
- return query.filter( or_( \
- or_( "metadata like '%%\"dbkey\": [\"%s\"]%%'" % dbkey, "metadata like '%%\"dbkey\": \"%s\"%%'" % dbkey ), \
- or_( "metadata like '%%\"dbkey\": [\"?\"]%%'", "metadata like '%%\"dbkey\": \"?\"%%'" ) \
- )
- )
-
-class HistoryColumn( grids.GridColumn ):
- """ Column for filtering by history id. """
- def filter( self, trans, user, query, history_id ):
- return query.filter( model.History.id==trans.security.decode_id(history_id) )
-
-class HistoryDatasetsSelectionGrid( grids.Grid ):
- # Grid definition.
- available_tracks = None
- title = "Add Datasets"
- template = "tracks/history_datasets_select_grid.mako"
- model_class = model.HistoryDatasetAssociation
- default_filter = { "deleted" : "False" , "shared" : "All" }
- default_sort_key = "-hid"
- use_async = True
- use_paging = False
- columns = [
- grids.GridColumn( "Id", key="hid" ),
- grids.TextColumn( "Name", key="name", model_class=model.HistoryDatasetAssociation ),
- grids.TextColumn( "Filetype", key="extension", model_class=model.HistoryDatasetAssociation ),
- HistoryColumn( "History", key="history", visible=False ),
- DbKeyColumn( "Dbkey", key="dbkey", model_class=model.HistoryDatasetAssociation, visible=True, sortable=False )
- ]
- columns.append(
- grids.MulticolFilterColumn( "Search name and filetype", cols_to_filter=[ columns[1], columns[2] ],
- key="free-text-search", visible=False, filterable="standard" )
- )
-
- def get_current_item( self, trans, **kwargs ):
- """
- Current item for grid is the history being queried. This is a bit
- of hack since current_item typically means the current item in the grid.
- """
- return model.History.get( trans.security.decode_id( kwargs[ 'f-history' ] ) )
- def build_initial_query( self, trans, **kwargs ):
- return trans.sa_session.query( self.model_class ).join( model.History.table ).join( model.Dataset.table )
- def apply_query_filter( self, trans, query, **kwargs ):
- if self.available_tracks is None:
- self.available_tracks = trans.app.datatypes_registry.get_available_tracks()
- return query.filter( model.HistoryDatasetAssociation.extension.in_(self.available_tracks) ) \
- .filter( model.Dataset.state == model.Dataset.states.OK ) \
- .filter( model.HistoryDatasetAssociation.deleted == False ) \
- .filter( model.HistoryDatasetAssociation.visible == True )
-
-class TracksterSelectionGrid( grids.Grid ):
- # Grid definition.
- title = "Insert into visualization"
- template = "/tracks/add_to_viz.mako"
- async_template = "/page/select_items_grid_async.mako"
- model_class = model.Visualization
- default_sort_key = "-update_time"
- use_async = True
- use_paging = False
- columns = [
- grids.TextColumn( "Title", key="title", model_class=model.Visualization, filterable="standard" ),
- grids.TextColumn( "Dbkey", key="dbkey", model_class=model.Visualization ),
- grids.GridColumn( "Last Updated", key="update_time", format=time_ago )
- ]
-
- def build_initial_query( self, trans, **kwargs ):
- return trans.sa_session.query( self.model_class ).filter( self.model_class.deleted == False )
- def apply_query_filter( self, trans, query, **kwargs ):
- return query.filter( self.model_class.user_id == trans.user.id )
+from galaxy.visualization.genome.visual_analytics import get_dataset_job
class TracksController( BaseUIController, UsesVisualizationMixin, UsesHistoryDatasetAssociationMixin, SharableMixin ):
"""
Controller for track browser interface. Handles building a new browser from
datasets in the current history, and display of the resulting browser.
"""
-
- libraries_grid = LibrarySelectionGrid()
- histories_grid = HistorySelectionGrid()
- history_datasets_grid = HistoryDatasetsSelectionGrid()
- tracks_grid = TracksterSelectionGrid()
@web.expose
@web.require_login()
@@ -441,70 +301,7 @@
result = data_provider.get_data( chrom, int( low ), int( high ), int( start_val ), int( max_vals ), **kwargs )
result.update( { 'dataset_type': tracks_dataset_type, 'extra_info': extra_info } )
return result
-
- @web.expose
- @web.require_login( "see all available libraries" )
- def list_libraries( self, trans, **kwargs ):
- """List all libraries that can be used for selecting datasets."""
-
- # Render the list view
- return self.libraries_grid( trans, **kwargs )
-
- @web.expose
- @web.require_login( "see a library's datasets that can added to this visualization" )
- def list_library_datasets( self, trans, **kwargs ):
- """List a library's datasets that can be added to a visualization."""
-
- library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( kwargs.get('f-library') ) )
- return trans.fill_template( '/tracks/library_datasets_select_grid.mako',
- cntrller="library",
- use_panels=False,
- library=library,
- created_ldda_ids='',
- hidden_folder_ids='',
- show_deleted=False,
- comptypes=[],
- current_user_roles=trans.get_current_user_roles(),
- message='',
- status="done" )
-
- @web.expose
- @web.require_login( "see all available histories" )
- def list_histories( self, trans, **kwargs ):
- """List all histories that can be used for selecting datasets."""
-
- # Render the list view
- return self.histories_grid( trans, **kwargs )
-
- @web.expose
- @web.require_login( "see current history's datasets that can added to this visualization" )
- def list_current_history_datasets( self, trans, **kwargs ):
- """ List a history's datasets that can be added to a visualization. """
-
- kwargs[ 'f-history' ] = trans.security.encode_id( trans.get_history().id )
- kwargs[ 'show_item_checkboxes' ] = 'True'
- return self.list_history_datasets( trans, **kwargs )
-
- @web.expose
- @web.require_login( "see a history's datasets that can added to this visualization" )
- def list_history_datasets( self, trans, **kwargs ):
- """List a history's datasets that can be added to a visualization."""
-
- # Render the list view
- return self.history_datasets_grid( trans, **kwargs )
-
- @web.expose
- @web.require_login( "see all available datasets" )
- def list_datasets( self, trans, **kwargs ):
- """List all datasets that can be added as tracks"""
-
- # Render the list view
- return self.data_grid( trans, **kwargs )
-
- @web.expose
- def list_tracks( self, trans, **kwargs ):
- return self.tracks_grid( trans, **kwargs )
-
+
@web.expose
def sweepster( self, trans, id=None, hda_ldda=None, dataset_id=None, regions=None ):
"""
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py
+++ b/lib/galaxy/web/controllers/visualization.py
@@ -3,6 +3,145 @@
from galaxy.web.base.controller import *
from galaxy.web.framework.helpers import time_ago, grids, iff
from galaxy.util.sanitize_html import sanitize_html
+from galaxy.web.controllers.library import LibraryListGrid
+from galaxy.visualization.genomes import decode_dbkey
+
+#
+# -- Grids --
+#
+
+class NameColumn( grids.TextColumn ):
+ def get_value( self, trans, grid, history ):
+ return history.get_display_name()
+ def get_link( self, trans, grid, history ):
+ # Provide link to list all datasets in history that have a given dbkey.
+ # Right now, only dbkey needs to be passed through, but pass through
+ # all for now since it's cleaner.
+ d = dict( action=grid.datasets_action, show_item_checkboxes=True )
+ d[ grid.datasets_param ] = trans.security.encode_id( history.id )
+ for filter, value in grid.cur_filter_dict.iteritems():
+ d[ "f-" + filter ] = value
+ return d
+
+class DbKeyPlaceholderColumn( grids.GridColumn ):
+ """ Placeholder to keep track of dbkey. """
+ def filter( self, trans, user, query, dbkey ):
+ return query
+
+class HistorySelectionGrid( grids.Grid ):
+ """
+ Grid enables user to select a history, which is then used to display
+ datasets from the history.
+ """
+ title = "Add Track: Select History"
+ model_class = model.History
+ template='/tracks/history_select_grid.mako'
+ default_sort_key = "-update_time"
+ datasets_action = 'list_history_datasets'
+ datasets_param = "f-history"
+ columns = [
+ NameColumn( "History Name", key="name", filterable="standard" ),
+ grids.GridColumn( "Last Updated", key="update_time", format=time_ago, visible=False ),
+ DbKeyPlaceholderColumn( "Dbkey", key="dbkey", model_class=model.HistoryDatasetAssociation, visible=False )
+ ]
+ num_rows_per_page = 10
+ use_async = True
+ use_paging = True
+ def apply_query_filter( self, trans, query, **kwargs ):
+ return query.filter_by( user=trans.user, purged=False, deleted=False, importing=False )
+
+class LibrarySelectionGrid( LibraryListGrid ):
+ """
+ Grid enables user to select a Library, which is then used to display
+ datasets from the history.
+ """
+ title = "Add Track: Select Library"
+ template='/tracks/history_select_grid.mako'
+ model_class = model.Library
+ datasets_action = 'list_library_datasets'
+ datasets_param = "f-library"
+ columns = [
+ NameColumn( "Library Name", key="name", filterable="standard" )
+ ]
+ num_rows_per_page = 10
+ use_async = True
+ use_paging = True
+
+class DbKeyColumn( grids.GridColumn ):
+ """ Column for filtering by and displaying dataset dbkey. """
+ def filter( self, trans, user, query, dbkey ):
+ """ Filter by dbkey; datasets without a dbkey are returned as well. """
+ # use raw SQL b/c metadata is a BLOB
+ dbkey_user, dbkey = decode_dbkey( dbkey )
+ dbkey = dbkey.replace("'", "\\'")
+ return query.filter( or_( \
+ or_( "metadata like '%%\"dbkey\": [\"%s\"]%%'" % dbkey, "metadata like '%%\"dbkey\": \"%s\"%%'" % dbkey ), \
+ or_( "metadata like '%%\"dbkey\": [\"?\"]%%'", "metadata like '%%\"dbkey\": \"?\"%%'" ) \
+ )
+ )
+
+class HistoryColumn( grids.GridColumn ):
+ """ Column for filtering by history id. """
+ def filter( self, trans, user, query, history_id ):
+ return query.filter( model.History.id==trans.security.decode_id(history_id) )
+
+class HistoryDatasetsSelectionGrid( grids.Grid ):
+ # Grid definition.
+ available_tracks = None
+ title = "Add Datasets"
+ template = "tracks/history_datasets_select_grid.mako"
+ model_class = model.HistoryDatasetAssociation
+ default_filter = { "deleted" : "False" , "shared" : "All" }
+ default_sort_key = "-hid"
+ use_async = True
+ use_paging = False
+ columns = [
+ grids.GridColumn( "Id", key="hid" ),
+ grids.TextColumn( "Name", key="name", model_class=model.HistoryDatasetAssociation ),
+ grids.TextColumn( "Filetype", key="extension", model_class=model.HistoryDatasetAssociation ),
+ HistoryColumn( "History", key="history", visible=False ),
+ DbKeyColumn( "Dbkey", key="dbkey", model_class=model.HistoryDatasetAssociation, visible=True, sortable=False )
+ ]
+ columns.append(
+ grids.MulticolFilterColumn( "Search name and filetype", cols_to_filter=[ columns[1], columns[2] ],
+ key="free-text-search", visible=False, filterable="standard" )
+ )
+
+ def get_current_item( self, trans, **kwargs ):
+ """
+ Current item for grid is the history being queried. This is a bit
+ of hack since current_item typically means the current item in the grid.
+ """
+ return model.History.get( trans.security.decode_id( kwargs[ 'f-history' ] ) )
+ def build_initial_query( self, trans, **kwargs ):
+ return trans.sa_session.query( self.model_class ).join( model.History.table ).join( model.Dataset.table )
+ def apply_query_filter( self, trans, query, **kwargs ):
+ if self.available_tracks is None:
+ self.available_tracks = trans.app.datatypes_registry.get_available_tracks()
+ return query.filter( model.HistoryDatasetAssociation.extension.in_(self.available_tracks) ) \
+ .filter( model.Dataset.state == model.Dataset.states.OK ) \
+ .filter( model.HistoryDatasetAssociation.deleted == False ) \
+ .filter( model.HistoryDatasetAssociation.visible == True )
+
+class TracksterSelectionGrid( grids.Grid ):
+ # Grid definition.
+ title = "Insert into visualization"
+ template = "/tracks/add_to_viz.mako"
+ async_template = "/page/select_items_grid_async.mako"
+ model_class = model.Visualization
+ default_sort_key = "-update_time"
+ use_async = True
+ use_paging = False
+ columns = [
+ grids.TextColumn( "Title", key="title", model_class=model.Visualization, filterable="standard" ),
+ grids.TextColumn( "Dbkey", key="dbkey", model_class=model.Visualization ),
+ grids.GridColumn( "Last Updated", key="update_time", format=time_ago )
+ ]
+
+ def build_initial_query( self, trans, **kwargs ):
+ return trans.sa_session.query( self.model_class ).filter( self.model_class.deleted == False )
+ def apply_query_filter( self, trans, query, **kwargs ):
+ return query.filter( self.model_class.user_id == trans.user.id )
class VisualizationListGrid( grids.Grid ):
def get_url_args( item ):
@@ -89,6 +228,10 @@
UsesItemRatings ):
_user_list_grid = VisualizationListGrid()
_published_list_grid = VisualizationAllPublishedGrid()
+ _libraries_grid = LibrarySelectionGrid()
+ _histories_grid = HistorySelectionGrid()
+ _history_datasets_grid = HistoryDatasetsSelectionGrid()
+ _tracks_grid = TracksterSelectionGrid()
@web.expose
def list_published( self, trans, *args, **kwargs ):
@@ -464,6 +607,69 @@
help="A description of the visualization; annotation is shown alongside published visualizations."),
template="visualization/create.mako" )
+ @web.expose
+ @web.require_login( "see all available libraries" )
+ def list_libraries( self, trans, **kwargs ):
+ """List all libraries that can be used for selecting datasets."""
+
+ # Render the list view
+ return self._libraries_grid( trans, **kwargs )
+
+ @web.expose
+ @web.require_login( "see a library's datasets that can added to this visualization" )
+ def list_library_datasets( self, trans, **kwargs ):
+ """List a library's datasets that can be added to a visualization."""
+
+ library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( kwargs.get('f-library') ) )
+ return trans.fill_template( '/tracks/library_datasets_select_grid.mako',
+ cntrller="library",
+ use_panels=False,
+ library=library,
+ created_ldda_ids='',
+ hidden_folder_ids='',
+ show_deleted=False,
+ comptypes=[],
+ current_user_roles=trans.get_current_user_roles(),
+ message='',
+ status="done" )
+
+ @web.expose
+ @web.require_login( "see all available histories" )
+ def list_histories( self, trans, **kwargs ):
+ """List all histories that can be used for selecting datasets."""
+
+ # Render the list view
+ return self._histories_grid( trans, **kwargs )
+
+ @web.expose
+ @web.require_login( "see current history's datasets that can added to this visualization" )
+ def list_current_history_datasets( self, trans, **kwargs ):
+ """ List a history's datasets that can be added to a visualization. """
+
+ kwargs[ 'f-history' ] = trans.security.encode_id( trans.get_history().id )
+ kwargs[ 'show_item_checkboxes' ] = 'True'
+ return self.list_history_datasets( trans, **kwargs )
+
+ @web.expose
+ @web.require_login( "see a history's datasets that can added to this visualization" )
+ def list_history_datasets( self, trans, **kwargs ):
+ """List a history's datasets that can be added to a visualization."""
+
+ # Render the list view
+ return self._history_datasets_grid( trans, **kwargs )
+
+ @web.expose
+ @web.require_login( "see all available datasets" )
+ def list_datasets( self, trans, **kwargs ):
+ """List all datasets that can be added as tracks"""
+
+ # Render the list view
+ return self._data_grid( trans, **kwargs )
+
+ @web.expose
+ def list_tracks( self, trans, **kwargs ):
+ return self._tracks_grid( trans, **kwargs )
+
def get_item( self, trans, id ):
return self.get_visualization( trans, id )
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 templates/root/alternate_history.mako
--- a/templates/root/alternate_history.mako
+++ b/templates/root/alternate_history.mako
@@ -131,10 +131,10 @@
# do these need _localized_ dbkeys?
trackster_urls = {}
if hda.dbkey != '?':
- data_url = h.url_for( controller='tracks', action='list_tracks', dbkey=hda.dbkey )
+ data_url = h.url_for( controller='visualization', action='list_tracks', dbkey=hda.dbkey )
data_url = hda.replace( 'dbkey', 'f-dbkey' )
else:
- data_url = h.url_for( controller='tracks', action='list_tracks' )
+ data_url = h.url_for( controller='visualization', action='list_tracks' )
trackster_urls[ 'hda-url' ] = data_url
trackster_urls[ 'action-url' ] = h.url_for( controller='tracks', action='browser', dataset_id=encoded_data_id )
trackster_urls[ 'new-url' ] = h.url_for( controller='tracks', action='index', dataset_id=encoded_data_id, default_dbkey=hda.dbkey )
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 templates/root/history_common.mako
--- a/templates/root/history_common.mako
+++ b/templates/root/history_common.mako
@@ -229,10 +229,10 @@
%if data.ext in app.datatypes_registry.get_available_tracks():
<%
if data.dbkey != '?':
- data_url = h.url_for( controller='tracks', action='list_tracks', dbkey=data.dbkey )
+ data_url = h.url_for( controller='visualization', action='list_tracks', dbkey=data.dbkey )
data_url = data_url.replace( 'dbkey', 'f-dbkey' )
else:
- data_url = h.url_for( controller='tracks', action='list_tracks' )
+ data_url = h.url_for( controller='visualization', action='list_tracks' )
%><a href="javascript:void(0)" data-url="${data_url}" class="icon-button chart_curve tooltip trackster-add"
action-url="${h.url_for( controller='tracks', action='browser', dataset_id=dataset_id)}"
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -51,7 +51,7 @@
var add_bookmarks = function() {
show_modal( "Select dataset for new bookmarks", "progress" );
$.ajax({
- url: "${h.url_for( action='list_histories' )}",
+ url: "${h.url_for( controller='visualization', action='list_histories' )}",
data: { "f-dbkey": view.dbkey },
error: function() { alert( "Grid failed" ); },
success: function(table_html) {
diff -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 -r bc56358a5c51512f98c09a88c31a7b445e8160e0 templates/visualization/trackster_common.mako
--- a/templates/visualization/trackster_common.mako
+++ b/templates/visualization/trackster_common.mako
@@ -17,7 +17,7 @@
## Render a block of JavaScript that contains all necessary variables for Trackster.
<%def name="render_trackster_js_vars()">
var add_track_async_url = "${h.url_for( controller='/tracks', action='add_track_async' )}",
- add_datasets_url = "${h.url_for( controller='/tracks', action='list_current_history_datasets' )}",
+ add_datasets_url = "${h.url_for( controller='/visualization', action='list_current_history_datasets' )}",
default_data_url = "${h.url_for( controller='/tracks', action='data' )}",
raw_data_url = "${h.url_for( controller='/tracks', action='raw_data' )}",
reference_url = "${h.url_for( controller='/tracks', action='reference' )}",
https://bitbucket.org/galaxy/galaxy-central/changeset/f8ea04e7bbff/
changeset: f8ea04e7bbff
user: jgoecks
date: 2012-09-14 20:42:11
summary: Summary tree documentation update.
affected #: 1 file
diff -r bc56358a5c51512f98c09a88c31a7b445e8160e0 -r f8ea04e7bbff4acbc14f95e14fd6f955c307f906 lib/galaxy/visualization/tracks/summary.py
--- a/lib/galaxy/visualization/tracks/summary.py
+++ b/lib/galaxy/visualization/tracks/summary.py
@@ -1,5 +1,5 @@
'''
-Summary tree data structure for feature aggregation across large genomic regions.
+This module cannot be moved due to the use of pickling.
'''
import sys, os
@@ -11,6 +11,9 @@
MIN_LEVEL = 2
class SummaryTree:
+ '''
+ Summary tree data structure for feature aggregation across large genomic regions.
+ '''
def __init__( self, block_size=25, levels=6, draw_cutoff=150, detail_cutoff=30 ):
self.chrom_blocks = {}
self.levels = levels
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
4 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/6eae334427ce/
changeset: 6eae334427ce
user: jgoecks
date: 2012-09-14 17:11:04
summary: Add column data provider.
affected #: 1 file
diff -r a5f93d5b509835c9e4a29ba793c6406cb3a63ca2 -r 6eae334427ce58f209a53eb7833c5b442f797040 lib/galaxy/visualization/tracks/data_providers.py
--- a/lib/galaxy/visualization/tracks/data_providers.py
+++ b/lib/galaxy/visualization/tracks/data_providers.py
@@ -18,24 +18,30 @@
from galaxy.util.lrucache import LRUCache
from galaxy.visualization.tracks.summary import *
import galaxy_utils.sequence.vcf
-from galaxy.datatypes.tabular import Vcf
+from galaxy.datatypes.tabular import Tabular, Vcf
from galaxy.datatypes.interval import Interval, Bed, Gff, Gtf, ENCODEPeak, ChromatinInteractions
from pysam import csamtools, ctabix
ERROR_MAX_VALS = "Only the first %i %s in this region are displayed."
-# Return None instead of NaN to pass jQuery 1.4's strict JSON
+#
+# Utility functions.
+#
+
def float_nan(n):
+ '''
+ Return None instead of NaN to pass jQuery 1.4's strict JSON
+ '''
if n != n: # NaN != NaN
return None
else:
return float(n)
def get_bounds( reads, start_pos_index, end_pos_index ):
- """
+ '''
Returns the minimum and maximum position for a set of reads.
- """
+ '''
max_low = sys.maxint
max_high = -sys.maxint
for read in reads:
@@ -60,6 +66,50 @@
def _chrom_naming_matches( chrom1, chrom2 ):
return ( chrom1.startswith( 'chr' ) and chrom2.startswith( 'chr' ) ) or ( not chrom1.startswith( 'chr' ) and not chrom2.startswith( 'chr' ) )
+
+class ColumnDataProvider( object ):
+ """ Data provider for columnar data """
+
+ def __init__( self, original_dataset ):
+ # Compatibility check.
+ if not isinstance( original_dataset.datatype, Tabular ):
+ raise Exception( "Data provider can only be used with tabular data" )
+
+ # Attribute init.
+ self.original_dataset = original_dataset
+
+ def get_data( self, cols, start_val=0, max_vals=sys.maxint ):
+ """
+ Returns data from specified columns in dataset. Format is list of lists
+ where each list is a line of data.
+ """
+
+ def cast_val( val, type ):
+ """ Cast value based on type. """
+ if type == 'int':
+ try: val = int( val )
+ except: pass
+ elif type == 'float':
+ try: val = float( val )
+ except: pass
+ return val
+
+ data = []
+ f = open( self.original_dataset.file_name )
+ for count, line in enumerate( f ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = ERROR_MAX_VALS % ( max_vals, "features" )
+ break
+
+ fields = line.split()
+ data.append( [ cast_val( fields[c], self.original_dataset.metadata.column_types[c] ) for c in cols ] )
+
+ f.close()
+
+ return data
+
class FeatureLocationIndexDataProvider( object ):
'''
https://bitbucket.org/galaxy/galaxy-central/changeset/586506caaad4/
changeset: 586506caaad4
user: jgoecks
date: 2012-09-14 18:14:15
summary: Codify data providers framework by adding and using a base provider.
affected #: 2 files
diff -r 6eae334427ce58f209a53eb7833c5b442f797040 -r 586506caaad452c533493e5db8f26a362fb61280 lib/galaxy/visualization/data_providers.py
--- /dev/null
+++ b/lib/galaxy/visualization/data_providers.py
@@ -0,0 +1,93 @@
+import sys
+
+class BaseDataProvider( object ):
+ """
+ Base class for data providers. Data providers (a) read and package data from datasets;
+ and (b) write subsets of data to new datasets.
+ """
+
+ def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None,
+ error_max_vals="Only the first %i values are returned." ):
+ """ Create basic data provider. """
+ self.converted_dataset = converted_dataset
+ self.original_dataset = original_dataset
+ self.dependencies = dependencies
+ self.error_max_vals = error_max_vals
+
+ def has_data( self, **kwargs ):
+ """
+ Returns true if dataset has data in the specified genome window, false
+ otherwise.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def get_iterator( self, **kwargs ):
+ """
+ Returns an iterator that provides data in the region chrom:start-end
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Process data from an iterator to a format that can be provided to client.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def get_data( self, start_val=0, max_vals=sys.maxint, **kwargs ):
+ """
+ Returns data as specified by kwargs. start_val is the first element to
+ return and max_vals indicates the number of values to return.
+
+ Return value must be a dictionary with the following attributes:
+ dataset_type, data
+ """
+ iterator = self.get_iterator( chrom, start, end )
+ return self.process_data( iterator, start_val, max_vals, **kwargs )
+ def write_data_to_file( self, filename, **kwargs ):
+ """
+ Write data in region defined by chrom, start, and end to a file.
+ """
+ raise Exception( "Unimplemented Function" )
+
+class ColumnDataProvider( BaseDataProvider ):
+ """ Data provider for columnar data """
+
+ def __init__( self, original_dataset ):
+ # Compatibility check.
+ if not isinstance( original_dataset.datatype, Tabular ):
+ raise Exception( "Data provider can only be used with tabular data" )
+
+ # Attribute init.
+ self.original_dataset = original_dataset
+
+ def get_data( self, cols, start_val=0, max_vals=sys.maxint ):
+ """
+ Returns data from specified columns in dataset. Format is list of lists
+ where each list is a line of data.
+ """
+
+ def cast_val( val, type ):
+ """ Cast value based on type. """
+ if type == 'int':
+ try: val = int( val )
+ except: pass
+ elif type == 'float':
+ try: val = float( val )
+ except: pass
+ return val
+
+ data = []
+ f = open( self.original_dataset.file_name )
+ for count, line in enumerate( f ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+
+ fields = line.split()
+ data.append( [ cast_val( fields[c], self.original_dataset.metadata.column_types[c] ) for c in cols ] )
+
+ f.close()
+
+ return data
diff -r 6eae334427ce58f209a53eb7833c5b442f797040 -r 586506caaad452c533493e5db8f26a362fb61280 lib/galaxy/visualization/tracks/data_providers.py
--- a/lib/galaxy/visualization/tracks/data_providers.py
+++ b/lib/galaxy/visualization/tracks/data_providers.py
@@ -1,5 +1,5 @@
"""
-Data providers for tracks visualizations.
+Data providers for genome visualizations.
"""
import os, sys
@@ -17,14 +17,13 @@
from bx.bbi.bigwig_file import BigWigFile
from galaxy.util.lrucache import LRUCache
from galaxy.visualization.tracks.summary import *
+from galaxy.visualization.data_providers import BaseDataProvider
import galaxy_utils.sequence.vcf
from galaxy.datatypes.tabular import Tabular, Vcf
from galaxy.datatypes.interval import Interval, Bed, Gff, Gtf, ENCODEPeak, ChromatinInteractions
from pysam import csamtools, ctabix
-ERROR_MAX_VALS = "Only the first %i %s in this region are displayed."
-
#
# Utility functions.
#
@@ -66,54 +65,10 @@
def _chrom_naming_matches( chrom1, chrom2 ):
return ( chrom1.startswith( 'chr' ) and chrom2.startswith( 'chr' ) ) or ( not chrom1.startswith( 'chr' ) and not chrom2.startswith( 'chr' ) )
-
-class ColumnDataProvider( object ):
- """ Data provider for columnar data """
-
- def __init__( self, original_dataset ):
- # Compatibility check.
- if not isinstance( original_dataset.datatype, Tabular ):
- raise Exception( "Data provider can only be used with tabular data" )
-
- # Attribute init.
- self.original_dataset = original_dataset
-
- def get_data( self, cols, start_val=0, max_vals=sys.maxint ):
- """
- Returns data from specified columns in dataset. Format is list of lists
- where each list is a line of data.
- """
-
- def cast_val( val, type ):
- """ Cast value based on type. """
- if type == 'int':
- try: val = int( val )
- except: pass
- elif type == 'float':
- try: val = float( val )
- except: pass
- return val
-
- data = []
- f = open( self.original_dataset.file_name )
- for count, line in enumerate( f ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "features" )
- break
-
- fields = line.split()
- data.append( [ cast_val( fields[c], self.original_dataset.metadata.column_types[c] ) for c in cols ] )
-
- f.close()
-
- return data
-
-class FeatureLocationIndexDataProvider( object ):
- '''
-
- '''
+class FeatureLocationIndexDataProvider( BaseDataProvider ):
+ """
+ Reads/writes/queries feature location index (FLI) datasets.
+ """
def __init__( self, converted_dataset ):
self.converted_dataset = converted_dataset
@@ -155,7 +110,7 @@
textloc_file.close()
return result
-class TracksDataProvider( object ):
+class TracksDataProvider( BaseDataProvider ):
""" Base class for tracks data providers. """
"""
@@ -167,11 +122,12 @@
"""
col_name_data_attr_mapping = {}
- def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None ):
- """ Create basic data provider. """
- self.converted_dataset = converted_dataset
- self.original_dataset = original_dataset
- self.dependencies = dependencies
+ def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None,
+ error_max_vals="Only the first %i %s in this region are displayed." ):
+ super( TracksDataProvider, self ).__init__( converted_dataset=converted_dataset,
+ original_dataset=original_dataset,
+ dependencies=dependencies,
+ error_max_vals=error_max_vals )
def write_data_to_file( self, regions, filename ):
"""
@@ -429,7 +385,7 @@
if count < start_val:
continue
if max_vals and count-start_val >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "features" )
+ message = self.error_max_vals % ( max_vals, "features" )
break
feature = line.split()
@@ -502,7 +458,7 @@
if count < start_val:
continue
if max_vals and count-start_val >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "features" )
+ message = self.error_max_vals % ( max_vals, "features" )
break
# TODO: can we use column metadata to fill out payload?
# TODO: use function to set payload data
@@ -656,7 +612,7 @@
if count < start_val:
continue
if max_vals and count-start_val >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "features" )
+ message = self.error_max_vals % ( max_vals, "features" )
break
feature = line.split()
@@ -927,7 +883,7 @@
if count < start_val:
continue
if ( count - start_val - unmapped ) >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "reads" )
+ message = self.error_max_vals % ( max_vals, "reads" )
break
# If not mapped, skip read.
@@ -1198,7 +1154,7 @@
if count < start_val:
continue
if count-start_val >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "features" )
+ message = self.error_max_vals % ( max_vals, "features" )
break
source.seek( offset )
# TODO: can we use column metadata to fill out payload?
@@ -1260,7 +1216,7 @@
if count < start_val:
continue
if count-start_val >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "reads" )
+ message = self.error_max_vals % ( max_vals, "reads" )
break
payload = package_gff_feature( feature, no_detail=no_detail, filter_cols=filter_cols )
@@ -1302,7 +1258,7 @@
if count < start_val:
continue
if count-start_val >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "reads" )
+ message = self.error_max_vals % ( max_vals, "reads" )
break
feature = GFFFeature( None, intervals=intervals )
@@ -1348,7 +1304,7 @@
if count < start_val:
continue
if max_vals and count-start_val >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "features" )
+ message = self.error_max_vals % ( max_vals, "features" )
break
feature = line.split()
@@ -1440,7 +1396,7 @@
if count < start_val:
continue
if max_vals and count-start_val >= max_vals:
- message = ERROR_MAX_VALS % ( max_vals, "interactions" )
+ message = self.error_max_vals % ( max_vals, "interactions" )
break
feature = line.split()
https://bitbucket.org/galaxy/galaxy-central/changeset/6805c477d616/
changeset: 6805c477d616
user: jgoecks
date: 2012-09-14 18:23:03
summary: Rename tracks package to genome to reflect that code is used for all genome browsers, not just trackster.
affected #: 16 files
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/datatypes/converters/interval_to_interval_index_converter.py
--- a/lib/galaxy/datatypes/converters/interval_to_interval_index_converter.py
+++ b/lib/galaxy/datatypes/converters/interval_to_interval_index_converter.py
@@ -14,7 +14,7 @@
import sys, fileinput, optparse
from galaxy import eggs
import pkg_resources; pkg_resources.require( "bx-python" )
-from galaxy.visualization.tracks.summary import *
+from galaxy.visualization.genome.summary import *
from galaxy.datatypes.util.gff_util import convert_gff_coords_to_bed
from bx.interval_index_file import Indexes
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.py
--- a/lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.py
+++ b/lib/galaxy/datatypes/converters/interval_to_summary_tree_converter.py
@@ -15,7 +15,7 @@
import sys, fileinput, optparse
from galaxy import eggs
import pkg_resources; pkg_resources.require( "bx-python" )
-from galaxy.visualization.tracks.summary import *
+from galaxy.visualization.genome.summary import *
from bx.intervals.io import *
from galaxy.datatypes.util.gff_util import *
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/datatypes/converters/sam_or_bam_to_summary_tree_converter.py
--- a/lib/galaxy/datatypes/converters/sam_or_bam_to_summary_tree_converter.py
+++ b/lib/galaxy/datatypes/converters/sam_or_bam_to_summary_tree_converter.py
@@ -14,7 +14,7 @@
pkg_resources.require( "pysam" )
from pysam import csamtools
-from galaxy.visualization.tracks.summary import *
+from galaxy.visualization.genome.summary import *
def main():
parser = optparse.OptionParser()
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.py
--- a/lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.py
+++ b/lib/galaxy/datatypes/converters/vcf_to_summary_tree_converter.py
@@ -9,7 +9,7 @@
import optparse
import galaxy_utils.sequence.vcf
-from galaxy.visualization.tracks.summary import SummaryTree
+from galaxy.visualization.genome.summary import SummaryTree
def main():
# Read options, args.
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -35,7 +35,7 @@
from galaxy.util.shed_util import *
from galaxy.web import url_for
-from galaxy.visualization.tracks.visual_analytics import TracksterConfig
+from galaxy.visualization.genome.visual_analytics import TracksterConfig
log = logging.getLogger( __name__ )
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/visualization/genome/__init__.py
--- /dev/null
+++ b/lib/galaxy/visualization/genome/__init__.py
@@ -0,0 +1,3 @@
+"""
+Code for Galaxy genome visualizations.
+"""
\ No newline at end of file
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/visualization/genome/data_providers.py
--- /dev/null
+++ b/lib/galaxy/visualization/genome/data_providers.py
@@ -0,0 +1,1557 @@
+"""
+Data providers for genome visualizations.
+"""
+
+import os, sys
+from math import ceil, log
+import pkg_resources
+pkg_resources.require( "bx-python" )
+if sys.version_info[:2] == (2, 4):
+ pkg_resources.require( "ctypes" )
+pkg_resources.require( "pysam" )
+pkg_resources.require( "numpy" )
+import numpy
+from galaxy.datatypes.util.gff_util import *
+from galaxy.util.json import from_json_string
+from bx.interval_index_file import Indexes
+from bx.bbi.bigwig_file import BigWigFile
+from galaxy.util.lrucache import LRUCache
+from galaxy.visualization.genome.summary import *
+from galaxy.visualization.data_providers import BaseDataProvider
+import galaxy_utils.sequence.vcf
+from galaxy.datatypes.tabular import Tabular, Vcf
+from galaxy.datatypes.interval import Interval, Bed, Gff, Gtf, ENCODEPeak, ChromatinInteractions
+
+from pysam import csamtools, ctabix
+
+#
+# Utility functions.
+#
+
+def float_nan(n):
+ '''
+ Return None instead of NaN to pass jQuery 1.4's strict JSON
+ '''
+ if n != n: # NaN != NaN
+ return None
+ else:
+ return float(n)
+
+def get_bounds( reads, start_pos_index, end_pos_index ):
+ '''
+ Returns the minimum and maximum position for a set of reads.
+ '''
+ max_low = sys.maxint
+ max_high = -sys.maxint
+ for read in reads:
+ if read[ start_pos_index ] < max_low:
+ max_low = read[ start_pos_index ]
+ if read[ end_pos_index ] > max_high:
+ max_high = read[ end_pos_index ]
+ return max_low, max_high
+
+def _convert_between_ucsc_and_ensemble_naming( chrom ):
+ '''
+ Convert between UCSC chromosome ('chr1') naming conventions and Ensembl
+ naming conventions ('1')
+ '''
+ if chrom.startswith( 'chr' ):
+ # Convert from UCSC to Ensembl
+ return chrom[ 3: ]
+ else:
+ # Convert from Ensembl to UCSC
+ return 'chr' + chrom
+
+def _chrom_naming_matches( chrom1, chrom2 ):
+ return ( chrom1.startswith( 'chr' ) and chrom2.startswith( 'chr' ) ) or ( not chrom1.startswith( 'chr' ) and not chrom2.startswith( 'chr' ) )
+
+class FeatureLocationIndexDataProvider( BaseDataProvider ):
+ """
+ Reads/writes/queries feature location index (FLI) datasets.
+ """
+
+ def __init__( self, converted_dataset ):
+ self.converted_dataset = converted_dataset
+
+ def get_data( self, query ):
+ # Init.
+ textloc_file = open( self.converted_dataset.file_name, 'r' )
+ line_len = int( textloc_file.readline() )
+ file_len = os.path.getsize( self.converted_dataset.file_name )
+ query = query.lower()
+
+ # Find query in file using binary search.
+ low = 0
+ high = file_len / line_len
+ while low < high:
+ mid = ( low + high ) // 2
+ position = mid * line_len
+ textloc_file.seek( position )
+
+ # Compare line with query and update low, high.
+ line = textloc_file.readline()
+ if line < query:
+ low = mid + 1
+ else:
+ high = mid
+
+ position = low * line_len
+
+ # At right point in file, generate hits.
+ result = []
+ while True:
+ line = textloc_file.readline()
+ if not line.startswith( query ):
+ break
+ if line[ -1: ] == '\n':
+ line = line[ :-1 ]
+ result.append( line.split()[1:] )
+
+ textloc_file.close()
+ return result
+
+class GenomeDataProvider( BaseDataProvider ):
+ """ Base class for genome data providers. """
+
+ """
+ Mapping from column name to payload data; this mapping is used to create
+ filters. Key is column name, value is a dict with mandatory key 'index' and
+ optional key 'name'. E.g. this defines column 4
+
+ col_name_data_attr_mapping = {4 : { index: 5, name: 'Score' } }
+ """
+ col_name_data_attr_mapping = {}
+
+ def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None,
+ error_max_vals="Only the first %i %s in this region are displayed." ):
+ super( GenomeDataProvider, self ).__init__( converted_dataset=converted_dataset,
+ original_dataset=original_dataset,
+ dependencies=dependencies,
+ error_max_vals=error_max_vals )
+
+ def write_data_to_file( self, regions, filename ):
+ """
+ Write data in region defined by chrom, start, and end to a file.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def valid_chroms( self ):
+ """
+ Returns chroms/contigs that the dataset contains
+ """
+ return None # by default
+
+ def has_data( self, chrom, start, end, **kwargs ):
+ """
+ Returns true if dataset has data in the specified genome window, false
+ otherwise.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def get_iterator( self, chrom, start, end ):
+ """
+ Returns an iterator that provides data in the region chrom:start-end
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Process data from an iterator to a format that can be provided to client.
+ """
+ raise Exception( "Unimplemented Function" )
+
+ def get_data( self, chrom, start, end, start_val=0, max_vals=sys.maxint, **kwargs ):
+ """
+ Returns data in region defined by chrom, start, and end. start_val and
+ max_vals are used to denote the data to return: start_val is the first element to
+ return and max_vals indicates the number of values to return.
+
+ Return value must be a dictionary with the following attributes:
+ dataset_type, data
+ """
+ iterator = self.get_iterator( chrom, start, end )
+ return self.process_data( iterator, start_val, max_vals, **kwargs )
+
+ def get_genome_data( self, chroms_info, **kwargs ):
+ """
+ Returns data for complete genome.
+ """
+ dataset_summary = []
+ for chrom_info in chroms_info[ 'chrom_info' ]:
+ summary = self.get_data( chrom_info[ 'chrom' ], 0, chrom_info[ 'len' ], **kwargs )
+ dataset_summary.append( summary )
+
+ return dataset_summary
+
+ def get_filters( self ):
+ """
+ Returns filters for provider's data. Return value is a list of
+ filters; each filter is a dictionary with the keys 'name', 'index', 'type'.
+ NOTE: This method uses the original dataset's datatype and metadata to
+ create the filters.
+ """
+ # Get column names.
+ try:
+ column_names = self.original_dataset.datatype.column_names
+ except AttributeError:
+ try:
+ column_names = range( self.original_dataset.metadata.columns )
+ except: # Give up
+ return []
+
+ # Dataset must have column types; if not, cannot create filters.
+ try:
+ column_types = self.original_dataset.metadata.column_types
+ except AttributeError:
+ return []
+
+ # Create and return filters.
+ filters = []
+ if self.original_dataset.metadata.viz_filter_cols:
+ for viz_col_index in self.original_dataset.metadata.viz_filter_cols:
+ # Some columns are optional, so can't assume that a filter
+ # column is in dataset.
+ if viz_col_index >= len( column_names ):
+ continue;
+ col_name = column_names[ viz_col_index ]
+ # Make sure that column has a mapped index. If not, do not add filter.
+ try:
+ attrs = self.col_name_data_attr_mapping[ col_name ]
+ except KeyError:
+ continue
+ filters.append(
+ { 'name' : attrs[ 'name' ], 'type' : column_types[viz_col_index], \
+ 'index' : attrs[ 'index' ] } )
+ return filters
+
+ def get_default_max_vals( self ):
+ return 5000
+
+#
+# -- Base mixins and providers --
+#
+
+class FilterableMixin:
+ def get_filters( self ):
+ """ Returns a dataset's filters. """
+
+ # is_ functions taken from Tabular.set_meta
+ def is_int( column_text ):
+ try:
+ int( column_text )
+ return True
+ except:
+ return False
+ def is_float( column_text ):
+ try:
+ float( column_text )
+ return True
+ except:
+ if column_text.strip().lower() == 'na':
+ return True #na is special cased to be a float
+ return False
+
+ #
+ # Get filters.
+ # TODOs:
+ # (a) might be useful to move this into each datatype's set_meta method;
+ # (b) could look at first N lines to ensure GTF attribute types are consistent.
+ #
+ filters = []
+ # HACK: first 8 fields are for drawing, so start filter column index at 9.
+ filter_col = 8
+ if isinstance( self.original_dataset.datatype, Gff ):
+ # Can filter by score and GTF attributes.
+ filters = [ { 'name': 'Score',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c6' } ]
+ filter_col += 1
+ if isinstance( self.original_dataset.datatype, Gtf ):
+ # Create filters based on dataset metadata.
+ for name, a_type in self.original_dataset.metadata.attribute_types.items():
+ if a_type in [ 'int', 'float' ]:
+ filters.append(
+ { 'name': name,
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'gff_filter_by_attribute',
+ 'tool_exp_name': name } )
+ filter_col += 1
+
+ '''
+ # Old code: use first line in dataset to find attributes.
+ for i, line in enumerate( open(self.original_dataset.file_name) ):
+ if not line.startswith('#'):
+ # Look at first line for attributes and types.
+ attributes = parse_gff_attributes( line.split('\t')[8] )
+ for attr, value in attributes.items():
+ # Get attribute type.
+ if is_int( value ):
+ attr_type = 'int'
+ elif is_float( value ):
+ attr_type = 'float'
+ else:
+ attr_type = 'str'
+ # Add to filters.
+ if attr_type is not 'str':
+ filters.append( { 'name': attr, 'type': attr_type, 'index': filter_col } )
+ filter_col += 1
+ break
+ '''
+ elif isinstance( self.original_dataset.datatype, Bed ):
+ # Can filter by score column only.
+ filters = [ { 'name': 'Score',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c5'
+ } ]
+
+ return filters
+
+
+class TabixDataProvider( FilterableMixin, GenomeDataProvider ):
+ """
+ Tabix index data provider for the Galaxy track browser.
+ """
+
+ col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } }
+
+ def get_iterator( self, chrom, start, end ):
+ start, end = int(start), int(end)
+ if end >= (2<<29):
+ end = (2<<29 - 1) # Tabix-enforced maximum
+
+ bgzip_fname = self.dependencies['bgzip'].file_name
+
+ tabix = ctabix.Tabixfile(bgzip_fname, index_filename=self.converted_dataset.file_name)
+
+ # If chrom not in data, try alternative.
+ if chrom not in tabix.contigs:
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+
+ return tabix.fetch(reference=chrom, start=start, end=end)
+
+ def write_data_to_file( self, regions, filename ):
+ out = open( filename, "w" )
+
+ for region in regions:
+ # Write data in region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+ iterator = self.get_iterator( chrom, start, end )
+ for line in iterator:
+ out.write( "%s\n" % line )
+
+ out.close()
+
+#
+# -- Interval data providers --
+#
+
+class IntervalDataProvider( GenomeDataProvider ):
+ """
+ Processes BED data from native format to payload format.
+
+ Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ raise Exception( "Unimplemented Function" )
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Provides
+ """
+ # Build data to return. Payload format is:
+ # [ <guid/offset>, <start>, <end>, <name>, <strand> ]
+ #
+ # First three entries are mandatory, others are optional.
+ #
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ rval = []
+ message = None
+ # Subtract one b/c columns are 1-based but indices are 0-based.
+ col_fn = lambda col: None if col is None else col - 1
+ start_col = self.original_dataset.metadata.startCol - 1
+ end_col = self.original_dataset.metadata.endCol - 1
+ strand_col = col_fn( self.original_dataset.metadata.strandCol )
+ name_col = col_fn( self.original_dataset.metadata.nameCol )
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+
+ feature = line.split()
+ length = len(feature)
+ # Unique id is just a hash of the line
+ payload = [ hash(line), int( feature[start_col] ), int( feature [end_col] ) ]
+
+ if no_detail:
+ rval.append( payload )
+ continue
+
+ # Name, strand.
+ if name_col:
+ payload.append( feature[name_col] )
+ if strand_col:
+ # Put empty name as placeholder.
+ if not name_col: payload.append( "" )
+ payload.append( feature[strand_col] )
+
+ # Score (filter data)
+ if length >= 5 and filter_cols and filter_cols[0] == "Score":
+ try:
+ payload.append( float( feature[4] ) )
+ except:
+ payload.append( feature[4] )
+
+ rval.append( payload )
+
+ return { 'data': rval, 'message': message }
+
+ def write_data_to_file( self, regions, filename ):
+ raise Exception( "Unimplemented Function" )
+
+class IntervalTabixDataProvider( TabixDataProvider, IntervalDataProvider ):
+ """
+ Provides data from a BED file indexed via tabix.
+ """
+ pass
+
+
+#
+# -- BED data providers --
+#
+
+class BedDataProvider( GenomeDataProvider ):
+ """
+ Processes BED data from native format to payload format.
+
+ Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ raise Exception( "Unimplemented Method" )
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Provides
+ """
+ # Build data to return. Payload format is:
+ # [ <guid/offset>, <start>, <end>, <name>, <strand>, <thick_start>,
+ # <thick_end>, <blocks> ]
+ #
+ # First three entries are mandatory, others are optional.
+ #
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ rval = []
+ message = None
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+ # TODO: can we use column metadata to fill out payload?
+ # TODO: use function to set payload data
+
+ feature = line.split()
+ length = len(feature)
+ # Unique id is just a hash of the line
+ payload = [ hash(line), int(feature[1]), int(feature[2]) ]
+
+ if no_detail:
+ rval.append( payload )
+ continue
+
+ # Name, strand, thick start, thick end.
+ if length >= 4:
+ payload.append(feature[3])
+ if length >= 6:
+ payload.append(feature[5])
+ if length >= 8:
+ payload.append(int(feature[6]))
+ payload.append(int(feature[7]))
+
+ # Blocks.
+ if length >= 12:
+ block_sizes = [ int(n) for n in feature[10].split(',') if n != '']
+ block_starts = [ int(n) for n in feature[11].split(',') if n != '' ]
+ blocks = zip( block_sizes, block_starts )
+ payload.append( [ ( int(feature[1]) + block[1], int(feature[1]) + block[1] + block[0] ) for block in blocks ] )
+
+ # Score (filter data)
+ if length >= 5 and filter_cols and filter_cols[0] == "Score":
+ # If dataset doesn't have name/strand/thick start/thick end/blocks,
+ # add placeholders. There should be 8 entries if all attributes
+ # are present.
+ payload.extend( [ None for i in range( 8 - len( payload ) ) ] )
+
+ try:
+ payload.append( float( feature[4] ) )
+ except:
+ payload.append( feature[4] )
+
+ rval.append( payload )
+
+ return { 'data': rval, 'message': message }
+
+ def write_data_to_file( self, regions, filename ):
+ out = open( filename, "w" )
+
+ for region in regions:
+ # Write data in region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+ iterator = self.get_iterator( chrom, start, end )
+ for line in iterator:
+ out.write( "%s\n" % line )
+
+ out.close()
+
+class BedTabixDataProvider( TabixDataProvider, BedDataProvider ):
+ """
+ Provides data from a BED file indexed via tabix.
+ """
+ pass
+
+class RawBedDataProvider( BedDataProvider ):
+ """
+ Provide data from BED file.
+
+ NOTE: this data provider does not use indices, and hence will be very slow
+ for large datasets.
+ """
+
+ def get_iterator( self, chrom=None, start=None, end=None ):
+ # Read first line in order to match chrom naming format.
+ line = source.readline()
+ dataset_chrom = line.split()[0]
+ if not _chrom_naming_matches( chrom, dataset_chrom ):
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ # Undo read.
+ source.seek( 0 )
+
+ def line_filter_iter():
+ for line in open( self.original_dataset.file_name ):
+ if line.startswith( "track" ) or line.startswith( "browser" ):
+ continue
+ feature = line.split()
+ feature_chrom = feature[0]
+ feature_start = int( feature[1] )
+ feature_end = int( feature[2] )
+ if ( chrom is not None and feature_chrom != chrom ) \
+ or ( start is not None and feature_start > end ) \
+ or ( end is not None and feature_end < start ):
+ continue
+ yield line
+
+ return line_filter_iter()
+
+#
+# -- VCF data providers --
+#
+
+class VcfDataProvider( GenomeDataProvider ):
+ """
+ Abstract class that processes VCF data from native format to payload format.
+
+ Payload format: TODO
+ """
+
+ col_name_data_attr_mapping = { 'Qual' : { 'index': 6 , 'name' : 'Qual' } }
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Returns a dict with the following attributes:
+ data - a list of variants with the format
+ [<guid>, <start>, <end>, <name>, cigar, seq]
+
+ message - error/informative message
+ """
+ rval = []
+ message = None
+
+ def get_mapping( ref, alt ):
+ """
+ Returns ( offset, new_seq, cigar ) tuple that defines mapping of
+ alt to ref. Cigar format is an array of [ op_index, length ] pairs
+ where op_index is the 0-based index into the string "MIDNSHP=X"
+ """
+
+ cig_ops = "MIDNSHP=X"
+
+ ref_len = len( ref )
+ alt_len = len( alt )
+
+ # Substitutions?
+ if ref_len == alt_len:
+ return 0, alt, [ [ cig_ops.find( "M" ), ref_len ] ]
+
+ # Deletions?
+ alt_in_ref_index = ref.find( alt )
+ if alt_in_ref_index != -1:
+ return alt_in_ref_index, ref[ alt_in_ref_index + 1: ], [ [ cig_ops.find( "D" ), ref_len - alt_len ] ]
+
+ # Insertions?
+ ref_in_alt_index = alt.find( ref )
+ if ref_in_alt_index != -1:
+ return ref_in_alt_index, alt[ ref_in_alt_index + 1: ], [ [ cig_ops.find( "I" ), alt_len - ref_len ] ]
+
+ # Pack data.
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+
+ feature = line.split()
+ start = int( feature[1] ) - 1
+ ref = feature[3]
+ alts = feature[4]
+
+ # HACK? alts == '.' --> monomorphism.
+ if alts == '.':
+ alts = ref
+
+ # Pack variants.
+ for alt in alts.split(","):
+ offset, new_seq, cigar = get_mapping( ref, alt )
+ start += offset
+ end = start + len( new_seq )
+
+ # Pack line.
+ payload = [
+ hash( line ),
+ start,
+ end,
+ # ID:
+ feature[2],
+ cigar,
+ # TODO? VCF does not have strand, so default to positive.
+ "+",
+ new_seq,
+ None if feature[5] == '.' else float( feature[5] )
+ ]
+ rval.append(payload)
+
+ return { 'data': rval, 'message': message }
+
+ def write_data_to_file( self, regions, filename ):
+ out = open( filename, "w" )
+
+ for region in regions:
+ # Write data in region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+ iterator = self.get_iterator( chrom, start, end )
+ for line in iterator:
+ out.write( "%s\n" % line )
+ out.close()
+
+class VcfTabixDataProvider( TabixDataProvider, VcfDataProvider ):
+ """
+ Provides data from a VCF file indexed via tabix.
+ """
+ pass
+
+class RawVcfDataProvider( VcfDataProvider ):
+ """
+ Provide data from VCF file.
+
+ NOTE: this data provider does not use indices, and hence will be very slow
+ for large datasets.
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ # Read first line in order to match chrom naming format.
+ line = source.readline()
+ dataset_chrom = line.split()[0]
+ if not _chrom_naming_matches( chrom, dataset_chrom ):
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ # Undo read.
+ source.seek( 0 )
+
+ def line_filter_iter():
+ for line in open( self.original_dataset.file_name ):
+ if line.startswith("#"):
+ continue
+ variant = line.split()
+ variant_chrom, variant_start, id, ref, alts = variant[ 0:5 ]
+ variant_start = int( variant_start )
+ longest_alt = -1
+ for alt in alts:
+ if len( alt ) > longest_alt:
+ longest_alt = len( alt )
+ variant_end = variant_start + abs( len( ref ) - longest_alt )
+ if variant_chrom != chrom or variant_start > end or variant_end < start:
+ continue
+ yield line
+
+ return line_filter_iter()
+
+class SummaryTreeDataProvider( GenomeDataProvider ):
+ """
+ Summary tree data provider for the Galaxy track browser.
+ """
+
+ CACHE = LRUCache( 20 ) # Store 20 recently accessed indices for performance
+
+ def valid_chroms( self ):
+ st = summary_tree_from_file( self.converted_dataset.file_name )
+ return st.chrom_blocks.keys()
+
+ def get_data( self, chrom, start, end, level=None, resolution=None, detail_cutoff=None, draw_cutoff=None ):
+ """
+ Returns summary tree data for a given genomic region.
+ """
+ filename = self.converted_dataset.file_name
+ st = self.CACHE[filename]
+ if st is None:
+ st = summary_tree_from_file( self.converted_dataset.file_name )
+ self.CACHE[filename] = st
+
+ # Look for chrom in tree using both naming conventions.
+ if chrom not in st.chrom_blocks:
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ if chrom not in st.chrom_blocks:
+ return None
+
+ # Get or compute level.
+ if level:
+ level = int( level )
+ elif resolution:
+ resolution = max( 1, ceil( float( resolution ) ) )
+ level = ceil( log( resolution, st.block_size ) ) - 1
+ level = int( max( level, 0 ) )
+ else:
+ # Either level or resolution is required.
+ return None
+
+ if level <= 1:
+ return "detail"
+
+ # Use level to get results.
+ stats = st.chrom_stats[ chrom ]
+ results = st.query( chrom, int(start), int(end), level, detail_cutoff=detail_cutoff, draw_cutoff=draw_cutoff )
+ if results == "detail" or results == "draw":
+ return results
+ else:
+ return results, stats[ level ][ "max" ], stats[ level ]["avg" ], stats[ level ][ "delta" ]
+
+ def has_data( self, chrom ):
+ """
+ Returns true if dataset has data for this chrom
+ """
+
+ # Get summary tree.
+ filename = self.converted_dataset.file_name
+ st = self.CACHE[filename]
+ if st is None:
+ st = summary_tree_from_file( self.converted_dataset.file_name )
+ self.CACHE[filename] = st
+
+ # Check for data.
+ return st.chrom_blocks.get(chrom, None) or st.chrom_blocks.get(_convert_between_ucsc_and_ensemble_naming(chrom), None)
+
+class BamDataProvider( GenomeDataProvider, FilterableMixin ):
+ """
+ Provides access to intervals from a sorted indexed BAM file. Position data
+ is reported in 1-based, closed format, i.e. SAM/BAM format.
+ """
+
+ def get_filters( self ):
+ """
+ Returns filters for dataset.
+ """
+ # HACK: first 7 fields are for drawing, so start filter column index at 7.
+ filter_col = 7
+ filters = []
+ filters.append( { 'name': 'Mapping Quality',
+ 'type': 'number',
+ 'index': filter_col
+ } )
+ return filters
+
+
+ def write_data_to_file( self, regions, filename ):
+ """
+ Write reads in regions to file.
+ """
+
+ # Open current BAM file using index.
+ bamfile = csamtools.Samfile( filename=self.original_dataset.file_name, mode='rb', \
+ index_filename=self.converted_dataset.file_name )
+
+ # TODO: write headers as well?
+ new_bamfile = csamtools.Samfile( template=bamfile, filename=filename, mode='wb' )
+
+ for region in regions:
+ # Write data from region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+
+ try:
+ data = bamfile.fetch(start=start, end=end, reference=chrom)
+ except ValueError, e:
+ # Try alternative chrom naming.
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ try:
+ data = bamfile.fetch( start=start, end=end, reference=chrom )
+ except ValueError:
+ return None
+
+ # Write reads in region.
+ for i, read in enumerate( data ):
+ new_bamfile.write( read )
+
+ # Cleanup.
+ new_bamfile.close()
+ bamfile.close()
+
+ def get_iterator( self, chrom, start, end ):
+ """
+ Returns an iterator that provides data in the region chrom:start-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)
+ except ValueError, e:
+ # Try alternative chrom naming.
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ try:
+ data = bamfile.fetch( start=start, end=end, reference=chrom )
+ except ValueError:
+ return None
+ return data
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Returns a dict with the following attributes:
+ data - a list of reads with the format
+ [<guid>, <start>, <end>, <name>, <read_1>, <read_2>, [empty], <mapq_scores>]
+ where <read_1> has the format
+ [<start>, <end>, <cigar>, <strand>, <read_seq>]
+ and <read_2> has the format
+ [<start>, <end>, <cigar>, <strand>, <read_seq>]
+ Field 7 is empty so that mapq scores' location matches that in single-end reads.
+ For single-end reads, read has format:
+ [<guid>, <start>, <end>, <name>, <cigar>, <strand>, <seq>, <mapq_score>]
+
+ NOTE: read end and sequence data are not valid for reads outside of
+ requested region and should not be used.
+
+ max_low - lowest coordinate for the returned reads
+ max_high - highest coordinate for the returned reads
+ message - error/informative message
+ """
+ # No iterator indicates no reads.
+ if iterator is None:
+ return { 'data': [], 'message': None }
+
+ # Decode strand from read flag.
+ def decode_strand( read_flag, mask ):
+ strand_flag = ( read_flag & mask == 0 )
+ if strand_flag:
+ return "+"
+ else:
+ return "-"
+
+ # Encode reads as list of lists.
+ results = []
+ paired_pending = {}
+ unmapped = 0
+ message = None
+ for count, read in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if ( count - start_val - unmapped ) >= max_vals:
+ message = self.error_max_vals % ( max_vals, "reads" )
+ break
+
+ # If not mapped, skip read.
+ is_mapped = ( read.flag & 0x0004 == 0 )
+ if not is_mapped:
+ unmapped += 1
+ continue
+
+ qname = read.qname
+ seq = read.seq
+ strand = decode_strand( read.flag, 0x0010 )
+ if read.cigar is not None:
+ read_len = sum( [cig[1] for cig in read.cigar] ) # Use cigar to determine length
+ else:
+ read_len = len(seq) # If no cigar, just use sequence length
+
+ if read.is_proper_pair:
+ if qname in paired_pending: # one in dict is always first
+ pair = paired_pending[qname]
+ results.append( [ "%i_%s" % ( pair['start'], qname ),
+ pair['start'],
+ read.pos + read_len,
+ qname,
+ [ pair['start'], pair['end'], pair['cigar'], pair['strand'], pair['seq'] ],
+ [ read.pos, read.pos + read_len, read.cigar, strand, seq ],
+ None, [ pair['mapq'], read.mapq ]
+ ] )
+ del paired_pending[qname]
+ else:
+ paired_pending[qname] = { 'start': read.pos, 'end': read.pos + read_len, 'seq': seq, 'mate_start': read.mpos,
+ 'rlen': read_len, 'strand': strand, 'cigar': read.cigar, 'mapq': read.mapq }
+ else:
+ results.append( [ "%i_%s" % ( read.pos, qname ),
+ read.pos, read.pos + read_len, qname,
+ read.cigar, strand, read.seq, read.mapq ] )
+
+ # Take care of reads whose mates are out of range.
+ # TODO: count paired reads when adhering to max_vals?
+ for qname, read in paired_pending.iteritems():
+ if read['mate_start'] < read['start']:
+ # Mate is before read.
+ read_start = read['mate_start']
+ read_end = read['end']
+ # Make read_1 start=end so that length is 0 b/c we don't know
+ # read length.
+ r1 = [ read['mate_start'], read['mate_start'] ]
+ r2 = [ read['start'], read['end'], read['cigar'], read['strand'], read['seq'] ]
+ else:
+ # Mate is after read.
+ read_start = read['start']
+ # Make read_2 start=end so that length is 0 b/c we don't know
+ # read length. Hence, end of read is start of read_2.
+ read_end = read['mate_start']
+ r1 = [ read['start'], read['end'], read['cigar'], read['strand'], read['seq'] ]
+ r2 = [ read['mate_start'], read['mate_start'] ]
+
+ results.append( [ "%i_%s" % ( read_start, qname ), read_start, read_end, qname, r1, r2, [read[ 'mapq' ], 125] ] )
+
+ # Clean up. TODO: is this needed? If so, we'll need a cleanup function after processing the data.
+ # bamfile.close()
+
+ max_low, max_high = get_bounds( results, 1, 2 )
+
+ return { 'data': results, 'message': message, 'max_low': max_low, 'max_high': max_high }
+
+class SamDataProvider( BamDataProvider ):
+
+ def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None ):
+ """ Create SamDataProvider. """
+
+ # HACK: to use BamDataProvider, original dataset must be BAM and
+ # converted dataset must be BAI. Use BAI from BAM metadata.
+ if converted_dataset:
+ self.converted_dataset = converted_dataset.metadata.bam_index
+ self.original_dataset = converted_dataset
+ self.dependencies = dependencies
+
+class BBIDataProvider( GenomeDataProvider ):
+ """
+ BBI data provider for the Galaxy track browser.
+ """
+ def valid_chroms( self ):
+ # No way to return this info as of now
+ return None
+
+ def has_data( self, chrom ):
+ f, bbi = self._get_dataset()
+ all_dat = bbi.query(chrom, 0, 2147483647, 1)
+ f.close()
+ return all_dat is not None
+
+ def get_data( self, chrom, start, end, start_val=0, max_vals=None, **kwargs ):
+ # Bigwig can be a standalone bigwig file, in which case we use
+ # original_dataset, or coming from wig->bigwig conversion in
+ # which we use converted_dataset
+ f, bbi = self._get_dataset()
+
+ # If stats requested, compute overall summary data for the range
+ # start:endbut no reduced data. This is currently used by client
+ # to determine the default range.
+ if 'stats' in kwargs:
+ summary = bbi.summarize( chrom, start, end, 1 )
+ f.close()
+
+ min = 0
+ max = 0
+ mean = 0
+ sd = 0
+ if summary is not None:
+ # Does the summary contain any defined values?
+ valid_count = summary.valid_count[0]
+ if summary.valid_count > 0:
+ # Compute $\mu \pm 2\sigma$ to provide an estimate for upper and lower
+ # bounds that contain ~95% of the data.
+ mean = summary.sum_data[0] / valid_count
+ var = summary.sum_squares[0] - mean
+ if valid_count > 1:
+ var /= valid_count - 1
+ sd = numpy.sqrt( var )
+ min = summary.min_val[0]
+ max = summary.max_val[0]
+
+ return dict( data=dict( min=min, max=max, mean=mean, sd=sd ) )
+
+ # Sample from region using approximately this many samples.
+ N = 1000
+
+ def summarize_region( bbi, chrom, start, end, num_points ):
+ '''
+ Returns results from summarizing a region using num_points.
+ NOTE: num_points cannot be greater than end - start or BBI
+ will return None for all positions.s
+ '''
+ result = []
+
+ # Get summary; this samples at intervals of length
+ # (end - start)/num_points -- i.e. drops any fractional component
+ # of interval length.
+ summary = bbi.summarize( chrom, start, end, num_points )
+ if summary:
+ #mean = summary.sum_data / summary.valid_count
+
+ ## Standard deviation by bin, not yet used
+ ## var = summary.sum_squares - mean
+ ## var /= minimum( valid_count - 1, 1 )
+ ## sd = sqrt( var )
+
+ pos = start
+ step_size = (end - start) / num_points
+
+ for i in range( num_points ):
+ result.append( (pos, float_nan( summary.sum_data[i] / summary.valid_count[i] ) ) )
+ pos += step_size
+
+ return result
+
+ # Approach is different depending on region size.
+ if end - start < N:
+ # Get values for individual bases in region, including start and end.
+ # To do this, need to increase end to next base and request number of points.
+ num_points = end - start + 1
+ end += 1
+ else:
+ #
+ # The goal is to sample the region between start and end uniformly
+ # using ~N data points. The challenge is that the size of sampled
+ # intervals rarely is full bases, so sampling using N points will
+ # leave the end of the region unsampled due to remainders for each
+ # interval. To recitify this, a new N is calculated based on the
+ # step size that covers as much of the region as possible.
+ #
+ # However, this still leaves some of the region unsampled. This
+ # could be addressed by repeatedly sampling remainder using a
+ # smaller and smaller step_size, but that would require iteratively
+ # going to BBI, which could be time consuming.
+ #
+
+ # Start with N samples.
+ num_points = N
+ step_size = ( end - start ) / num_points
+ # Add additional points to sample in the remainder not covered by
+ # the initial N samples.
+ remainder_start = start + step_size * num_points
+ additional_points = ( end - remainder_start ) / step_size
+ num_points += additional_points
+
+ result = summarize_region( bbi, chrom, start, end, num_points )
+
+ # Cleanup and return.
+ f.close()
+ return { 'data': result }
+
+class BigBedDataProvider( BBIDataProvider ):
+ def _get_dataset( self ):
+ # Nothing converts to bigBed so we don't consider converted dataset
+ f = open( self.original_dataset.file_name )
+ return f, BigBedFile(file=f)
+
+class BigWigDataProvider ( BBIDataProvider ):
+ """
+ Provides data from BigWig files; position data is reported in 1-based
+ coordinate system, i.e. wiggle format.
+ """
+ def _get_dataset( self ):
+ if self.converted_dataset is not None:
+ f = open( self.converted_dataset.file_name )
+ else:
+ f = open( self.original_dataset.file_name )
+ return f, BigWigFile(file=f)
+
+class IntervalIndexDataProvider( FilterableMixin, GenomeDataProvider ):
+ """
+ Interval index files used only for GFF files.
+ """
+ col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } }
+
+ def write_data_to_file( self, regions, filename ):
+ source = open( self.original_dataset.file_name )
+ index = Indexes( self.converted_dataset.file_name )
+ out = open( filename, 'w' )
+
+ for region in regions:
+ # Write data from region.
+ chrom = region.chrom
+ start = region.start
+ end = region.end
+ for start, end, offset in index.find(chrom, start, end):
+ source.seek( offset )
+
+ reader = GFFReaderWrapper( source, fix_strand=True )
+ feature = reader.next()
+ for interval in feature.intervals:
+ out.write( '\t'.join( interval.fields ) + '\n' )
+
+ out.close()
+
+ def get_iterator( self, chrom, start, end ):
+ """
+ Returns an array with values: (a) source file and (b) an iterator that
+ provides data in the region chrom:start-end
+ """
+ start, end = int(start), int(end)
+ source = open( self.original_dataset.file_name )
+ index = Indexes( self.converted_dataset.file_name )
+
+ if chrom not in index.indexes:
+ # Try alternative naming.
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+
+ return index.find(chrom, start, end)
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ results = []
+ message = None
+ source = open( self.original_dataset.file_name )
+
+ #
+ # Build data to return. Payload format is:
+ # [ <guid/offset>, <start>, <end>, <name>, <score>, <strand>, <thick_start>,
+ # <thick_end>, <blocks> ]
+ #
+ # First three entries are mandatory, others are optional.
+ #
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ for count, val in enumerate( iterator ):
+ start, end, offset = val[0], val[1], val[2]
+ if count < start_val:
+ continue
+ if count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+ source.seek( offset )
+ # TODO: can we use column metadata to fill out payload?
+
+ # GFF dataset.
+ reader = GFFReaderWrapper( source, fix_strand=True )
+ feature = reader.next()
+ payload = package_gff_feature( feature, no_detail, filter_cols )
+ payload.insert( 0, offset )
+
+ results.append( payload )
+
+ return { 'data': results, 'message': message }
+
+class RawGFFDataProvider( GenomeDataProvider ):
+ """
+ Provide data from GFF file that has not been indexed.
+
+ NOTE: this data provider does not use indices, and hence will be very slow
+ for large datasets.
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ """
+ Returns an iterator that provides data in the region chrom:start-end as well as
+ a file offset.
+ """
+ source = open( self.original_dataset.file_name )
+
+ # Read first line in order to match chrom naming format.
+ line = source.readline()
+ dataset_chrom = line.split()[0]
+ if not _chrom_naming_matches( chrom, dataset_chrom ):
+ chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
+ # Undo read.
+ source.seek( 0 )
+
+ def features_in_region_iter():
+ offset = 0
+ for feature in GFFReaderWrapper( source, fix_strand=True ):
+ # Only provide features that are in region.
+ feature_start, feature_end = convert_gff_coords_to_bed( [ feature.start, feature.end ] )
+ if feature.chrom == chrom and feature_end > start and feature_start < end:
+ yield feature, offset
+ offset += feature.raw_size
+
+ return features_in_region_iter()
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Process data from an iterator to a format that can be provided to client.
+ """
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ results = []
+ message = None
+
+ for count, ( feature, offset ) in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "reads" )
+ break
+
+ payload = package_gff_feature( feature, no_detail=no_detail, filter_cols=filter_cols )
+ payload.insert( 0, offset )
+ results.append( payload )
+
+
+ return { 'data': results, 'message': message }
+
+class GtfTabixDataProvider( TabixDataProvider ):
+ """
+ Returns data from GTF datasets that are indexed via tabix.
+ """
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ # Loop through lines and group by transcript_id; each group is a feature.
+
+ # TODO: extend this code or use code in gff_util to process GFF/3 as well
+ # and then create a generic GFFDataProvider that can be used with both
+ # raw and tabix datasets.
+ features = {}
+ for count, line in enumerate( iterator ):
+ line_attrs = parse_gff_attributes( line.split('\t')[8] )
+ transcript_id = line_attrs[ 'transcript_id' ]
+ if transcript_id in features:
+ feature = features[ transcript_id ]
+ else:
+ feature = []
+ features[ transcript_id ] = feature
+ feature.append( GFFInterval( None, line.split( '\t') ) )
+
+ # Process data.
+ filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
+ no_detail = ( "no_detail" in kwargs )
+ results = []
+ message = None
+
+ for count, intervals in enumerate( features.values() ):
+ if count < start_val:
+ continue
+ if count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "reads" )
+ break
+
+ feature = GFFFeature( None, intervals=intervals )
+ payload = package_gff_feature( feature, no_detail=no_detail, filter_cols=filter_cols )
+ payload.insert( 0, feature.intervals[ 0 ].attributes[ 'transcript_id' ] )
+ results.append( payload )
+
+ return { 'data': results, 'message': message }
+
+#
+# -- ENCODE Peak data providers.
+#
+
+class ENCODEPeakDataProvider( GenomeDataProvider ):
+ """
+ Abstract class that processes ENCODEPeak data from native format to payload format.
+
+ Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
+ """
+
+ def get_iterator( self, chrom, start, end ):
+ raise "Unimplemented Method"
+
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Provides
+ """
+
+ ## FIXMEs:
+ # (1) should be able to unify some of this code with BedDataProvider.process_data
+ # (2) are optional number of parameters supported?
+
+ # Build data to return. Payload format is:
+ # [ <guid/offset>, <start>, <end>, <name>, <strand>, <thick_start>,
+ # <thick_end>, <blocks> ]
+ #
+ # First three entries are mandatory, others are optional.
+ #
+ no_detail = ( "no_detail" in kwargs )
+ rval = []
+ message = None
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "features" )
+ break
+
+ feature = line.split()
+ length = len( feature )
+
+ # Feature initialization.
+ payload = [
+ # GUID is just a hash of the line
+ hash( line ),
+ # Add start, end.
+ int( feature[1] ),
+ int( feature[2] )
+ ]
+
+ if no_detail:
+ rval.append( payload )
+ continue
+
+ # Extend with additional data.
+ payload.extend( [
+ # Add name, strand.
+ feature[3],
+ feature[5],
+ # Thick start, end are feature start, end for now.
+ int( feature[1] ),
+ int( feature[2] ),
+ # No blocks.
+ None,
+ # Filtering data: Score, signalValue, pValue, qValue.
+ float( feature[4] ),
+ float( feature[6] ),
+ float( feature[7] ),
+ float( feature[8] )
+ ] )
+
+ rval.append( payload )
+
+ return { 'data': rval, 'message': message }
+
+class ENCODEPeakTabixDataProvider( TabixDataProvider, ENCODEPeakDataProvider ):
+ """
+ Provides data from an ENCODEPeak dataset indexed via tabix.
+ """
+
+ def get_filters( self ):
+ """
+ Returns filters for dataset.
+ """
+ # HACK: first 8 fields are for drawing, so start filter column index at 9.
+ filter_col = 8
+ filters = []
+ filters.append( { 'name': 'Score',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c6' } )
+ filter_col += 1
+ filters.append( { 'name': 'Signal Value',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c7' } )
+ filter_col += 1
+ filters.append( { 'name': 'pValue',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c8' } )
+ filter_col += 1
+ filters.append( { 'name': 'qValue',
+ 'type': 'number',
+ 'index': filter_col,
+ 'tool_id': 'Filter1',
+ 'tool_exp_name': 'c9' } )
+ return filters
+
+#
+# -- ChromatinInteraction data providers --
+#
+class ChromatinInteractionsDataProvider( GenomeDataProvider ):
+ def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
+ """
+ Provides
+ """
+
+ rval = []
+ message = None
+ for count, line in enumerate( iterator ):
+ if count < start_val:
+ continue
+ if max_vals and count-start_val >= max_vals:
+ message = self.error_max_vals % ( max_vals, "interactions" )
+ break
+
+ feature = line.split()
+ length = len( feature )
+
+ s1 = int( feature[1] ),
+ e1 = int( feature[2] ),
+ c = feature[3],
+ s2 = int( feature[4] ),
+ e2 = int( feature[5] ),
+ v = float( feature[6] )
+
+ # Feature initialization.
+ payload = [
+ # GUID is just a hash of the line
+ hash( line ),
+ # Add start1, end1, chr2, start2, end2, value.
+ s1, e1, c, s2, e2, v
+ ]
+
+ rval.append( payload )
+
+ return { 'data': rval, 'message': message }
+
+ def get_default_max_vals( self ):
+ return 50000;
+
+class ChromatinInteractionsTabixDataProvider( TabixDataProvider, ChromatinInteractionsDataProvider ):
+ def get_iterator( self, chrom, start, end ):
+ """
+ """
+ # Modify start as needed to get earlier interactions with start region.
+ start = max( 0, int( start) - 1000000 )
+ def filter( iter ):
+ for line in iter:
+ feature = line.split()
+ s1 = int( feature[1] ),
+ e1 = int( feature[2] ),
+ c = feature[3]
+ s2 = int( feature[4] ),
+ e2 = int( feature[5] ),
+ if ( ( c == chrom ) and ( s1 < end and e1 > start ) and ( s2 < end and e2 > start ) ):
+ yield line
+ return filter( TabixDataProvider.get_iterator( self, chrom, start, end ) )
+
+#
+# -- Helper methods. --
+#
+
+# Mapping from dataset type name to a class that can fetch data from a file of that
+# type. First key is converted dataset type; if result is another dict, second key
+# is original dataset type. TODO: This needs to be more flexible.
+dataset_type_name_to_data_provider = {
+ "tabix": {
+ Vcf: VcfTabixDataProvider,
+ Bed: BedTabixDataProvider,
+ Gtf: GtfTabixDataProvider,
+ ENCODEPeak: ENCODEPeakTabixDataProvider,
+ Interval: IntervalTabixDataProvider,
+ ChromatinInteractions: ChromatinInteractionsTabixDataProvider,
+ "default" : TabixDataProvider
+ },
+ "interval_index": IntervalIndexDataProvider,
+ "bai": BamDataProvider,
+ "bam": SamDataProvider,
+ "summary_tree": SummaryTreeDataProvider,
+ "bigwig": BigWigDataProvider,
+ "bigbed": BigBedDataProvider
+}
+
+def get_data_provider( name=None, original_dataset=None ):
+ """
+ Returns data provider class by name and/or original dataset.
+ """
+ data_provider = None
+ if name:
+ value = dataset_type_name_to_data_provider[ name ]
+ if isinstance( value, dict ):
+ # Get converter by dataset extension; if there is no data provider,
+ # get the default.
+ data_provider = value.get( original_dataset.datatype.__class__, value.get( "default" ) )
+ else:
+ data_provider = value
+ elif original_dataset:
+ # Look up data provider from datatype's informaton.
+ try:
+ # Get data provider mapping and data provider for 'data'. If
+ # provider available, use it; otherwise use generic provider.
+ _ , data_provider_mapping = original_dataset.datatype.get_track_type()
+ if 'data_standalone' in data_provider_mapping:
+ data_provider_name = data_provider_mapping[ 'data_standalone' ]
+ else:
+ data_provider_name = data_provider_mapping[ 'data' ]
+ if data_provider_name:
+ data_provider = get_data_provider( name=data_provider_name, original_dataset=original_dataset )
+ else:
+ data_provider = GenomeDataProvider
+ except:
+ pass
+ return data_provider
+
+def package_gff_feature( feature, no_detail=False, filter_cols=[] ):
+ """ Package a GFF feature in an array for data providers. """
+ feature = convert_gff_coords_to_bed( feature )
+
+ # No detail means only start, end.
+ if no_detail:
+ return [ feature.start, feature.end ]
+
+ # Return full feature.
+ payload = [ feature.start,
+ feature.end,
+ feature.name(),
+ feature.strand,
+ # No notion of thick start, end in GFF, so make everything
+ # thick.
+ feature.start,
+ feature.end
+ ]
+
+ # HACK: ignore interval with name 'transcript' from feature.
+ # Cufflinks puts this interval in each of its transcripts,
+ # and they mess up trackster by covering the feature's blocks.
+ # This interval will always be a feature's first interval,
+ # and the GFF's third column is its feature name.
+ feature_intervals = feature.intervals
+ if feature.intervals[0].fields[2] == 'transcript':
+ feature_intervals = feature.intervals[1:]
+ # Add blocks.
+ block_sizes = [ (interval.end - interval.start ) for interval in feature_intervals ]
+ block_starts = [ ( interval.start - feature.start ) for interval in feature_intervals ]
+ blocks = zip( block_sizes, block_starts )
+ payload.append( [ ( feature.start + block[1], feature.start + block[1] + block[0] ) for block in blocks ] )
+
+ # Add filter data to payload.
+ for col in filter_cols:
+ if col == "Score":
+ if feature.score == 'nan':
+ payload.append( feature.score )
+ else:
+ try:
+ f = float( feature.score )
+ payload.append( f )
+ except:
+ payload.append( feature.score )
+ elif col in feature.attributes:
+ if feature.attributes[col] == 'nan':
+ payload.append( feature.attributes[col] )
+ else:
+ try:
+ f = float( feature.attributes[col] )
+ payload.append( f )
+ except:
+ payload.append( feature.attributes[col] )
+ else:
+ # Dummy value.
+ payload.append( 0 )
+ return payload
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/visualization/genome/summary.py
--- /dev/null
+++ b/lib/galaxy/visualization/genome/summary.py
@@ -0,0 +1,111 @@
+'''
+Summary tree data structure for feature aggregation across large genomic regions.
+'''
+
+import sys, os
+import cPickle
+
+# TODO: What are the performance implications of setting min level to 1? Data
+# structure size and/or query speed? It would be nice to have level 1 data
+# so that client does not have to compute it.
+MIN_LEVEL = 2
+
+class SummaryTree:
+ def __init__( self, block_size=25, levels=6, draw_cutoff=150, detail_cutoff=30 ):
+ self.chrom_blocks = {}
+ self.levels = levels
+ self.draw_cutoff = draw_cutoff
+ self.detail_cutoff = detail_cutoff
+ self.block_size = block_size
+ self.chrom_stats = {}
+
+ def find_block( self, num, level ):
+ """ Returns block that num is in for level. """
+ return ( num / self.block_size ** level )
+
+ def insert_range( self, chrom, start, end ):
+ """ Inserts a feature at chrom:start-end into the tree. """
+
+ # Get or set up chrom blocks.
+ if chrom in self.chrom_blocks:
+ blocks = self.chrom_blocks[ chrom ]
+ else:
+ blocks = self.chrom_blocks[ chrom ] = {}
+ self.chrom_stats[ chrom ] = {}
+ for level in range( MIN_LEVEL, self.levels + 1 ):
+ blocks[ level ] = {}
+
+ # Insert feature into all matching blocks at all levels.
+ for level in range( MIN_LEVEL, self.levels + 1 ):
+ block_level = blocks[ level ]
+ starting_block = self.find_block( start, level )
+ ending_block = self.find_block( end, level )
+ for block in range( starting_block, ending_block + 1 ):
+ if block in block_level:
+ block_level[ block ] += 1
+ else:
+ block_level[ block ] = 1
+
+ def finish( self ):
+ """ Compute stats for levels. """
+
+ for chrom, blocks in self.chrom_blocks.iteritems():
+ for level in range( self.levels, MIN_LEVEL - 1, -1 ):
+ # Set level's stats.
+ max_val = max( blocks[ level ].values() )
+ self.chrom_stats[ chrom ][ level ] = {}
+ self.chrom_stats[ chrom ][ level ][ "delta" ] = self.block_size ** level
+ self.chrom_stats[ chrom ][ level ][ "max" ] = max_val
+ self.chrom_stats[ chrom ][ level ][ "avg" ] = float( max_val ) / len( blocks[ level ] )
+
+ self.chrom_blocks[ chrom ] = dict( [ ( key, value ) for key, value in blocks.iteritems() ] )
+
+ def query( self, chrom, start, end, level, draw_cutoff=None, detail_cutoff=None ):
+ """ Queries tree for data. """
+
+ # Set cutoffs to self's attributes if not defined.
+ if draw_cutoff != 0:
+ draw_cutoff = self.draw_cutoff
+ if detail_cutoff != 0:
+ detail_cutoff = self.detail_cutoff
+
+ # Get data.
+ if chrom in self.chrom_blocks:
+ stats = self.chrom_stats[ chrom ]
+
+ # For backwards compatibility:
+ if "detail_level" in stats and level <= stats[ "detail_level" ]:
+ return "detail"
+ elif "draw_level" in stats and level <= stats[ "draw_level" ]:
+ return "draw"
+
+ # If below draw, detail level, return string to denote this.
+ max = stats[ level ][ "max" ]
+ if max < detail_cutoff:
+ return "detail"
+ if max < draw_cutoff:
+ return "draw"
+
+ # Return block data.
+ blocks = self.chrom_blocks[ chrom ]
+ results = []
+ multiplier = self.block_size ** level
+ starting_block = self.find_block( start, level )
+ ending_block = self.find_block( end, level )
+ for block in range( starting_block, ending_block + 1 ):
+ val = 0
+ if block in blocks[ level ]:
+ val = blocks[ level ][ block ]
+ results.append( ( block * multiplier, val ) )
+ return results
+
+ return None
+
+ def write( self, filename ):
+ """ Writes tree to file. """
+ self.finish()
+ cPickle.dump( self, open( filename, 'wb' ), 2 )
+
+def summary_tree_from_file( filename ):
+ return cPickle.load( open( filename, "rb" ) )
+
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/visualization/genome/visual_analytics.py
--- /dev/null
+++ b/lib/galaxy/visualization/genome/visual_analytics.py
@@ -0,0 +1,80 @@
+import urllib
+
+from galaxy.tools.parameters.basic import IntegerToolParameter, FloatToolParameter, SelectToolParameter
+from galaxy.tools.parameters.dynamic_options import DynamicOptions
+
+class TracksterConfig:
+ """ Trackster configuration encapsulation. """
+
+ def __init__( self, actions ):
+ self.actions = actions
+
+ @staticmethod
+ def parse( root ):
+ actions = []
+ for action_elt in root.findall( "action" ):
+ actions.append( SetParamAction.parse( action_elt ) )
+ return TracksterConfig( actions )
+
+class SetParamAction:
+ """ Set parameter action. """
+
+ def __init__( self, name, output_name ):
+ self.name = name
+ self.output_name = output_name
+
+ @staticmethod
+ def parse( elt ):
+ """ Parse action from element. """
+ return SetParamAction( elt.get( "name" ), elt.get( "output_name" ) )
+
+def get_dataset_job( hda ):
+ # Get dataset's job.
+ job = None
+ for job_output_assoc in hda.creating_job_associations:
+ job = job_output_assoc.job
+ break
+ return job
+
+def get_tool_def( trans, hda ):
+ """ Returns definition of an interactive tool for an HDA. """
+
+ job = get_dataset_job( hda )
+ # TODO: could use this assertion to provide more information.
+ # assert job is not None, 'Requested job has not been loaded.'
+ if not job:
+ return None
+ tool = trans.app.toolbox.get_tool( job.tool_id )
+ # TODO: could use this assertion to provide more information.
+ # assert tool is not None, 'Requested tool has not been loaded.'
+ if not tool:
+ return None
+
+ # Tool must have a Trackster configuration.
+ if not tool.trackster_conf:
+ return None
+
+ # Get list of tool parameters that can be interactively modified.
+ tool_params = []
+ tool_param_values = dict( [ ( p.name, p.value ) for p in job.parameters ] )
+ tool_param_values = tool.params_from_strings( tool_param_values, trans.app, ignore_errors=True )
+ for name, input in tool.inputs.items():
+ if type( input ) == IntegerToolParameter or type( input ) == FloatToolParameter:
+ param_dict = { 'name' : name, 'label' : input.label, \
+ 'value' : tool_param_values.get( name, input.value ), \
+ 'type' : 'number', 'init_value' : input.value,
+ 'html' : urllib.quote( input.get_html() ) }
+ if input.min:
+ param_dict['min'] = input.min
+ if input.max:
+ param_dict['max'] = input.max
+ tool_params.append( param_dict )
+ elif type( input ) == SelectToolParameter and type( input.options ) != DynamicOptions:
+ tool_params.append( { 'name' : name, 'label' : input.label, 'type' : 'select', \
+ 'value' : tool_param_values.get( name, None ), \
+ 'html' : urllib.quote( input.get_html() ) } )
+
+ # If tool has parameters that can be interactively modified, return tool.
+ if len( tool_params ) != 0:
+ return { 'name' : tool.name, 'params' : tool_params }
+ return None
\ No newline at end of file
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/visualization/tracks/__init__.py
--- a/lib/galaxy/visualization/tracks/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Package for track style visualization using the trackster UI.
-"""
\ No newline at end of file
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/visualization/tracks/data_providers.py
--- a/lib/galaxy/visualization/tracks/data_providers.py
+++ /dev/null
@@ -1,1557 +0,0 @@
-"""
-Data providers for genome visualizations.
-"""
-
-import os, sys
-from math import ceil, log
-import pkg_resources
-pkg_resources.require( "bx-python" )
-if sys.version_info[:2] == (2, 4):
- pkg_resources.require( "ctypes" )
-pkg_resources.require( "pysam" )
-pkg_resources.require( "numpy" )
-import numpy
-from galaxy.datatypes.util.gff_util import *
-from galaxy.util.json import from_json_string
-from bx.interval_index_file import Indexes
-from bx.bbi.bigwig_file import BigWigFile
-from galaxy.util.lrucache import LRUCache
-from galaxy.visualization.tracks.summary import *
-from galaxy.visualization.data_providers import BaseDataProvider
-import galaxy_utils.sequence.vcf
-from galaxy.datatypes.tabular import Tabular, Vcf
-from galaxy.datatypes.interval import Interval, Bed, Gff, Gtf, ENCODEPeak, ChromatinInteractions
-
-from pysam import csamtools, ctabix
-
-#
-# Utility functions.
-#
-
-def float_nan(n):
- '''
- Return None instead of NaN to pass jQuery 1.4's strict JSON
- '''
- if n != n: # NaN != NaN
- return None
- else:
- return float(n)
-
-def get_bounds( reads, start_pos_index, end_pos_index ):
- '''
- Returns the minimum and maximum position for a set of reads.
- '''
- max_low = sys.maxint
- max_high = -sys.maxint
- for read in reads:
- if read[ start_pos_index ] < max_low:
- max_low = read[ start_pos_index ]
- if read[ end_pos_index ] > max_high:
- max_high = read[ end_pos_index ]
- return max_low, max_high
-
-def _convert_between_ucsc_and_ensemble_naming( chrom ):
- '''
- Convert between UCSC chromosome ('chr1') naming conventions and Ensembl
- naming conventions ('1')
- '''
- if chrom.startswith( 'chr' ):
- # Convert from UCSC to Ensembl
- return chrom[ 3: ]
- else:
- # Convert from Ensembl to UCSC
- return 'chr' + chrom
-
-def _chrom_naming_matches( chrom1, chrom2 ):
- return ( chrom1.startswith( 'chr' ) and chrom2.startswith( 'chr' ) ) or ( not chrom1.startswith( 'chr' ) and not chrom2.startswith( 'chr' ) )
-
-class FeatureLocationIndexDataProvider( BaseDataProvider ):
- """
- Reads/writes/queries feature location index (FLI) datasets.
- """
-
- def __init__( self, converted_dataset ):
- self.converted_dataset = converted_dataset
-
- def get_data( self, query ):
- # Init.
- textloc_file = open( self.converted_dataset.file_name, 'r' )
- line_len = int( textloc_file.readline() )
- file_len = os.path.getsize( self.converted_dataset.file_name )
- query = query.lower()
-
- # Find query in file using binary search.
- low = 0
- high = file_len / line_len
- while low < high:
- mid = ( low + high ) // 2
- position = mid * line_len
- textloc_file.seek( position )
-
- # Compare line with query and update low, high.
- line = textloc_file.readline()
- if line < query:
- low = mid + 1
- else:
- high = mid
-
- position = low * line_len
-
- # At right point in file, generate hits.
- result = []
- while True:
- line = textloc_file.readline()
- if not line.startswith( query ):
- break
- if line[ -1: ] == '\n':
- line = line[ :-1 ]
- result.append( line.split()[1:] )
-
- textloc_file.close()
- return result
-
-class TracksDataProvider( BaseDataProvider ):
- """ Base class for tracks data providers. """
-
- """
- Mapping from column name to payload data; this mapping is used to create
- filters. Key is column name, value is a dict with mandatory key 'index' and
- optional key 'name'. E.g. this defines column 4
-
- col_name_data_attr_mapping = {4 : { index: 5, name: 'Score' } }
- """
- col_name_data_attr_mapping = {}
-
- def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None,
- error_max_vals="Only the first %i %s in this region are displayed." ):
- super( TracksDataProvider, self ).__init__( converted_dataset=converted_dataset,
- original_dataset=original_dataset,
- dependencies=dependencies,
- error_max_vals=error_max_vals )
-
- def write_data_to_file( self, regions, filename ):
- """
- Write data in region defined by chrom, start, and end to a file.
- """
- raise Exception( "Unimplemented Function" )
-
- def valid_chroms( self ):
- """
- Returns chroms/contigs that the dataset contains
- """
- return None # by default
-
- def has_data( self, chrom, start, end, **kwargs ):
- """
- Returns true if dataset has data in the specified genome window, false
- otherwise.
- """
- raise Exception( "Unimplemented Function" )
-
- def get_iterator( self, chrom, start, end ):
- """
- Returns an iterator that provides data in the region chrom:start-end
- """
- raise Exception( "Unimplemented Function" )
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Process data from an iterator to a format that can be provided to client.
- """
- raise Exception( "Unimplemented Function" )
-
- def get_data( self, chrom, start, end, start_val=0, max_vals=sys.maxint, **kwargs ):
- """
- Returns data in region defined by chrom, start, and end. start_val and
- max_vals are used to denote the data to return: start_val is the first element to
- return and max_vals indicates the number of values to return.
-
- Return value must be a dictionary with the following attributes:
- dataset_type, data
- """
- iterator = self.get_iterator( chrom, start, end )
- return self.process_data( iterator, start_val, max_vals, **kwargs )
-
- def get_genome_data( self, chroms_info, **kwargs ):
- """
- Returns data for complete genome.
- """
- dataset_summary = []
- for chrom_info in chroms_info[ 'chrom_info' ]:
- summary = self.get_data( chrom_info[ 'chrom' ], 0, chrom_info[ 'len' ], **kwargs )
- dataset_summary.append( summary )
-
- return dataset_summary
-
- def get_filters( self ):
- """
- Returns filters for provider's data. Return value is a list of
- filters; each filter is a dictionary with the keys 'name', 'index', 'type'.
- NOTE: This method uses the original dataset's datatype and metadata to
- create the filters.
- """
- # Get column names.
- try:
- column_names = self.original_dataset.datatype.column_names
- except AttributeError:
- try:
- column_names = range( self.original_dataset.metadata.columns )
- except: # Give up
- return []
-
- # Dataset must have column types; if not, cannot create filters.
- try:
- column_types = self.original_dataset.metadata.column_types
- except AttributeError:
- return []
-
- # Create and return filters.
- filters = []
- if self.original_dataset.metadata.viz_filter_cols:
- for viz_col_index in self.original_dataset.metadata.viz_filter_cols:
- # Some columns are optional, so can't assume that a filter
- # column is in dataset.
- if viz_col_index >= len( column_names ):
- continue;
- col_name = column_names[ viz_col_index ]
- # Make sure that column has a mapped index. If not, do not add filter.
- try:
- attrs = self.col_name_data_attr_mapping[ col_name ]
- except KeyError:
- continue
- filters.append(
- { 'name' : attrs[ 'name' ], 'type' : column_types[viz_col_index], \
- 'index' : attrs[ 'index' ] } )
- return filters
-
- def get_default_max_vals( self ):
- return 5000
-
-#
-# -- Base mixins and providers --
-#
-
-class FilterableMixin:
- def get_filters( self ):
- """ Returns a dataset's filters. """
-
- # is_ functions taken from Tabular.set_meta
- def is_int( column_text ):
- try:
- int( column_text )
- return True
- except:
- return False
- def is_float( column_text ):
- try:
- float( column_text )
- return True
- except:
- if column_text.strip().lower() == 'na':
- return True #na is special cased to be a float
- return False
-
- #
- # Get filters.
- # TODOs:
- # (a) might be useful to move this into each datatype's set_meta method;
- # (b) could look at first N lines to ensure GTF attribute types are consistent.
- #
- filters = []
- # HACK: first 8 fields are for drawing, so start filter column index at 9.
- filter_col = 8
- if isinstance( self.original_dataset.datatype, Gff ):
- # Can filter by score and GTF attributes.
- filters = [ { 'name': 'Score',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c6' } ]
- filter_col += 1
- if isinstance( self.original_dataset.datatype, Gtf ):
- # Create filters based on dataset metadata.
- for name, a_type in self.original_dataset.metadata.attribute_types.items():
- if a_type in [ 'int', 'float' ]:
- filters.append(
- { 'name': name,
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'gff_filter_by_attribute',
- 'tool_exp_name': name } )
- filter_col += 1
-
- '''
- # Old code: use first line in dataset to find attributes.
- for i, line in enumerate( open(self.original_dataset.file_name) ):
- if not line.startswith('#'):
- # Look at first line for attributes and types.
- attributes = parse_gff_attributes( line.split('\t')[8] )
- for attr, value in attributes.items():
- # Get attribute type.
- if is_int( value ):
- attr_type = 'int'
- elif is_float( value ):
- attr_type = 'float'
- else:
- attr_type = 'str'
- # Add to filters.
- if attr_type is not 'str':
- filters.append( { 'name': attr, 'type': attr_type, 'index': filter_col } )
- filter_col += 1
- break
- '''
- elif isinstance( self.original_dataset.datatype, Bed ):
- # Can filter by score column only.
- filters = [ { 'name': 'Score',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c5'
- } ]
-
- return filters
-
-
-class TabixDataProvider( FilterableMixin, TracksDataProvider ):
- """
- Tabix index data provider for the Galaxy track browser.
- """
-
- col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } }
-
- def get_iterator( self, chrom, start, end ):
- start, end = int(start), int(end)
- if end >= (2<<29):
- end = (2<<29 - 1) # Tabix-enforced maximum
-
- bgzip_fname = self.dependencies['bgzip'].file_name
-
- tabix = ctabix.Tabixfile(bgzip_fname, index_filename=self.converted_dataset.file_name)
-
- # If chrom not in data, try alternative.
- if chrom not in tabix.contigs:
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
-
- return tabix.fetch(reference=chrom, start=start, end=end)
-
- def write_data_to_file( self, regions, filename ):
- out = open( filename, "w" )
-
- for region in regions:
- # Write data in region.
- chrom = region.chrom
- start = region.start
- end = region.end
- iterator = self.get_iterator( chrom, start, end )
- for line in iterator:
- out.write( "%s\n" % line )
-
- out.close()
-
-#
-# -- Interval data providers --
-#
-
-class IntervalDataProvider( TracksDataProvider ):
- """
- Processes BED data from native format to payload format.
-
- Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
- """
-
- def get_iterator( self, chrom, start, end ):
- raise Exception( "Unimplemented Function" )
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Provides
- """
- # Build data to return. Payload format is:
- # [ <guid/offset>, <start>, <end>, <name>, <strand> ]
- #
- # First three entries are mandatory, others are optional.
- #
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- rval = []
- message = None
- # Subtract one b/c columns are 1-based but indices are 0-based.
- col_fn = lambda col: None if col is None else col - 1
- start_col = self.original_dataset.metadata.startCol - 1
- end_col = self.original_dataset.metadata.endCol - 1
- strand_col = col_fn( self.original_dataset.metadata.strandCol )
- name_col = col_fn( self.original_dataset.metadata.nameCol )
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
-
- feature = line.split()
- length = len(feature)
- # Unique id is just a hash of the line
- payload = [ hash(line), int( feature[start_col] ), int( feature [end_col] ) ]
-
- if no_detail:
- rval.append( payload )
- continue
-
- # Name, strand.
- if name_col:
- payload.append( feature[name_col] )
- if strand_col:
- # Put empty name as placeholder.
- if not name_col: payload.append( "" )
- payload.append( feature[strand_col] )
-
- # Score (filter data)
- if length >= 5 and filter_cols and filter_cols[0] == "Score":
- try:
- payload.append( float( feature[4] ) )
- except:
- payload.append( feature[4] )
-
- rval.append( payload )
-
- return { 'data': rval, 'message': message }
-
- def write_data_to_file( self, regions, filename ):
- raise Exception( "Unimplemented Function" )
-
-class IntervalTabixDataProvider( TabixDataProvider, IntervalDataProvider ):
- """
- Provides data from a BED file indexed via tabix.
- """
- pass
-
-
-#
-# -- BED data providers --
-#
-
-class BedDataProvider( TracksDataProvider ):
- """
- Processes BED data from native format to payload format.
-
- Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
- """
-
- def get_iterator( self, chrom, start, end ):
- raise Exception( "Unimplemented Method" )
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Provides
- """
- # Build data to return. Payload format is:
- # [ <guid/offset>, <start>, <end>, <name>, <strand>, <thick_start>,
- # <thick_end>, <blocks> ]
- #
- # First three entries are mandatory, others are optional.
- #
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- rval = []
- message = None
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
- # TODO: can we use column metadata to fill out payload?
- # TODO: use function to set payload data
-
- feature = line.split()
- length = len(feature)
- # Unique id is just a hash of the line
- payload = [ hash(line), int(feature[1]), int(feature[2]) ]
-
- if no_detail:
- rval.append( payload )
- continue
-
- # Name, strand, thick start, thick end.
- if length >= 4:
- payload.append(feature[3])
- if length >= 6:
- payload.append(feature[5])
- if length >= 8:
- payload.append(int(feature[6]))
- payload.append(int(feature[7]))
-
- # Blocks.
- if length >= 12:
- block_sizes = [ int(n) for n in feature[10].split(',') if n != '']
- block_starts = [ int(n) for n in feature[11].split(',') if n != '' ]
- blocks = zip( block_sizes, block_starts )
- payload.append( [ ( int(feature[1]) + block[1], int(feature[1]) + block[1] + block[0] ) for block in blocks ] )
-
- # Score (filter data)
- if length >= 5 and filter_cols and filter_cols[0] == "Score":
- # If dataset doesn't have name/strand/thick start/thick end/blocks,
- # add placeholders. There should be 8 entries if all attributes
- # are present.
- payload.extend( [ None for i in range( 8 - len( payload ) ) ] )
-
- try:
- payload.append( float( feature[4] ) )
- except:
- payload.append( feature[4] )
-
- rval.append( payload )
-
- return { 'data': rval, 'message': message }
-
- def write_data_to_file( self, regions, filename ):
- out = open( filename, "w" )
-
- for region in regions:
- # Write data in region.
- chrom = region.chrom
- start = region.start
- end = region.end
- iterator = self.get_iterator( chrom, start, end )
- for line in iterator:
- out.write( "%s\n" % line )
-
- out.close()
-
-class BedTabixDataProvider( TabixDataProvider, BedDataProvider ):
- """
- Provides data from a BED file indexed via tabix.
- """
- pass
-
-class RawBedDataProvider( BedDataProvider ):
- """
- Provide data from BED file.
-
- NOTE: this data provider does not use indices, and hence will be very slow
- for large datasets.
- """
-
- def get_iterator( self, chrom=None, start=None, end=None ):
- # Read first line in order to match chrom naming format.
- line = source.readline()
- dataset_chrom = line.split()[0]
- if not _chrom_naming_matches( chrom, dataset_chrom ):
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- # Undo read.
- source.seek( 0 )
-
- def line_filter_iter():
- for line in open( self.original_dataset.file_name ):
- if line.startswith( "track" ) or line.startswith( "browser" ):
- continue
- feature = line.split()
- feature_chrom = feature[0]
- feature_start = int( feature[1] )
- feature_end = int( feature[2] )
- if ( chrom is not None and feature_chrom != chrom ) \
- or ( start is not None and feature_start > end ) \
- or ( end is not None and feature_end < start ):
- continue
- yield line
-
- return line_filter_iter()
-
-#
-# -- VCF data providers --
-#
-
-class VcfDataProvider( TracksDataProvider ):
- """
- Abstract class that processes VCF data from native format to payload format.
-
- Payload format: TODO
- """
-
- col_name_data_attr_mapping = { 'Qual' : { 'index': 6 , 'name' : 'Qual' } }
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Returns a dict with the following attributes:
- data - a list of variants with the format
- [<guid>, <start>, <end>, <name>, cigar, seq]
-
- message - error/informative message
- """
- rval = []
- message = None
-
- def get_mapping( ref, alt ):
- """
- Returns ( offset, new_seq, cigar ) tuple that defines mapping of
- alt to ref. Cigar format is an array of [ op_index, length ] pairs
- where op_index is the 0-based index into the string "MIDNSHP=X"
- """
-
- cig_ops = "MIDNSHP=X"
-
- ref_len = len( ref )
- alt_len = len( alt )
-
- # Substitutions?
- if ref_len == alt_len:
- return 0, alt, [ [ cig_ops.find( "M" ), ref_len ] ]
-
- # Deletions?
- alt_in_ref_index = ref.find( alt )
- if alt_in_ref_index != -1:
- return alt_in_ref_index, ref[ alt_in_ref_index + 1: ], [ [ cig_ops.find( "D" ), ref_len - alt_len ] ]
-
- # Insertions?
- ref_in_alt_index = alt.find( ref )
- if ref_in_alt_index != -1:
- return ref_in_alt_index, alt[ ref_in_alt_index + 1: ], [ [ cig_ops.find( "I" ), alt_len - ref_len ] ]
-
- # Pack data.
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
-
- feature = line.split()
- start = int( feature[1] ) - 1
- ref = feature[3]
- alts = feature[4]
-
- # HACK? alts == '.' --> monomorphism.
- if alts == '.':
- alts = ref
-
- # Pack variants.
- for alt in alts.split(","):
- offset, new_seq, cigar = get_mapping( ref, alt )
- start += offset
- end = start + len( new_seq )
-
- # Pack line.
- payload = [
- hash( line ),
- start,
- end,
- # ID:
- feature[2],
- cigar,
- # TODO? VCF does not have strand, so default to positive.
- "+",
- new_seq,
- None if feature[5] == '.' else float( feature[5] )
- ]
- rval.append(payload)
-
- return { 'data': rval, 'message': message }
-
- def write_data_to_file( self, regions, filename ):
- out = open( filename, "w" )
-
- for region in regions:
- # Write data in region.
- chrom = region.chrom
- start = region.start
- end = region.end
- iterator = self.get_iterator( chrom, start, end )
- for line in iterator:
- out.write( "%s\n" % line )
- out.close()
-
-class VcfTabixDataProvider( TabixDataProvider, VcfDataProvider ):
- """
- Provides data from a VCF file indexed via tabix.
- """
- pass
-
-class RawVcfDataProvider( VcfDataProvider ):
- """
- Provide data from VCF file.
-
- NOTE: this data provider does not use indices, and hence will be very slow
- for large datasets.
- """
-
- def get_iterator( self, chrom, start, end ):
- # Read first line in order to match chrom naming format.
- line = source.readline()
- dataset_chrom = line.split()[0]
- if not _chrom_naming_matches( chrom, dataset_chrom ):
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- # Undo read.
- source.seek( 0 )
-
- def line_filter_iter():
- for line in open( self.original_dataset.file_name ):
- if line.startswith("#"):
- continue
- variant = line.split()
- variant_chrom, variant_start, id, ref, alts = variant[ 0:5 ]
- variant_start = int( variant_start )
- longest_alt = -1
- for alt in alts:
- if len( alt ) > longest_alt:
- longest_alt = len( alt )
- variant_end = variant_start + abs( len( ref ) - longest_alt )
- if variant_chrom != chrom or variant_start > end or variant_end < start:
- continue
- yield line
-
- return line_filter_iter()
-
-class SummaryTreeDataProvider( TracksDataProvider ):
- """
- Summary tree data provider for the Galaxy track browser.
- """
-
- CACHE = LRUCache( 20 ) # Store 20 recently accessed indices for performance
-
- def valid_chroms( self ):
- st = summary_tree_from_file( self.converted_dataset.file_name )
- return st.chrom_blocks.keys()
-
- def get_data( self, chrom, start, end, level=None, resolution=None, detail_cutoff=None, draw_cutoff=None ):
- """
- Returns summary tree data for a given genomic region.
- """
- filename = self.converted_dataset.file_name
- st = self.CACHE[filename]
- if st is None:
- st = summary_tree_from_file( self.converted_dataset.file_name )
- self.CACHE[filename] = st
-
- # Look for chrom in tree using both naming conventions.
- if chrom not in st.chrom_blocks:
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- if chrom not in st.chrom_blocks:
- return None
-
- # Get or compute level.
- if level:
- level = int( level )
- elif resolution:
- resolution = max( 1, ceil( float( resolution ) ) )
- level = ceil( log( resolution, st.block_size ) ) - 1
- level = int( max( level, 0 ) )
- else:
- # Either level or resolution is required.
- return None
-
- if level <= 1:
- return "detail"
-
- # Use level to get results.
- stats = st.chrom_stats[ chrom ]
- results = st.query( chrom, int(start), int(end), level, detail_cutoff=detail_cutoff, draw_cutoff=draw_cutoff )
- if results == "detail" or results == "draw":
- return results
- else:
- return results, stats[ level ][ "max" ], stats[ level ]["avg" ], stats[ level ][ "delta" ]
-
- def has_data( self, chrom ):
- """
- Returns true if dataset has data for this chrom
- """
-
- # Get summary tree.
- filename = self.converted_dataset.file_name
- st = self.CACHE[filename]
- if st is None:
- st = summary_tree_from_file( self.converted_dataset.file_name )
- self.CACHE[filename] = st
-
- # Check for data.
- return st.chrom_blocks.get(chrom, None) or st.chrom_blocks.get(_convert_between_ucsc_and_ensemble_naming(chrom), None)
-
-class BamDataProvider( TracksDataProvider, FilterableMixin ):
- """
- Provides access to intervals from a sorted indexed BAM file. Position data
- is reported in 1-based, closed format, i.e. SAM/BAM format.
- """
-
- def get_filters( self ):
- """
- Returns filters for dataset.
- """
- # HACK: first 7 fields are for drawing, so start filter column index at 7.
- filter_col = 7
- filters = []
- filters.append( { 'name': 'Mapping Quality',
- 'type': 'number',
- 'index': filter_col
- } )
- return filters
-
-
- def write_data_to_file( self, regions, filename ):
- """
- Write reads in regions to file.
- """
-
- # Open current BAM file using index.
- bamfile = csamtools.Samfile( filename=self.original_dataset.file_name, mode='rb', \
- index_filename=self.converted_dataset.file_name )
-
- # TODO: write headers as well?
- new_bamfile = csamtools.Samfile( template=bamfile, filename=filename, mode='wb' )
-
- for region in regions:
- # Write data from region.
- chrom = region.chrom
- start = region.start
- end = region.end
-
- try:
- data = bamfile.fetch(start=start, end=end, reference=chrom)
- except ValueError, e:
- # Try alternative chrom naming.
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- try:
- data = bamfile.fetch( start=start, end=end, reference=chrom )
- except ValueError:
- return None
-
- # Write reads in region.
- for i, read in enumerate( data ):
- new_bamfile.write( read )
-
- # Cleanup.
- new_bamfile.close()
- bamfile.close()
-
- def get_iterator( self, chrom, start, end ):
- """
- Returns an iterator that provides data in the region chrom:start-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)
- except ValueError, e:
- # Try alternative chrom naming.
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- try:
- data = bamfile.fetch( start=start, end=end, reference=chrom )
- except ValueError:
- return None
- return data
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Returns a dict with the following attributes:
- data - a list of reads with the format
- [<guid>, <start>, <end>, <name>, <read_1>, <read_2>, [empty], <mapq_scores>]
- where <read_1> has the format
- [<start>, <end>, <cigar>, <strand>, <read_seq>]
- and <read_2> has the format
- [<start>, <end>, <cigar>, <strand>, <read_seq>]
- Field 7 is empty so that mapq scores' location matches that in single-end reads.
- For single-end reads, read has format:
- [<guid>, <start>, <end>, <name>, <cigar>, <strand>, <seq>, <mapq_score>]
-
- NOTE: read end and sequence data are not valid for reads outside of
- requested region and should not be used.
-
- max_low - lowest coordinate for the returned reads
- max_high - highest coordinate for the returned reads
- message - error/informative message
- """
- # No iterator indicates no reads.
- if iterator is None:
- return { 'data': [], 'message': None }
-
- # Decode strand from read flag.
- def decode_strand( read_flag, mask ):
- strand_flag = ( read_flag & mask == 0 )
- if strand_flag:
- return "+"
- else:
- return "-"
-
- # Encode reads as list of lists.
- results = []
- paired_pending = {}
- unmapped = 0
- message = None
- for count, read in enumerate( iterator ):
- if count < start_val:
- continue
- if ( count - start_val - unmapped ) >= max_vals:
- message = self.error_max_vals % ( max_vals, "reads" )
- break
-
- # If not mapped, skip read.
- is_mapped = ( read.flag & 0x0004 == 0 )
- if not is_mapped:
- unmapped += 1
- continue
-
- qname = read.qname
- seq = read.seq
- strand = decode_strand( read.flag, 0x0010 )
- if read.cigar is not None:
- read_len = sum( [cig[1] for cig in read.cigar] ) # Use cigar to determine length
- else:
- read_len = len(seq) # If no cigar, just use sequence length
-
- if read.is_proper_pair:
- if qname in paired_pending: # one in dict is always first
- pair = paired_pending[qname]
- results.append( [ "%i_%s" % ( pair['start'], qname ),
- pair['start'],
- read.pos + read_len,
- qname,
- [ pair['start'], pair['end'], pair['cigar'], pair['strand'], pair['seq'] ],
- [ read.pos, read.pos + read_len, read.cigar, strand, seq ],
- None, [ pair['mapq'], read.mapq ]
- ] )
- del paired_pending[qname]
- else:
- paired_pending[qname] = { 'start': read.pos, 'end': read.pos + read_len, 'seq': seq, 'mate_start': read.mpos,
- 'rlen': read_len, 'strand': strand, 'cigar': read.cigar, 'mapq': read.mapq }
- else:
- results.append( [ "%i_%s" % ( read.pos, qname ),
- read.pos, read.pos + read_len, qname,
- read.cigar, strand, read.seq, read.mapq ] )
-
- # Take care of reads whose mates are out of range.
- # TODO: count paired reads when adhering to max_vals?
- for qname, read in paired_pending.iteritems():
- if read['mate_start'] < read['start']:
- # Mate is before read.
- read_start = read['mate_start']
- read_end = read['end']
- # Make read_1 start=end so that length is 0 b/c we don't know
- # read length.
- r1 = [ read['mate_start'], read['mate_start'] ]
- r2 = [ read['start'], read['end'], read['cigar'], read['strand'], read['seq'] ]
- else:
- # Mate is after read.
- read_start = read['start']
- # Make read_2 start=end so that length is 0 b/c we don't know
- # read length. Hence, end of read is start of read_2.
- read_end = read['mate_start']
- r1 = [ read['start'], read['end'], read['cigar'], read['strand'], read['seq'] ]
- r2 = [ read['mate_start'], read['mate_start'] ]
-
- results.append( [ "%i_%s" % ( read_start, qname ), read_start, read_end, qname, r1, r2, [read[ 'mapq' ], 125] ] )
-
- # Clean up. TODO: is this needed? If so, we'll need a cleanup function after processing the data.
- # bamfile.close()
-
- max_low, max_high = get_bounds( results, 1, 2 )
-
- return { 'data': results, 'message': message, 'max_low': max_low, 'max_high': max_high }
-
-class SamDataProvider( BamDataProvider ):
-
- def __init__( self, converted_dataset=None, original_dataset=None, dependencies=None ):
- """ Create SamDataProvider. """
-
- # HACK: to use BamDataProvider, original dataset must be BAM and
- # converted dataset must be BAI. Use BAI from BAM metadata.
- if converted_dataset:
- self.converted_dataset = converted_dataset.metadata.bam_index
- self.original_dataset = converted_dataset
- self.dependencies = dependencies
-
-class BBIDataProvider( TracksDataProvider ):
- """
- BBI data provider for the Galaxy track browser.
- """
- def valid_chroms( self ):
- # No way to return this info as of now
- return None
-
- def has_data( self, chrom ):
- f, bbi = self._get_dataset()
- all_dat = bbi.query(chrom, 0, 2147483647, 1)
- f.close()
- return all_dat is not None
-
- def get_data( self, chrom, start, end, start_val=0, max_vals=None, **kwargs ):
- # Bigwig can be a standalone bigwig file, in which case we use
- # original_dataset, or coming from wig->bigwig conversion in
- # which we use converted_dataset
- f, bbi = self._get_dataset()
-
- # If stats requested, compute overall summary data for the range
- # start:endbut no reduced data. This is currently used by client
- # to determine the default range.
- if 'stats' in kwargs:
- summary = bbi.summarize( chrom, start, end, 1 )
- f.close()
-
- min = 0
- max = 0
- mean = 0
- sd = 0
- if summary is not None:
- # Does the summary contain any defined values?
- valid_count = summary.valid_count[0]
- if summary.valid_count > 0:
- # Compute $\mu \pm 2\sigma$ to provide an estimate for upper and lower
- # bounds that contain ~95% of the data.
- mean = summary.sum_data[0] / valid_count
- var = summary.sum_squares[0] - mean
- if valid_count > 1:
- var /= valid_count - 1
- sd = numpy.sqrt( var )
- min = summary.min_val[0]
- max = summary.max_val[0]
-
- return dict( data=dict( min=min, max=max, mean=mean, sd=sd ) )
-
- # Sample from region using approximately this many samples.
- N = 1000
-
- def summarize_region( bbi, chrom, start, end, num_points ):
- '''
- Returns results from summarizing a region using num_points.
- NOTE: num_points cannot be greater than end - start or BBI
- will return None for all positions.s
- '''
- result = []
-
- # Get summary; this samples at intervals of length
- # (end - start)/num_points -- i.e. drops any fractional component
- # of interval length.
- summary = bbi.summarize( chrom, start, end, num_points )
- if summary:
- #mean = summary.sum_data / summary.valid_count
-
- ## Standard deviation by bin, not yet used
- ## var = summary.sum_squares - mean
- ## var /= minimum( valid_count - 1, 1 )
- ## sd = sqrt( var )
-
- pos = start
- step_size = (end - start) / num_points
-
- for i in range( num_points ):
- result.append( (pos, float_nan( summary.sum_data[i] / summary.valid_count[i] ) ) )
- pos += step_size
-
- return result
-
- # Approach is different depending on region size.
- if end - start < N:
- # Get values for individual bases in region, including start and end.
- # To do this, need to increase end to next base and request number of points.
- num_points = end - start + 1
- end += 1
- else:
- #
- # The goal is to sample the region between start and end uniformly
- # using ~N data points. The challenge is that the size of sampled
- # intervals rarely is full bases, so sampling using N points will
- # leave the end of the region unsampled due to remainders for each
- # interval. To recitify this, a new N is calculated based on the
- # step size that covers as much of the region as possible.
- #
- # However, this still leaves some of the region unsampled. This
- # could be addressed by repeatedly sampling remainder using a
- # smaller and smaller step_size, but that would require iteratively
- # going to BBI, which could be time consuming.
- #
-
- # Start with N samples.
- num_points = N
- step_size = ( end - start ) / num_points
- # Add additional points to sample in the remainder not covered by
- # the initial N samples.
- remainder_start = start + step_size * num_points
- additional_points = ( end - remainder_start ) / step_size
- num_points += additional_points
-
- result = summarize_region( bbi, chrom, start, end, num_points )
-
- # Cleanup and return.
- f.close()
- return { 'data': result }
-
-class BigBedDataProvider( BBIDataProvider ):
- def _get_dataset( self ):
- # Nothing converts to bigBed so we don't consider converted dataset
- f = open( self.original_dataset.file_name )
- return f, BigBedFile(file=f)
-
-class BigWigDataProvider ( BBIDataProvider ):
- """
- Provides data from BigWig files; position data is reported in 1-based
- coordinate system, i.e. wiggle format.
- """
- def _get_dataset( self ):
- if self.converted_dataset is not None:
- f = open( self.converted_dataset.file_name )
- else:
- f = open( self.original_dataset.file_name )
- return f, BigWigFile(file=f)
-
-class IntervalIndexDataProvider( FilterableMixin, TracksDataProvider ):
- """
- Interval index files used only for GFF files.
- """
- col_name_data_attr_mapping = { 4 : { 'index': 4 , 'name' : 'Score' } }
-
- def write_data_to_file( self, regions, filename ):
- source = open( self.original_dataset.file_name )
- index = Indexes( self.converted_dataset.file_name )
- out = open( filename, 'w' )
-
- for region in regions:
- # Write data from region.
- chrom = region.chrom
- start = region.start
- end = region.end
- for start, end, offset in index.find(chrom, start, end):
- source.seek( offset )
-
- reader = GFFReaderWrapper( source, fix_strand=True )
- feature = reader.next()
- for interval in feature.intervals:
- out.write( '\t'.join( interval.fields ) + '\n' )
-
- out.close()
-
- def get_iterator( self, chrom, start, end ):
- """
- Returns an array with values: (a) source file and (b) an iterator that
- provides data in the region chrom:start-end
- """
- start, end = int(start), int(end)
- source = open( self.original_dataset.file_name )
- index = Indexes( self.converted_dataset.file_name )
-
- if chrom not in index.indexes:
- # Try alternative naming.
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
-
- return index.find(chrom, start, end)
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- results = []
- message = None
- source = open( self.original_dataset.file_name )
-
- #
- # Build data to return. Payload format is:
- # [ <guid/offset>, <start>, <end>, <name>, <score>, <strand>, <thick_start>,
- # <thick_end>, <blocks> ]
- #
- # First three entries are mandatory, others are optional.
- #
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- for count, val in enumerate( iterator ):
- start, end, offset = val[0], val[1], val[2]
- if count < start_val:
- continue
- if count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
- source.seek( offset )
- # TODO: can we use column metadata to fill out payload?
-
- # GFF dataset.
- reader = GFFReaderWrapper( source, fix_strand=True )
- feature = reader.next()
- payload = package_gff_feature( feature, no_detail, filter_cols )
- payload.insert( 0, offset )
-
- results.append( payload )
-
- return { 'data': results, 'message': message }
-
-class RawGFFDataProvider( TracksDataProvider ):
- """
- Provide data from GFF file that has not been indexed.
-
- NOTE: this data provider does not use indices, and hence will be very slow
- for large datasets.
- """
-
- def get_iterator( self, chrom, start, end ):
- """
- Returns an iterator that provides data in the region chrom:start-end as well as
- a file offset.
- """
- source = open( self.original_dataset.file_name )
-
- # Read first line in order to match chrom naming format.
- line = source.readline()
- dataset_chrom = line.split()[0]
- if not _chrom_naming_matches( chrom, dataset_chrom ):
- chrom = _convert_between_ucsc_and_ensemble_naming( chrom )
- # Undo read.
- source.seek( 0 )
-
- def features_in_region_iter():
- offset = 0
- for feature in GFFReaderWrapper( source, fix_strand=True ):
- # Only provide features that are in region.
- feature_start, feature_end = convert_gff_coords_to_bed( [ feature.start, feature.end ] )
- if feature.chrom == chrom and feature_end > start and feature_start < end:
- yield feature, offset
- offset += feature.raw_size
-
- return features_in_region_iter()
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Process data from an iterator to a format that can be provided to client.
- """
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- results = []
- message = None
-
- for count, ( feature, offset ) in enumerate( iterator ):
- if count < start_val:
- continue
- if count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "reads" )
- break
-
- payload = package_gff_feature( feature, no_detail=no_detail, filter_cols=filter_cols )
- payload.insert( 0, offset )
- results.append( payload )
-
-
- return { 'data': results, 'message': message }
-
-class GtfTabixDataProvider( TabixDataProvider ):
- """
- Returns data from GTF datasets that are indexed via tabix.
- """
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- # Loop through lines and group by transcript_id; each group is a feature.
-
- # TODO: extend this code or use code in gff_util to process GFF/3 as well
- # and then create a generic GFFDataProvider that can be used with both
- # raw and tabix datasets.
- features = {}
- for count, line in enumerate( iterator ):
- line_attrs = parse_gff_attributes( line.split('\t')[8] )
- transcript_id = line_attrs[ 'transcript_id' ]
- if transcript_id in features:
- feature = features[ transcript_id ]
- else:
- feature = []
- features[ transcript_id ] = feature
- feature.append( GFFInterval( None, line.split( '\t') ) )
-
- # Process data.
- filter_cols = from_json_string( kwargs.get( "filter_cols", "[]" ) )
- no_detail = ( "no_detail" in kwargs )
- results = []
- message = None
-
- for count, intervals in enumerate( features.values() ):
- if count < start_val:
- continue
- if count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "reads" )
- break
-
- feature = GFFFeature( None, intervals=intervals )
- payload = package_gff_feature( feature, no_detail=no_detail, filter_cols=filter_cols )
- payload.insert( 0, feature.intervals[ 0 ].attributes[ 'transcript_id' ] )
- results.append( payload )
-
- return { 'data': results, 'message': message }
-
-#
-# -- ENCODE Peak data providers.
-#
-
-class ENCODEPeakDataProvider( TracksDataProvider ):
- """
- Abstract class that processes ENCODEPeak data from native format to payload format.
-
- Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ]
- """
-
- def get_iterator( self, chrom, start, end ):
- raise "Unimplemented Method"
-
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Provides
- """
-
- ## FIXMEs:
- # (1) should be able to unify some of this code with BedDataProvider.process_data
- # (2) are optional number of parameters supported?
-
- # Build data to return. Payload format is:
- # [ <guid/offset>, <start>, <end>, <name>, <strand>, <thick_start>,
- # <thick_end>, <blocks> ]
- #
- # First three entries are mandatory, others are optional.
- #
- no_detail = ( "no_detail" in kwargs )
- rval = []
- message = None
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "features" )
- break
-
- feature = line.split()
- length = len( feature )
-
- # Feature initialization.
- payload = [
- # GUID is just a hash of the line
- hash( line ),
- # Add start, end.
- int( feature[1] ),
- int( feature[2] )
- ]
-
- if no_detail:
- rval.append( payload )
- continue
-
- # Extend with additional data.
- payload.extend( [
- # Add name, strand.
- feature[3],
- feature[5],
- # Thick start, end are feature start, end for now.
- int( feature[1] ),
- int( feature[2] ),
- # No blocks.
- None,
- # Filtering data: Score, signalValue, pValue, qValue.
- float( feature[4] ),
- float( feature[6] ),
- float( feature[7] ),
- float( feature[8] )
- ] )
-
- rval.append( payload )
-
- return { 'data': rval, 'message': message }
-
-class ENCODEPeakTabixDataProvider( TabixDataProvider, ENCODEPeakDataProvider ):
- """
- Provides data from an ENCODEPeak dataset indexed via tabix.
- """
-
- def get_filters( self ):
- """
- Returns filters for dataset.
- """
- # HACK: first 8 fields are for drawing, so start filter column index at 9.
- filter_col = 8
- filters = []
- filters.append( { 'name': 'Score',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c6' } )
- filter_col += 1
- filters.append( { 'name': 'Signal Value',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c7' } )
- filter_col += 1
- filters.append( { 'name': 'pValue',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c8' } )
- filter_col += 1
- filters.append( { 'name': 'qValue',
- 'type': 'number',
- 'index': filter_col,
- 'tool_id': 'Filter1',
- 'tool_exp_name': 'c9' } )
- return filters
-
-#
-# -- ChromatinInteraction data providers --
-#
-class ChromatinInteractionsDataProvider( TracksDataProvider ):
- def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
- """
- Provides
- """
-
- rval = []
- message = None
- for count, line in enumerate( iterator ):
- if count < start_val:
- continue
- if max_vals and count-start_val >= max_vals:
- message = self.error_max_vals % ( max_vals, "interactions" )
- break
-
- feature = line.split()
- length = len( feature )
-
- s1 = int( feature[1] ),
- e1 = int( feature[2] ),
- c = feature[3],
- s2 = int( feature[4] ),
- e2 = int( feature[5] ),
- v = float( feature[6] )
-
- # Feature initialization.
- payload = [
- # GUID is just a hash of the line
- hash( line ),
- # Add start1, end1, chr2, start2, end2, value.
- s1, e1, c, s2, e2, v
- ]
-
- rval.append( payload )
-
- return { 'data': rval, 'message': message }
-
- def get_default_max_vals( self ):
- return 50000;
-
-class ChromatinInteractionsTabixDataProvider( TabixDataProvider, ChromatinInteractionsDataProvider ):
- def get_iterator( self, chrom, start, end ):
- """
- """
- # Modify start as needed to get earlier interactions with start region.
- start = max( 0, int( start) - 1000000 )
- def filter( iter ):
- for line in iter:
- feature = line.split()
- s1 = int( feature[1] ),
- e1 = int( feature[2] ),
- c = feature[3]
- s2 = int( feature[4] ),
- e2 = int( feature[5] ),
- if ( ( c == chrom ) and ( s1 < end and e1 > start ) and ( s2 < end and e2 > start ) ):
- yield line
- return filter( TabixDataProvider.get_iterator( self, chrom, start, end ) )
-
-#
-# -- Helper methods. --
-#
-
-# Mapping from dataset type name to a class that can fetch data from a file of that
-# type. First key is converted dataset type; if result is another dict, second key
-# is original dataset type. TODO: This needs to be more flexible.
-dataset_type_name_to_data_provider = {
- "tabix": {
- Vcf: VcfTabixDataProvider,
- Bed: BedTabixDataProvider,
- Gtf: GtfTabixDataProvider,
- ENCODEPeak: ENCODEPeakTabixDataProvider,
- Interval: IntervalTabixDataProvider,
- ChromatinInteractions: ChromatinInteractionsTabixDataProvider,
- "default" : TabixDataProvider
- },
- "interval_index": IntervalIndexDataProvider,
- "bai": BamDataProvider,
- "bam": SamDataProvider,
- "summary_tree": SummaryTreeDataProvider,
- "bigwig": BigWigDataProvider,
- "bigbed": BigBedDataProvider
-}
-
-def get_data_provider( name=None, original_dataset=None ):
- """
- Returns data provider class by name and/or original dataset.
- """
- data_provider = None
- if name:
- value = dataset_type_name_to_data_provider[ name ]
- if isinstance( value, dict ):
- # Get converter by dataset extension; if there is no data provider,
- # get the default.
- data_provider = value.get( original_dataset.datatype.__class__, value.get( "default" ) )
- else:
- data_provider = value
- elif original_dataset:
- # Look up data provider from datatype's informaton.
- try:
- # Get data provider mapping and data provider for 'data'. If
- # provider available, use it; otherwise use generic provider.
- _ , data_provider_mapping = original_dataset.datatype.get_track_type()
- if 'data_standalone' in data_provider_mapping:
- data_provider_name = data_provider_mapping[ 'data_standalone' ]
- else:
- data_provider_name = data_provider_mapping[ 'data' ]
- if data_provider_name:
- data_provider = get_data_provider( name=data_provider_name, original_dataset=original_dataset )
- else:
- data_provider = TracksDataProvider
- except:
- pass
- return data_provider
-
-def package_gff_feature( feature, no_detail=False, filter_cols=[] ):
- """ Package a GFF feature in an array for data providers. """
- feature = convert_gff_coords_to_bed( feature )
-
- # No detail means only start, end.
- if no_detail:
- return [ feature.start, feature.end ]
-
- # Return full feature.
- payload = [ feature.start,
- feature.end,
- feature.name(),
- feature.strand,
- # No notion of thick start, end in GFF, so make everything
- # thick.
- feature.start,
- feature.end
- ]
-
- # HACK: ignore interval with name 'transcript' from feature.
- # Cufflinks puts this interval in each of its transcripts,
- # and they mess up trackster by covering the feature's blocks.
- # This interval will always be a feature's first interval,
- # and the GFF's third column is its feature name.
- feature_intervals = feature.intervals
- if feature.intervals[0].fields[2] == 'transcript':
- feature_intervals = feature.intervals[1:]
- # Add blocks.
- block_sizes = [ (interval.end - interval.start ) for interval in feature_intervals ]
- block_starts = [ ( interval.start - feature.start ) for interval in feature_intervals ]
- blocks = zip( block_sizes, block_starts )
- payload.append( [ ( feature.start + block[1], feature.start + block[1] + block[0] ) for block in blocks ] )
-
- # Add filter data to payload.
- for col in filter_cols:
- if col == "Score":
- if feature.score == 'nan':
- payload.append( feature.score )
- else:
- try:
- f = float( feature.score )
- payload.append( f )
- except:
- payload.append( feature.score )
- elif col in feature.attributes:
- if feature.attributes[col] == 'nan':
- payload.append( feature.attributes[col] )
- else:
- try:
- f = float( feature.attributes[col] )
- payload.append( f )
- except:
- payload.append( feature.attributes[col] )
- else:
- # Dummy value.
- payload.append( 0 )
- return payload
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/visualization/tracks/summary.py
--- a/lib/galaxy/visualization/tracks/summary.py
+++ /dev/null
@@ -1,111 +0,0 @@
-'''
-Summary tree data structure for feature aggregation across large genomic regions.
-'''
-
-import sys, os
-import cPickle
-
-# TODO: What are the performance implications of setting min level to 1? Data
-# structure size and/or query speed? It would be nice to have level 1 data
-# so that client does not have to compute it.
-MIN_LEVEL = 2
-
-class SummaryTree:
- def __init__( self, block_size=25, levels=6, draw_cutoff=150, detail_cutoff=30 ):
- self.chrom_blocks = {}
- self.levels = levels
- self.draw_cutoff = draw_cutoff
- self.detail_cutoff = detail_cutoff
- self.block_size = block_size
- self.chrom_stats = {}
-
- def find_block( self, num, level ):
- """ Returns block that num is in for level. """
- return ( num / self.block_size ** level )
-
- def insert_range( self, chrom, start, end ):
- """ Inserts a feature at chrom:start-end into the tree. """
-
- # Get or set up chrom blocks.
- if chrom in self.chrom_blocks:
- blocks = self.chrom_blocks[ chrom ]
- else:
- blocks = self.chrom_blocks[ chrom ] = {}
- self.chrom_stats[ chrom ] = {}
- for level in range( MIN_LEVEL, self.levels + 1 ):
- blocks[ level ] = {}
-
- # Insert feature into all matching blocks at all levels.
- for level in range( MIN_LEVEL, self.levels + 1 ):
- block_level = blocks[ level ]
- starting_block = self.find_block( start, level )
- ending_block = self.find_block( end, level )
- for block in range( starting_block, ending_block + 1 ):
- if block in block_level:
- block_level[ block ] += 1
- else:
- block_level[ block ] = 1
-
- def finish( self ):
- """ Compute stats for levels. """
-
- for chrom, blocks in self.chrom_blocks.iteritems():
- for level in range( self.levels, MIN_LEVEL - 1, -1 ):
- # Set level's stats.
- max_val = max( blocks[ level ].values() )
- self.chrom_stats[ chrom ][ level ] = {}
- self.chrom_stats[ chrom ][ level ][ "delta" ] = self.block_size ** level
- self.chrom_stats[ chrom ][ level ][ "max" ] = max_val
- self.chrom_stats[ chrom ][ level ][ "avg" ] = float( max_val ) / len( blocks[ level ] )
-
- self.chrom_blocks[ chrom ] = dict( [ ( key, value ) for key, value in blocks.iteritems() ] )
-
- def query( self, chrom, start, end, level, draw_cutoff=None, detail_cutoff=None ):
- """ Queries tree for data. """
-
- # Set cutoffs to self's attributes if not defined.
- if draw_cutoff != 0:
- draw_cutoff = self.draw_cutoff
- if detail_cutoff != 0:
- detail_cutoff = self.detail_cutoff
-
- # Get data.
- if chrom in self.chrom_blocks:
- stats = self.chrom_stats[ chrom ]
-
- # For backwards compatibility:
- if "detail_level" in stats and level <= stats[ "detail_level" ]:
- return "detail"
- elif "draw_level" in stats and level <= stats[ "draw_level" ]:
- return "draw"
-
- # If below draw, detail level, return string to denote this.
- max = stats[ level ][ "max" ]
- if max < detail_cutoff:
- return "detail"
- if max < draw_cutoff:
- return "draw"
-
- # Return block data.
- blocks = self.chrom_blocks[ chrom ]
- results = []
- multiplier = self.block_size ** level
- starting_block = self.find_block( start, level )
- ending_block = self.find_block( end, level )
- for block in range( starting_block, ending_block + 1 ):
- val = 0
- if block in blocks[ level ]:
- val = blocks[ level ][ block ]
- results.append( ( block * multiplier, val ) )
- return results
-
- return None
-
- def write( self, filename ):
- """ Writes tree to file. """
- self.finish()
- cPickle.dump( self, open( filename, 'wb' ), 2 )
-
-def summary_tree_from_file( filename ):
- return cPickle.load( open( filename, "rb" ) )
-
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/visualization/tracks/visual_analytics.py
--- a/lib/galaxy/visualization/tracks/visual_analytics.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import urllib
-
-from galaxy.tools.parameters.basic import IntegerToolParameter, FloatToolParameter, SelectToolParameter
-from galaxy.tools.parameters.dynamic_options import DynamicOptions
-
-class TracksterConfig:
- """ Trackster configuration encapsulation. """
-
- def __init__( self, actions ):
- self.actions = actions
-
- @staticmethod
- def parse( root ):
- actions = []
- for action_elt in root.findall( "action" ):
- actions.append( SetParamAction.parse( action_elt ) )
- return TracksterConfig( actions )
-
-class SetParamAction:
- """ Set parameter action. """
-
- def __init__( self, name, output_name ):
- self.name = name
- self.output_name = output_name
-
- @staticmethod
- def parse( elt ):
- """ Parse action from element. """
- return SetParamAction( elt.get( "name" ), elt.get( "output_name" ) )
-
-def get_dataset_job( hda ):
- # Get dataset's job.
- job = None
- for job_output_assoc in hda.creating_job_associations:
- job = job_output_assoc.job
- break
- return job
-
-def get_tool_def( trans, hda ):
- """ Returns definition of an interactive tool for an HDA. """
-
- job = get_dataset_job( hda )
- # TODO: could use this assertion to provide more information.
- # assert job is not None, 'Requested job has not been loaded.'
- if not job:
- return None
- tool = trans.app.toolbox.get_tool( job.tool_id )
- # TODO: could use this assertion to provide more information.
- # assert tool is not None, 'Requested tool has not been loaded.'
- if not tool:
- return None
-
- # Tool must have a Trackster configuration.
- if not tool.trackster_conf:
- return None
-
- # Get list of tool parameters that can be interactively modified.
- tool_params = []
- tool_param_values = dict( [ ( p.name, p.value ) for p in job.parameters ] )
- tool_param_values = tool.params_from_strings( tool_param_values, trans.app, ignore_errors=True )
- for name, input in tool.inputs.items():
- if type( input ) == IntegerToolParameter or type( input ) == FloatToolParameter:
- param_dict = { 'name' : name, 'label' : input.label, \
- 'value' : tool_param_values.get( name, input.value ), \
- 'type' : 'number', 'init_value' : input.value,
- 'html' : urllib.quote( input.get_html() ) }
- if input.min:
- param_dict['min'] = input.min
- if input.max:
- param_dict['max'] = input.max
- tool_params.append( param_dict )
- elif type( input ) == SelectToolParameter and type( input.options ) != DynamicOptions:
- tool_params.append( { 'name' : name, 'label' : input.label, 'type' : 'select', \
- 'value' : tool_param_values.get( name, None ), \
- 'html' : urllib.quote( input.get_html() ) } )
-
- # If tool has parameters that can be interactively modified, return tool.
- if len( tool_params ) != 0:
- return { 'name' : tool.name, 'params' : tool_params }
- return None
\ No newline at end of file
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/web/api/tools.py
--- a/lib/galaxy/web/api/tools.py
+++ b/lib/galaxy/web/api/tools.py
@@ -1,9 +1,9 @@
from galaxy import web, util
from galaxy.web.base.controller import BaseAPIController, UsesHistoryDatasetAssociationMixin, UsesVisualizationMixin, messages, get_highest_priority_msg
-from galaxy.visualization.tracks.visual_analytics import get_dataset_job
+from galaxy.visualization.genome.visual_analytics import get_dataset_job
from galaxy.visualization.genomes import GenomeRegion
from galaxy.util.json import to_json_string, from_json_string
-from galaxy.visualization.tracks.data_providers import *
+from galaxy.visualization.genome.data_providers import *
class ToolsController( BaseAPIController, UsesHistoryDatasetAssociationMixin, UsesVisualizationMixin ):
"""
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -14,8 +14,8 @@
from galaxy.web.framework import simplejson
from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea, TextField
from galaxy.web.form_builder import WorkflowField, WorkflowMappingField, HistoryField, PasswordField, build_select_field
-from galaxy.visualization.tracks.data_providers import get_data_provider
-from galaxy.visualization.tracks.visual_analytics import get_tool_def
+from galaxy.visualization.genome.data_providers import get_data_provider
+from galaxy.visualization.genome.visual_analytics import get_tool_def
from galaxy.security.validate_user_input import validate_publicname
from paste.httpexceptions import *
from galaxy.exceptions import *
diff -r 586506caaad452c533493e5db8f26a362fb61280 -r 6805c477d61601ad304577ad6603dab71b22df24 lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py
+++ b/lib/galaxy/web/controllers/tracks.py
@@ -14,9 +14,9 @@
from galaxy.util.bunch import Bunch
from galaxy.datatypes.interval import Gff, Bed
from galaxy.model import NoConverterException, ConverterDependencyException
-from galaxy.visualization.tracks.data_providers import *
+from galaxy.visualization.genome.data_providers import *
from galaxy.visualization.genomes import decode_dbkey, Genomes
-from galaxy.visualization.tracks.visual_analytics import get_dataset_job
+from galaxy.visualization.genome.visual_analytics import get_dataset_job
class NameColumn( grids.TextColumn ):
https://bitbucket.org/galaxy/galaxy-central/changeset/40f6d9738623/
changeset: 40f6d9738623
user: jgoecks
date: 2012-09-14 18:35:20
summary: Begin process of migrating Phyloviz data provider to data provider framework.
affected #: 2 files
diff -r 6805c477d61601ad304577ad6603dab71b22df24 -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
--- a/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
+++ b/lib/galaxy/visualization/phyloviz/phyloviz_dataprovider.py
@@ -1,13 +1,17 @@
from newickparser import Newick_Parser
from nexusparser import Nexus_Parser
from phyloxmlparser import Phyloxml_Parser
+from galaxy.visualization.data_providers import BaseDataProvider
-class Phyloviz_DataProvider(object):
+# TODO: bring this class into line with BaseDataProvider by
+# using BaseDataProvider.init() and providing original dataset
+# and then reading from dataset rather than filepath.
+class Phyloviz_DataProvider( BaseDataProvider ):
- def __init__(self):
+ def __init__( self ):
pass
- def parseFile(self, filepath, fileExt):
+ def get_data( self, filepath, fileExt ):
"""returns [trees], meta
Trees are actually an array of JsonDicts. It's usually one tree, except in the case of Nexus
"""
diff -r 6805c477d61601ad304577ad6603dab71b22df24 -r 40f6d9738623ee2b2c7ff1f5a82fe09c7628d766 lib/galaxy/web/controllers/phyloviz.py
--- a/lib/galaxy/web/controllers/phyloviz.py
+++ b/lib/galaxy/web/controllers/phyloviz.py
@@ -84,7 +84,7 @@
else:
try:
pd = Phyloviz_DataProvider()
- json, config = pd.parseFile(filepath, fileExt)
+ json, config = pd.get_data(filepath, fileExt)
json = json[treeIndex]
except Exception:
pass
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