galaxy-commits
Threads by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ea4f983c227e/
Changeset: ea4f983c227e
User: jmchilton
Date: 2014-08-05 03:45:02
Summary: API tests for authenticate and some of users endpoints.
Affected #: 4 files
diff -r d4070ec86d404eec61f78a60f23536080b04ab1f -r ea4f983c227e4cac4b331699e8b7a87f9383df06 test/api/test_authenticate.py
--- /dev/null
+++ b/test/api/test_authenticate.py
@@ -0,0 +1,29 @@
+import base64
+
+from base.interactor import get_request
+from base import api
+
+
+TEST_USER_EMAIL = "auth_user_test(a)bx.psu.edu"
+TEST_USER_PASSWORD = "testpassword1"
+
+
+class AuthenticationApiTestCase( api.ApiTestCase ):
+
+ def test_auth( self ):
+ self._setup_user( TEST_USER_EMAIL, TEST_USER_PASSWORD )
+ baseauth_url = self._api_url( "authenticate/baseauth", use_key=False )
+ unencoded_credentials = "%s:%s" % ( TEST_USER_EMAIL, TEST_USER_PASSWORD )
+ authorization = base64.b64encode(unencoded_credentials)
+ headers = {
+ "Authorization": authorization,
+ }
+ auth_response = get_request( baseauth_url, headers=headers )
+ self._assert_status_code_is( auth_response, 200 )
+ auth_dict = auth_response.json()
+ self._assert_has_keys( auth_dict, "api_key" )
+
+ # Verify key...
+ random_api_url = self._api_url( "users", use_key=False )
+ random_api_response = get_request( random_api_url, params=dict( key=auth_dict[ "api_key" ] ) )
+ self._assert_status_code_is( random_api_response, 200 )
diff -r d4070ec86d404eec61f78a60f23536080b04ab1f -r ea4f983c227e4cac4b331699e8b7a87f9383df06 test/api/test_users.py
--- /dev/null
+++ b/test/api/test_users.py
@@ -0,0 +1,24 @@
+from base import api
+
+TEST_USER_EMAIL = "user_for_users_index_test(a)bx.psu.edu"
+
+
+class UsersApiTestCase( api.ApiTestCase ):
+
+ def test_index( self ):
+ self._setup_user( TEST_USER_EMAIL )
+ all_users_response = self._get( "users", admin=True )
+ self._assert_status_code_is( all_users_response, 200 )
+ all_users = all_users_response.json()
+ # New user is in list
+ assert len( [ u for u in all_users if u[ "email" ] == TEST_USER_EMAIL ] ) == 1
+ # Request made from admin user, so should at least self and this
+ # new user.
+ assert len( all_users ) > 1
+
+ def test_index_only_self_for_nonadmins( self ):
+ self._setup_user( TEST_USER_EMAIL )
+ with self._different_user( ):
+ all_users_response = self._get( "users" )
+ # Non admin users can only see themselves
+ assert len( all_users_response.json() ) == 1
diff -r d4070ec86d404eec61f78a60f23536080b04ab1f -r ea4f983c227e4cac4b331699e8b7a87f9383df06 test/base/api.py
--- a/test/base/api.py
+++ b/test/base/api.py
@@ -41,8 +41,8 @@
url = "%s?%s" % ( url, query )
return url
- def _setup_user( self, email ):
- self.galaxy_interactor.ensure_user_with_email(email)
+ def _setup_user( self, email, password=None ):
+ self.galaxy_interactor.ensure_user_with_email( email, password=password )
users = self._get( "users", admin=True ).json()
user = [ user for user in users if user["email"] == email ][0]
return user
diff -r d4070ec86d404eec61f78a60f23536080b04ab1f -r ea4f983c227e4cac4b331699e8b7a87f9383df06 test/base/interactor.py
--- a/test/base/interactor.py
+++ b/test/base/interactor.py
@@ -325,16 +325,17 @@
)
return self._post( "tools", files=files, data=data )
- def ensure_user_with_email( self, email ):
+ def ensure_user_with_email( self, email, password=None ):
admin_key = self.master_api_key
all_users = self._get( 'users', key=admin_key ).json()
try:
test_user = [ user for user in all_users if user["email"] == email ][0]
except IndexError:
username = re.sub('[^a-z-]', '--', email.lower())
+ password = password or 'testpass'
data = dict(
email=email,
- password='testuser',
+ password=password,
username=username,
)
test_user = self._post( 'users', data, key=admin_key ).json()
https://bitbucket.org/galaxy/galaxy-central/commits/a714f168aa7d/
Changeset: a714f168aa7d
User: jmchilton
Date: 2014-08-05 03:45:02
Summary: Introduce ApiKeyManager to replace and expand upon CreatedApiKeysMixin.
Affected #: 3 files
diff -r ea4f983c227e4cac4b331699e8b7a87f9383df06 -r a714f168aa7ddb1dfd3142f49869992cd325456c lib/galaxy/managers/api_keys.py
--- /dev/null
+++ b/lib/galaxy/managers/api_keys.py
@@ -0,0 +1,26 @@
+
+
+class ApiKeyManager( object ):
+
+ def __init__( self, app ):
+ self.app = app
+
+ def create_api_key( self, user ):
+ guid = self.app.security.get_new_guid()
+ new_key = self.app.model.APIKeys()
+ new_key.user_id = user.id
+ new_key.key = guid
+ sa_session = self.app.model.context
+ sa_session.add( new_key )
+ sa_session.flush()
+ return guid
+
+ def get_or_create_api_key( self, user ):
+ # Logic Galaxy has always used - but it would appear to have a race
+ # condition. Worth fixing? Would kind of need a message queue to fix
+ # in multiple process mode.
+ if user.api_keys:
+ key = user.api_keys[0].key
+ else:
+ key = self.create_api_key( user )
+ return key
diff -r ea4f983c227e4cac4b331699e8b7a87f9383df06 -r a714f168aa7ddb1dfd3142f49869992cd325456c lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -37,6 +37,7 @@
from galaxy.model import ExtendedMetadata, ExtendedMetadataIndex, LibraryDatasetDatasetAssociation, HistoryDatasetAssociation
+from galaxy.managers import api_keys
from galaxy.datatypes.metadata import FileParameter
from galaxy.tools.parameters import RuntimeValue, visit_input_values
from galaxy.tools.parameters.basic import DataToolParameter
@@ -286,16 +287,12 @@
class CreatesApiKeysMixin:
"""
Mixing centralizing logic for creating API keys for user objects.
+
+ Deprecated - please use api_keys.ApiKeyManager for new development.
"""
def create_api_key( self, trans, user ):
- guid = trans.app.security.get_new_guid()
- new_key = trans.app.model.APIKeys()
- new_key.user_id = user.id
- new_key.key = guid
- trans.sa_session.add( new_key )
- trans.sa_session.flush()
- return guid
+ return api_keys.ApiKeyManager( trans.app ).create_api_key( user )
class SharableItemSecurityMixin:
diff -r ea4f983c227e4cac4b331699e8b7a87f9383df06 -r a714f168aa7ddb1dfd3142f49869992cd325456c lib/galaxy/webapps/galaxy/api/authenticate.py
--- a/lib/galaxy/webapps/galaxy/api/authenticate.py
+++ b/lib/galaxy/webapps/galaxy/api/authenticate.py
@@ -15,14 +15,19 @@
from urllib import unquote
from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
+from galaxy.managers import api_keys
from galaxy import exceptions
-from galaxy.web.base.controller import BaseAPIController, CreatesApiKeysMixin
+from galaxy.web.base.controller import BaseAPIController
import logging
log = logging.getLogger( __name__ )
-class AuthenticationController( BaseAPIController, CreatesApiKeysMixin ):
+class AuthenticationController( BaseAPIController ):
+
+ def __init__( self, app ):
+ super( AuthenticationController, self ).__init__( app )
+ self.api_keys_manager = api_keys.ApiKeyManager( app )
@expose_api_anonymous
def get_api_key( self, trans, **kwd ):
@@ -47,10 +52,7 @@
user = user[0]
is_valid_user = user.check_password( password )
if ( is_valid_user ):
- if user.api_keys:
- key = user.api_keys[0].key
- else:
- key = self.create_api_key( trans, user )
+ key = self.api_keys_manager.get_or_create_api_key( user )
return dict( api_key=key )
else:
raise exceptions.AuthenticationFailed()
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
04 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d4070ec86d40/
Changeset: d4070ec86d40
User: jmchilton
Date: 2014-08-04 21:02:01
Summary: Merge next-stable.
Affected #: 6 files
diff -r cd82587fb36ecbc802931edad29372f69cee7108 -r d4070ec86d404eec61f78a60f23536080b04ab1f lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -69,7 +69,7 @@
from galaxy.model import Workflow
from tool_shed.util import common_util
from tool_shed.util import shed_util_common as suc
-from .loader import load_tool, template_macro_params
+from .loader import load_tool, template_macro_params, raw_tool_xml_tree, imported_macro_paths
from .execute import execute as execute_job
from .wrappers import (
ToolParameterValueWrapper,
@@ -2989,6 +2989,23 @@
def get_default_history_by_trans( self, trans, create=False ):
return trans.get_history( create=create )
+ @classmethod
+ def get_externally_referenced_paths( self, path ):
+ """ Return relative paths to externally referenced files by the tool
+ described by file at `path`. External components should not assume things
+ about the structure of tool xml files (this is the tool's responsibility).
+ """
+ tree = raw_tool_xml_tree(path)
+ root = tree.getroot()
+ external_paths = []
+ for code_elem in root.findall( 'code' ):
+ external_path = code_elem.get( 'file' )
+ if external_path:
+ external_paths.append( external_path )
+ external_paths.extend( imported_macro_paths( root ) )
+ # May also need to load external citation files as well at some point.
+ return external_paths
+
class OutputParameterJSONTool( Tool ):
"""
diff -r cd82587fb36ecbc802931edad29372f69cee7108 -r d4070ec86d404eec61f78a60f23536080b04ab1f lib/galaxy/tools/loader.py
--- a/lib/galaxy/tools/loader.py
+++ b/lib/galaxy/tools/loader.py
@@ -10,7 +10,7 @@
"""
Loads tool from file system and preprocesses tool macros.
"""
- tree = parse_xml(path)
+ tree = raw_tool_xml_tree(path)
root = tree.getroot()
_import_macros(root, path)
@@ -38,14 +38,31 @@
return param_dict
+def raw_tool_xml_tree(path):
+ """ Load raw (no macro expansion) tree representation of tool represented
+ at the specified path.
+ """
+ tree = parse_xml(path)
+ return tree
+
+
+def imported_macro_paths(root):
+ macros_el = _macros_el(root)
+ return _imported_macro_paths_from_el(macros_el)
+
+
def _import_macros(root, path):
tool_dir = os.path.dirname(path)
- macros_el = root.find('macros')
+ macros_el = _macros_el(root)
if macros_el:
macro_els = _load_macros(macros_el, tool_dir)
_xml_set_children(macros_el, macro_els)
+def _macros_el(root):
+ return root.find('macros')
+
+
def _macros_of_type(root, type, el_func):
macros_el = root.find('macros')
macro_dict = {}
@@ -159,6 +176,17 @@
def _load_imported_macros(macros_el, tool_dir):
macros = []
+ for tool_relative_import_path in _imported_macro_paths_from_el(macros_el):
+ import_path = \
+ os.path.join(tool_dir, tool_relative_import_path)
+ file_macros = _load_macro_file(import_path, tool_dir)
+ macros.extend(file_macros)
+
+ return macros
+
+
+def _imported_macro_paths_from_el(macros_el):
+ imported_macro_paths = []
macro_import_els = []
if macros_el:
macro_import_els = macros_el.findall("import")
@@ -166,12 +194,8 @@
raw_import_path = macro_import_el.text
tool_relative_import_path = \
os.path.basename(raw_import_path) # Sanitize this
- import_path = \
- os.path.join(tool_dir, tool_relative_import_path)
- file_macros = _load_macro_file(import_path, tool_dir)
- macros.extend(file_macros)
-
- return macros
+ imported_macro_paths.append( tool_relative_import_path )
+ return imported_macro_paths
def _load_macro_file(path, tool_dir):
diff -r cd82587fb36ecbc802931edad29372f69cee7108 -r d4070ec86d404eec61f78a60f23536080b04ab1f lib/tool_shed/tools/tool_validator.py
--- a/lib/tool_shed/tools/tool_validator.py
+++ b/lib/tool_shed/tools/tool_validator.py
@@ -3,6 +3,7 @@
import os
import tempfile
+from galaxy.tools import Tool
from galaxy.tools import parameters
from galaxy.tools.parameters import dynamic_options
@@ -311,15 +312,14 @@
message = ''
tmp_tool_config = hg_util.get_named_tmpfile_from_ctx( ctx, ctx_file, work_dir )
if tmp_tool_config:
- element_tree, error_message = xml_util.parse_xml( tmp_tool_config )
- if element_tree is None:
+ tool_element, error_message = xml_util.parse_xml( tmp_tool_config )
+ if tool_element is None:
return tool, message
- element_tree_root = element_tree.getroot()
- # Look for code files required by the tool config.
+ # Look for external files required by the tool config.
tmp_code_files = []
- for code_elem in element_tree_root.findall( 'code' ):
- code_file_name = code_elem.get( 'file' )
- tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, code_file_name, work_dir )
+ external_paths = Tool.get_externally_referenced_paths( tmp_tool_config )
+ for path in external_paths:
+ tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, path, work_dir )
if tmp_code_file_name:
tmp_code_files.append( tmp_code_file_name )
tool, valid, message = self.load_tool_from_config( repository_id, tmp_tool_config )
diff -r cd82587fb36ecbc802931edad29372f69cee7108 -r d4070ec86d404eec61f78a60f23536080b04ab1f static/scripts/packed/viz/trackster/painters.js
--- a/static/scripts/packed/viz/trackster/painters.js
+++ b/static/scripts/packed/viz/trackster/painters.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(_){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 DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};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 LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};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 painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.round((data[i][0]-view_start)*w_scale);y=data[i][1];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=painter_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());this.max_label_length=200};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)},get_top_padding:function(width){return 0},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,incomplete_features=[];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((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){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]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){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],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(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_start+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_start+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_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(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_start,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-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(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_start+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_start+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_start)}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_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+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_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);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,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.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},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}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];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,y_start+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_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")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+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_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}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.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,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_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end,y_start+5,b2_start,y_start+5)}}else{this.draw_read(ctx,mode,w_scale,y_start,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;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}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_start){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_start,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{if(rgb.length==7){this.rgb=rgb.substring(1,7).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:"#FF8C00",neg_color:"#4169E1"};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()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
+define(["libs/underscore"],function(_){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 DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};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 LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};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 painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];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=painter_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());this.max_label_length=200};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)},get_top_padding:function(width){return 0},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,incomplete_features=[];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((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){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]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){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],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(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_start+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_start+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_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(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_start,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-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(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_start+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_start+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_start)}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_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+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_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);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,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.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},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}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];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,y_start+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_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")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+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_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}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.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,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_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end,y_start+5,b2_start,y_start+5)}}else{this.draw_read(ctx,mode,w_scale,y_start,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;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}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_start){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_start,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{if(rgb.length==7){this.rgb=rgb.substring(1,7).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:"#FF8C00",neg_color:"#4169E1"};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()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
diff -r cd82587fb36ecbc802931edad29372f69cee7108 -r d4070ec86d404eec61f78a60f23536080b04ab1f static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -196,7 +196,7 @@
ctx.fillStyle = ctx.strokeStyle = painter_color;
top_overflow = bot_overflow = false;
- x_scaled = Math.round((data[i][0] - view_start) * w_scale);
+ x_scaled = Math.ceil((data[i][0] - view_start) * w_scale);
y = data[i][1];
// Process Y (scaler) value.
diff -r cd82587fb36ecbc802931edad29372f69cee7108 -r d4070ec86d404eec61f78a60f23536080b04ab1f test/unit/tools/test_tool_external_files.py
--- /dev/null
+++ b/test/unit/tools/test_tool_external_files.py
@@ -0,0 +1,30 @@
+""" Unit test logic related to finding externally referenced files in tool
+descriptions.
+"""
+import tempfile
+import os
+import shutil
+from galaxy.tools import Tool
+
+
+def test_finds_external_code_file():
+ assert __external_files("""<tool><code file="foo.py" /></tool>""") == ["foo.py"]
+
+
+def test_finds_skips_empty_code_file_attribute():
+ assert __external_files("""<tool><code /></tool>""") == []
+
+
+def test_finds_external_macro_file():
+ assert __external_files("""<tool><macros><import>cool_macros.xml</import></macros></tool>""") == ["cool_macros.xml"]
+
+
+def __external_files(contents):
+ base_path = tempfile.mkdtemp()
+ try:
+ tool_path = os.path.join(base_path, "tool.xml")
+ with open(tool_path, "w") as f:
+ f.write(contents)
+ return Tool.get_externally_referenced_paths(tool_path)
+ finally:
+ shutil.rmtree(base_path)
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: jmchilton: Merged in jmchilton/galaxy-central-fork-1/next-stable (pull request #449)
by commits-noreply@bitbucket.org 04 Aug '14
by commits-noreply@bitbucket.org 04 Aug '14
04 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7cacfb33db90/
Changeset: 7cacfb33db90
Branch: next-stable
User: jmchilton
Date: 2014-08-04 20:57:31
Summary: Merged in jmchilton/galaxy-central-fork-1/next-stable (pull request #449)
Fix tool shed's logic related to finding tool externally referenced files.
Affected #: 4 files
diff -r 7ac5a36c0ce7a6eb280d339de2107740552825ce -r 7cacfb33db90dee8c4e9ce78a3a735cd6cef8490 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -69,7 +69,7 @@
from galaxy.model import Workflow
from tool_shed.util import common_util
from tool_shed.util import shed_util_common as suc
-from .loader import load_tool, template_macro_params
+from .loader import load_tool, template_macro_params, raw_tool_xml_tree, imported_macro_paths
from .execute import execute as execute_job
from .wrappers import (
ToolParameterValueWrapper,
@@ -2989,6 +2989,23 @@
def get_default_history_by_trans( self, trans, create=False ):
return trans.get_history( create=create )
+ @classmethod
+ def get_externally_referenced_paths( self, path ):
+ """ Return relative paths to externally referenced files by the tool
+ described by file at `path`. External components should not assume things
+ about the structure of tool xml files (this is the tool's responsibility).
+ """
+ tree = raw_tool_xml_tree(path)
+ root = tree.getroot()
+ external_paths = []
+ for code_elem in root.findall( 'code' ):
+ external_path = code_elem.get( 'file' )
+ if external_path:
+ external_paths.append( external_path )
+ external_paths.extend( imported_macro_paths( root ) )
+ # May also need to load external citation files as well at some point.
+ return external_paths
+
class OutputParameterJSONTool( Tool ):
"""
diff -r 7ac5a36c0ce7a6eb280d339de2107740552825ce -r 7cacfb33db90dee8c4e9ce78a3a735cd6cef8490 lib/galaxy/tools/loader.py
--- a/lib/galaxy/tools/loader.py
+++ b/lib/galaxy/tools/loader.py
@@ -10,7 +10,7 @@
"""
Loads tool from file system and preprocesses tool macros.
"""
- tree = parse_xml(path)
+ tree = raw_tool_xml_tree(path)
root = tree.getroot()
_import_macros(root, path)
@@ -38,14 +38,31 @@
return param_dict
+def raw_tool_xml_tree(path):
+ """ Load raw (no macro expansion) tree representation of tool represented
+ at the specified path.
+ """
+ tree = parse_xml(path)
+ return tree
+
+
+def imported_macro_paths(root):
+ macros_el = _macros_el(root)
+ return _imported_macro_paths_from_el(macros_el)
+
+
def _import_macros(root, path):
tool_dir = os.path.dirname(path)
- macros_el = root.find('macros')
+ macros_el = _macros_el(root)
if macros_el:
macro_els = _load_macros(macros_el, tool_dir)
_xml_set_children(macros_el, macro_els)
+def _macros_el(root):
+ return root.find('macros')
+
+
def _macros_of_type(root, type, el_func):
macros_el = root.find('macros')
macro_dict = {}
@@ -159,6 +176,17 @@
def _load_imported_macros(macros_el, tool_dir):
macros = []
+ for tool_relative_import_path in _imported_macro_paths_from_el(macros_el):
+ import_path = \
+ os.path.join(tool_dir, tool_relative_import_path)
+ file_macros = _load_macro_file(import_path, tool_dir)
+ macros.extend(file_macros)
+
+ return macros
+
+
+def _imported_macro_paths_from_el(macros_el):
+ imported_macro_paths = []
macro_import_els = []
if macros_el:
macro_import_els = macros_el.findall("import")
@@ -166,12 +194,8 @@
raw_import_path = macro_import_el.text
tool_relative_import_path = \
os.path.basename(raw_import_path) # Sanitize this
- import_path = \
- os.path.join(tool_dir, tool_relative_import_path)
- file_macros = _load_macro_file(import_path, tool_dir)
- macros.extend(file_macros)
-
- return macros
+ imported_macro_paths.append( tool_relative_import_path )
+ return imported_macro_paths
def _load_macro_file(path, tool_dir):
diff -r 7ac5a36c0ce7a6eb280d339de2107740552825ce -r 7cacfb33db90dee8c4e9ce78a3a735cd6cef8490 lib/tool_shed/tools/tool_validator.py
--- a/lib/tool_shed/tools/tool_validator.py
+++ b/lib/tool_shed/tools/tool_validator.py
@@ -3,6 +3,7 @@
import os
import tempfile
+from galaxy.tools import Tool
from galaxy.tools import parameters
from galaxy.tools.parameters import dynamic_options
@@ -311,15 +312,14 @@
message = ''
tmp_tool_config = hg_util.get_named_tmpfile_from_ctx( ctx, ctx_file, work_dir )
if tmp_tool_config:
- element_tree, error_message = xml_util.parse_xml( tmp_tool_config )
- if element_tree is None:
+ tool_element, error_message = xml_util.parse_xml( tmp_tool_config )
+ if tool_element is None:
return tool, message
- element_tree_root = element_tree.getroot()
- # Look for code files required by the tool config.
+ # Look for external files required by the tool config.
tmp_code_files = []
- for code_elem in element_tree_root.findall( 'code' ):
- code_file_name = code_elem.get( 'file' )
- tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, code_file_name, work_dir )
+ external_paths = Tool.get_externally_referenced_paths( tmp_tool_config )
+ for path in external_paths:
+ tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, path, work_dir )
if tmp_code_file_name:
tmp_code_files.append( tmp_code_file_name )
tool, valid, message = self.load_tool_from_config( repository_id, tmp_tool_config )
diff -r 7ac5a36c0ce7a6eb280d339de2107740552825ce -r 7cacfb33db90dee8c4e9ce78a3a735cd6cef8490 test/unit/tools/test_tool_external_files.py
--- /dev/null
+++ b/test/unit/tools/test_tool_external_files.py
@@ -0,0 +1,30 @@
+""" Unit test logic related to finding externally referenced files in tool
+descriptions.
+"""
+import tempfile
+import os
+import shutil
+from galaxy.tools import Tool
+
+
+def test_finds_external_code_file():
+ assert __external_files("""<tool><code file="foo.py" /></tool>""") == ["foo.py"]
+
+
+def test_finds_skips_empty_code_file_attribute():
+ assert __external_files("""<tool><code /></tool>""") == []
+
+
+def test_finds_external_macro_file():
+ assert __external_files("""<tool><macros><import>cool_macros.xml</import></macros></tool>""") == ["cool_macros.xml"]
+
+
+def __external_files(contents):
+ base_path = tempfile.mkdtemp()
+ try:
+ tool_path = os.path.join(base_path, "tool.xml")
+ with open(tool_path, "w") as f:
+ f.write(contents)
+ return Tool.get_externally_referenced_paths(tool_path)
+ finally:
+ shutil.rmtree(base_path)
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e90ee102ac65/
Changeset: e90ee102ac65
Branch: next-stable
User: jmchilton
Date: 2014-08-04 18:18:00
Summary: Restructure tool external file logic in load_tool_from_tmp_config in ToolValidator...
... so internals of tool XML description are only utilized in the galaxy.tools module (and submodules). Add some unit tests for this new method for finding externally referenced files.
Affected #: 4 files
diff -r 2438770e2cfbf804acc0d5c7b2f3d6e491f30695 -r e90ee102ac654cc88bc3cf156aa1319008412846 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -69,7 +69,7 @@
from galaxy.model import Workflow
from tool_shed.util import common_util
from tool_shed.util import shed_util_common as suc
-from .loader import load_tool, template_macro_params
+from .loader import load_tool, template_macro_params, raw_tool_xml_tree
from .execute import execute as execute_job
from .wrappers import (
ToolParameterValueWrapper,
@@ -2989,6 +2989,21 @@
def get_default_history_by_trans( self, trans, create=False ):
return trans.get_history( create=create )
+ @classmethod
+ def get_externally_referenced_paths( self, path ):
+ """ Return relative paths to externally referenced files by the tool
+ described by file at `path`. External components should not assume things
+ about the structure of tool xml files (this is the tool's responsibility).
+ """
+ tree = raw_tool_xml_tree(path)
+ root = tree.getroot()
+ external_paths = []
+ for code_elem in root.findall( 'code' ):
+ external_path = code_elem.get( 'file' )
+ if external_path:
+ external_paths.append( external_path )
+ return external_paths
+
class OutputParameterJSONTool( Tool ):
"""
diff -r 2438770e2cfbf804acc0d5c7b2f3d6e491f30695 -r e90ee102ac654cc88bc3cf156aa1319008412846 lib/galaxy/tools/loader.py
--- a/lib/galaxy/tools/loader.py
+++ b/lib/galaxy/tools/loader.py
@@ -10,7 +10,7 @@
"""
Loads tool from file system and preprocesses tool macros.
"""
- tree = parse_xml(path)
+ tree = raw_tool_xml_tree(path)
root = tree.getroot()
_import_macros(root, path)
@@ -38,6 +38,14 @@
return param_dict
+def raw_tool_xml_tree(path):
+ """ Load raw (no macro expansion) tree representation of tool represented
+ at the specified path.
+ """
+ tree = parse_xml(path)
+ return tree
+
+
def _import_macros(root, path):
tool_dir = os.path.dirname(path)
macros_el = root.find('macros')
diff -r 2438770e2cfbf804acc0d5c7b2f3d6e491f30695 -r e90ee102ac654cc88bc3cf156aa1319008412846 lib/tool_shed/tools/tool_validator.py
--- a/lib/tool_shed/tools/tool_validator.py
+++ b/lib/tool_shed/tools/tool_validator.py
@@ -3,6 +3,7 @@
import os
import tempfile
+from galaxy.tools import Tool
from galaxy.tools import parameters
from galaxy.tools.parameters import dynamic_options
@@ -311,15 +312,14 @@
message = ''
tmp_tool_config = hg_util.get_named_tmpfile_from_ctx( ctx, ctx_file, work_dir )
if tmp_tool_config:
- element_tree, error_message = xml_util.parse_xml( tmp_tool_config )
- if element_tree is None:
+ tool_element, error_message = xml_util.parse_xml( tmp_tool_config )
+ if tool_element is None:
return tool, message
- element_tree_root = element_tree.getroot()
- # Look for code files required by the tool config.
+ # Look for external files required by the tool config.
tmp_code_files = []
- for code_elem in element_tree_root.findall( 'code' ):
- code_file_name = code_elem.get( 'file' )
- tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, code_file_name, work_dir )
+ external_paths = Tool.get_externally_referenced_paths( tmp_tool_config )
+ for path in external_paths:
+ tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, path, work_dir )
if tmp_code_file_name:
tmp_code_files.append( tmp_code_file_name )
tool, valid, message = self.load_tool_from_config( repository_id, tmp_tool_config )
diff -r 2438770e2cfbf804acc0d5c7b2f3d6e491f30695 -r e90ee102ac654cc88bc3cf156aa1319008412846 test/unit/tools/test_tool_external_files.py
--- /dev/null
+++ b/test/unit/tools/test_tool_external_files.py
@@ -0,0 +1,26 @@
+""" Unit test logic related to finding externally referenced files in tool
+descriptions.
+"""
+import tempfile
+import os
+import shutil
+from galaxy.tools import Tool
+
+
+def test_finds_external_code_file():
+ assert __external_files("""<tool><code file="foo.py" /></tool>""") == ["foo.py"]
+
+
+def test_finds_skips_empty_code_file_attribute():
+ assert __external_files("""<tool><code /></tool>""") == []
+
+
+def __external_files(contents):
+ base_path = tempfile.mkdtemp()
+ try:
+ tool_path = os.path.join(base_path, "tool.xml")
+ with open(tool_path, "w") as f:
+ f.write(contents)
+ return Tool.get_externally_referenced_paths(tool_path)
+ finally:
+ shutil.rmtree(base_path)
https://bitbucket.org/galaxy/galaxy-central/commits/d026577e04ac/
Changeset: d026577e04ac
Branch: next-stable
User: jmchilton
Date: 2014-08-04 18:18:00
Summary: Fix new Tool.get_externally_referenced_paths to find imported macro files.
Should fix this bug https://trello.com/c/TeguDYSq discovered by Bjoern... on stage at the GCC.
Affected #: 3 files
diff -r e90ee102ac654cc88bc3cf156aa1319008412846 -r d026577e04ac9802249aeecb64d14292bf59e20d lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -69,7 +69,7 @@
from galaxy.model import Workflow
from tool_shed.util import common_util
from tool_shed.util import shed_util_common as suc
-from .loader import load_tool, template_macro_params, raw_tool_xml_tree
+from .loader import load_tool, template_macro_params, raw_tool_xml_tree, imported_macro_paths
from .execute import execute as execute_job
from .wrappers import (
ToolParameterValueWrapper,
@@ -3002,6 +3002,8 @@
external_path = code_elem.get( 'file' )
if external_path:
external_paths.append( external_path )
+ external_paths.extend( imported_macro_paths( root ) )
+ # May also need to load external citation files as well at some point.
return external_paths
diff -r e90ee102ac654cc88bc3cf156aa1319008412846 -r d026577e04ac9802249aeecb64d14292bf59e20d lib/galaxy/tools/loader.py
--- a/lib/galaxy/tools/loader.py
+++ b/lib/galaxy/tools/loader.py
@@ -46,14 +46,23 @@
return tree
+def imported_macro_paths(root):
+ macros_el = _macros_el(root)
+ return _imported_macro_paths_from_el(macros_el)
+
+
def _import_macros(root, path):
tool_dir = os.path.dirname(path)
- macros_el = root.find('macros')
+ macros_el = _macros_el(root)
if macros_el:
macro_els = _load_macros(macros_el, tool_dir)
_xml_set_children(macros_el, macro_els)
+def _macros_el(root):
+ return root.find('macros')
+
+
def _macros_of_type(root, type, el_func):
macros_el = root.find('macros')
macro_dict = {}
@@ -167,6 +176,17 @@
def _load_imported_macros(macros_el, tool_dir):
macros = []
+ for tool_relative_import_path in _imported_macro_paths_from_el(macros_el):
+ import_path = \
+ os.path.join(tool_dir, tool_relative_import_path)
+ file_macros = _load_macro_file(import_path, tool_dir)
+ macros.extend(file_macros)
+
+ return macros
+
+
+def _imported_macro_paths_from_el(macros_el):
+ imported_macro_paths = []
macro_import_els = []
if macros_el:
macro_import_els = macros_el.findall("import")
@@ -174,12 +194,8 @@
raw_import_path = macro_import_el.text
tool_relative_import_path = \
os.path.basename(raw_import_path) # Sanitize this
- import_path = \
- os.path.join(tool_dir, tool_relative_import_path)
- file_macros = _load_macro_file(import_path, tool_dir)
- macros.extend(file_macros)
-
- return macros
+ imported_macro_paths.append( tool_relative_import_path )
+ return imported_macro_paths
def _load_macro_file(path, tool_dir):
diff -r e90ee102ac654cc88bc3cf156aa1319008412846 -r d026577e04ac9802249aeecb64d14292bf59e20d test/unit/tools/test_tool_external_files.py
--- a/test/unit/tools/test_tool_external_files.py
+++ b/test/unit/tools/test_tool_external_files.py
@@ -15,6 +15,10 @@
assert __external_files("""<tool><code /></tool>""") == []
+def test_finds_external_macro_file():
+ assert __external_files("""<tool><macros><import>cool_macros.xml</import></macros></tool>""") == ["cool_macros.xml"]
+
+
def __external_files(contents):
base_path = tempfile.mkdtemp()
try:
https://bitbucket.org/galaxy/galaxy-central/commits/7cacfb33db90/
Changeset: 7cacfb33db90
Branch: next-stable
User: jmchilton
Date: 2014-08-04 20:57:31
Summary: Merged in jmchilton/galaxy-central-fork-1/next-stable (pull request #449)
Fix tool shed's logic related to finding tool externally referenced files.
Affected #: 4 files
diff -r 7ac5a36c0ce7a6eb280d339de2107740552825ce -r 7cacfb33db90dee8c4e9ce78a3a735cd6cef8490 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -69,7 +69,7 @@
from galaxy.model import Workflow
from tool_shed.util import common_util
from tool_shed.util import shed_util_common as suc
-from .loader import load_tool, template_macro_params
+from .loader import load_tool, template_macro_params, raw_tool_xml_tree, imported_macro_paths
from .execute import execute as execute_job
from .wrappers import (
ToolParameterValueWrapper,
@@ -2989,6 +2989,23 @@
def get_default_history_by_trans( self, trans, create=False ):
return trans.get_history( create=create )
+ @classmethod
+ def get_externally_referenced_paths( self, path ):
+ """ Return relative paths to externally referenced files by the tool
+ described by file at `path`. External components should not assume things
+ about the structure of tool xml files (this is the tool's responsibility).
+ """
+ tree = raw_tool_xml_tree(path)
+ root = tree.getroot()
+ external_paths = []
+ for code_elem in root.findall( 'code' ):
+ external_path = code_elem.get( 'file' )
+ if external_path:
+ external_paths.append( external_path )
+ external_paths.extend( imported_macro_paths( root ) )
+ # May also need to load external citation files as well at some point.
+ return external_paths
+
class OutputParameterJSONTool( Tool ):
"""
diff -r 7ac5a36c0ce7a6eb280d339de2107740552825ce -r 7cacfb33db90dee8c4e9ce78a3a735cd6cef8490 lib/galaxy/tools/loader.py
--- a/lib/galaxy/tools/loader.py
+++ b/lib/galaxy/tools/loader.py
@@ -10,7 +10,7 @@
"""
Loads tool from file system and preprocesses tool macros.
"""
- tree = parse_xml(path)
+ tree = raw_tool_xml_tree(path)
root = tree.getroot()
_import_macros(root, path)
@@ -38,14 +38,31 @@
return param_dict
+def raw_tool_xml_tree(path):
+ """ Load raw (no macro expansion) tree representation of tool represented
+ at the specified path.
+ """
+ tree = parse_xml(path)
+ return tree
+
+
+def imported_macro_paths(root):
+ macros_el = _macros_el(root)
+ return _imported_macro_paths_from_el(macros_el)
+
+
def _import_macros(root, path):
tool_dir = os.path.dirname(path)
- macros_el = root.find('macros')
+ macros_el = _macros_el(root)
if macros_el:
macro_els = _load_macros(macros_el, tool_dir)
_xml_set_children(macros_el, macro_els)
+def _macros_el(root):
+ return root.find('macros')
+
+
def _macros_of_type(root, type, el_func):
macros_el = root.find('macros')
macro_dict = {}
@@ -159,6 +176,17 @@
def _load_imported_macros(macros_el, tool_dir):
macros = []
+ for tool_relative_import_path in _imported_macro_paths_from_el(macros_el):
+ import_path = \
+ os.path.join(tool_dir, tool_relative_import_path)
+ file_macros = _load_macro_file(import_path, tool_dir)
+ macros.extend(file_macros)
+
+ return macros
+
+
+def _imported_macro_paths_from_el(macros_el):
+ imported_macro_paths = []
macro_import_els = []
if macros_el:
macro_import_els = macros_el.findall("import")
@@ -166,12 +194,8 @@
raw_import_path = macro_import_el.text
tool_relative_import_path = \
os.path.basename(raw_import_path) # Sanitize this
- import_path = \
- os.path.join(tool_dir, tool_relative_import_path)
- file_macros = _load_macro_file(import_path, tool_dir)
- macros.extend(file_macros)
-
- return macros
+ imported_macro_paths.append( tool_relative_import_path )
+ return imported_macro_paths
def _load_macro_file(path, tool_dir):
diff -r 7ac5a36c0ce7a6eb280d339de2107740552825ce -r 7cacfb33db90dee8c4e9ce78a3a735cd6cef8490 lib/tool_shed/tools/tool_validator.py
--- a/lib/tool_shed/tools/tool_validator.py
+++ b/lib/tool_shed/tools/tool_validator.py
@@ -3,6 +3,7 @@
import os
import tempfile
+from galaxy.tools import Tool
from galaxy.tools import parameters
from galaxy.tools.parameters import dynamic_options
@@ -311,15 +312,14 @@
message = ''
tmp_tool_config = hg_util.get_named_tmpfile_from_ctx( ctx, ctx_file, work_dir )
if tmp_tool_config:
- element_tree, error_message = xml_util.parse_xml( tmp_tool_config )
- if element_tree is None:
+ tool_element, error_message = xml_util.parse_xml( tmp_tool_config )
+ if tool_element is None:
return tool, message
- element_tree_root = element_tree.getroot()
- # Look for code files required by the tool config.
+ # Look for external files required by the tool config.
tmp_code_files = []
- for code_elem in element_tree_root.findall( 'code' ):
- code_file_name = code_elem.get( 'file' )
- tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, code_file_name, work_dir )
+ external_paths = Tool.get_externally_referenced_paths( tmp_tool_config )
+ for path in external_paths:
+ tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, path, work_dir )
if tmp_code_file_name:
tmp_code_files.append( tmp_code_file_name )
tool, valid, message = self.load_tool_from_config( repository_id, tmp_tool_config )
diff -r 7ac5a36c0ce7a6eb280d339de2107740552825ce -r 7cacfb33db90dee8c4e9ce78a3a735cd6cef8490 test/unit/tools/test_tool_external_files.py
--- /dev/null
+++ b/test/unit/tools/test_tool_external_files.py
@@ -0,0 +1,30 @@
+""" Unit test logic related to finding externally referenced files in tool
+descriptions.
+"""
+import tempfile
+import os
+import shutil
+from galaxy.tools import Tool
+
+
+def test_finds_external_code_file():
+ assert __external_files("""<tool><code file="foo.py" /></tool>""") == ["foo.py"]
+
+
+def test_finds_skips_empty_code_file_attribute():
+ assert __external_files("""<tool><code /></tool>""") == []
+
+
+def test_finds_external_macro_file():
+ assert __external_files("""<tool><macros><import>cool_macros.xml</import></macros></tool>""") == ["cool_macros.xml"]
+
+
+def __external_files(contents):
+ base_path = tempfile.mkdtemp()
+ try:
+ tool_path = os.path.join(base_path, "tool.xml")
+ with open(tool_path, "w") as f:
+ f.write(contents)
+ return Tool.get_externally_referenced_paths(tool_path)
+ finally:
+ shutil.rmtree(base_path)
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: fix single-pixel gap bug in quantitative track display.
by commits-noreply@bitbucket.org 04 Aug '14
by commits-noreply@bitbucket.org 04 Aug '14
04 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7ac5a36c0ce7/
Changeset: 7ac5a36c0ce7
Branch: next-stable
User: jgoecks
Date: 2014-08-04 20:50:28
Summary: Trackster: fix single-pixel gap bug in quantitative track display.
Affected #: 2 files
diff -r 2438770e2cfbf804acc0d5c7b2f3d6e491f30695 -r 7ac5a36c0ce7a6eb280d339de2107740552825ce static/scripts/packed/viz/trackster/painters.js
--- a/static/scripts/packed/viz/trackster/painters.js
+++ b/static/scripts/packed/viz/trackster/painters.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(_){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 DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};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 LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};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 painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.round((data[i][0]-view_start)*w_scale);y=data[i][1];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=painter_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());this.max_label_length=200};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)},get_top_padding:function(width){return 0},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,incomplete_features=[];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((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){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]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){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],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(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_start+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_start+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_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(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_start,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-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(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_start+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_start+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_start)}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_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+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_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);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,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.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},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}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];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,y_start+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_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")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+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_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}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.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,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_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end,y_start+5,b2_start,y_start+5)}}else{this.draw_read(ctx,mode,w_scale,y_start,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;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}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_start){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_start,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{if(rgb.length==7){this.rgb=rgb.substring(1,7).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:"#FF8C00",neg_color:"#4169E1"};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()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
+define(["libs/underscore"],function(_){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 DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};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 LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};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 painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];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=painter_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());this.max_label_length=200};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)},get_top_padding:function(width){return 0},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,incomplete_features=[];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((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){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]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){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],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(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_start+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_start+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_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(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_start,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-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(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_start+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_start+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_start)}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_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+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_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);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,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.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},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}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];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,y_start+5,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_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")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+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_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}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.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,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_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;dashedLine(ctx,b1_end,y_start+5,b2_start,y_start+5)}}else{this.draw_read(ctx,mode,w_scale,y_start,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;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}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_start){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_start,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{if(rgb.length==7){this.rgb=rgb.substring(1,7).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:"#FF8C00",neg_color:"#4169E1"};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()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
diff -r 2438770e2cfbf804acc0d5c7b2f3d6e491f30695 -r 7ac5a36c0ce7a6eb280d339de2107740552825ce static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -196,7 +196,7 @@
ctx.fillStyle = ctx.strokeStyle = painter_color;
top_overflow = bot_overflow = false;
- x_scaled = Math.round((data[i][0] - view_start) * w_scale);
+ x_scaled = Math.ceil((data[i][0] - view_start) * w_scale);
y = data[i][1];
// Process Y (scaler) value.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2438770e2cfb/
Changeset: 2438770e2cfb
Branch: next-stable
User: jmchilton
Date: 2014-08-04 16:15:57
Summary: Python 2.6 compat fix for 591f036.
Affected #: 1 file
diff -r 4aa37815f1fba179ac45c0a67eaffc319905cf0e -r 2438770e2cfbf804acc0d5c7b2f3d6e491f30695 lib/galaxy/util/topsort.py
--- a/lib/galaxy/util/topsort.py
+++ b/lib/galaxy/util/topsort.py
@@ -36,7 +36,7 @@
many methods to help analyze and break the cycles. This requires
a good deal more code than topsort itself!
"""
-from collections import OrderedDict
+from galaxy.util.odict import odict as OrderedDict
from exceptions import Exception
https://bitbucket.org/galaxy/galaxy-central/commits/cd82587fb36e/
Changeset: cd82587fb36e
User: jmchilton
Date: 2014-08-04 16:16:13
Summary: Merge next-stable.
Affected #: 1 file
diff -r 120b7b9c1c73e5577f874674e9773b17784c0d52 -r cd82587fb36ecbc802931edad29372f69cee7108 lib/galaxy/util/topsort.py
--- a/lib/galaxy/util/topsort.py
+++ b/lib/galaxy/util/topsort.py
@@ -36,7 +36,7 @@
many methods to help analyze and break the cycles. This requires
a good deal more code than topsort itself!
"""
-from collections import OrderedDict
+from galaxy.util.odict import odict as OrderedDict
from exceptions import Exception
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: jmchilton: Cleanup test case in e7ba2469bca0cb7a1d5a8d754885537dc683d490.
by commits-noreply@bitbucket.org 04 Aug '14
by commits-noreply@bitbucket.org 04 Aug '14
04 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/120b7b9c1c73/
Changeset: 120b7b9c1c73
User: jmchilton
Date: 2014-08-04 15:38:05
Summary: Cleanup test case in e7ba2469bca0cb7a1d5a8d754885537dc683d490.
Affected #: 1 file
diff -r cde36ab1fe9934579d1fc03c7538853b0f533708 -r 120b7b9c1c73e5577f874674e9773b17784c0d52 test/api/test_workflows.py
--- a/test/api/test_workflows.py
+++ b/test/api/test_workflows.py
@@ -109,11 +109,12 @@
# Run this index stability test with following command:
# ./run_tests.sh test/api/test_workflows.py:WorkflowsApiTestCase.test_workflow_stability
from pkg_resources import resource_string
+ num_tests = 1
for workflow_file in [ "test_workflow_topoambigouity.ga", "test_workflow_topoambigouity_auto_laidout.ga" ]:
workflow_str = resource_string( __name__, workflow_file )
workflow = self.workflow_populator.load_workflow( "test1", content=workflow_str )
last_step_map = self._step_map( workflow )
- for i in range(10):
+ for i in range(num_tests):
uploaded_workflow_id = self.workflow_populator.create_workflow( workflow )
download_response = self._get( "workflows/%s/download" % uploaded_workflow_id )
downloaded_workflow = download_response.json()
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/commits/e7ba2469bca0/
Changeset: e7ba2469bca0
Branch: next-stable
User: jmchilton
Date: 2014-08-04 15:33:40
Summary: Test cases and test workflows to verify workflow import stability.
Affected #: 3 files
diff -r f4f50588c63807c1da91b5e820cfa15837a20d75 -r e7ba2469bca0cb7a1d5a8d754885537dc683d490 test/api/test_workflow_topoambigouity.ga
--- /dev/null
+++ b/test/api/test_workflow_topoambigouity.ga
@@ -0,0 +1,471 @@
+{
+ "a_galaxy_workflow": "true",
+ "annotation": "",
+ "format-version": "0.1",
+ "name": "topoambigouity",
+ "steps": {
+ "0": {
+ "annotation": "",
+ "id": 0,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "l"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 193.7604217529297,
+ "top": 156.00001525878906
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"l\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "1": {
+ "annotation": "",
+ "id": 1,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "m"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 199.7639012336731,
+ "top": 282.9757237434387
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"m\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "2": {
+ "annotation": "",
+ "id": 2,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "n"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 213.73957872390747,
+ "top": 372.92363023757935
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"n\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "3": {
+ "annotation": "",
+ "id": 3,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "a"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 387.21183824539185,
+ "top": 414.39933824539185
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"a\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "4": {
+ "annotation": "",
+ "id": 4,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "b"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 389.2083592414856,
+ "top": 484.4514012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"b\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "5": {
+ "annotation": "",
+ "id": 5,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "c"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 402.2465672492981,
+ "top": 568.4618382453918
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"c\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "6": {
+ "annotation": "",
+ "id": 6,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "d"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 398.2881932258606,
+ "top": 641.5000462532043
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"d\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "7": {
+ "annotation": "",
+ "id": 7,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "k"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 931.6736912727356,
+ "top": 787.8889012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"k\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "8": {
+ "annotation": "",
+ "id": 8,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "h"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 923.6006932258606,
+ "top": 599.7986302375793
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"h\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "9": {
+ "annotation": "",
+ "id": 9,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "i"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 921.5694432258606,
+ "top": 694.7639012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"i\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "10": {
+ "annotation": "",
+ "id": 10,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "e"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 683.3750462532043,
+ "top": 600.5972752571106
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"e\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "11": {
+ "annotation": "",
+ "id": 11,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "f"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 692.3854222297668,
+ "top": 694.5729222297668
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"f\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "12": {
+ "annotation": "",
+ "id": 12,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "g"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 681.5173802375793,
+ "top": 760.7014012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"g\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "13": {
+ "annotation": "",
+ "id": 13,
+ "input_connections": {
+ "input1": {
+ "id": 3,
+ "output_name": "output"
+ },
+ "queries_0|input2": {
+ "id": 4,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 5,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 6,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 660.3368382453918,
+ "top": 404.57295274734497
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "14": {
+ "annotation": "",
+ "id": 14,
+ "input_connections": {
+ "input1": {
+ "id": 13,
+ "output_name": "out_file1"
+ },
+ "queries_0|input2": {
+ "id": 10,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 11,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 12,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 915.5451512336731,
+ "top": 394.7639012336731
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "15": {
+ "annotation": "",
+ "id": 15,
+ "input_connections": {
+ "input1": {
+ "id": 14,
+ "output_name": "out_file1"
+ },
+ "queries_0|input2": {
+ "id": 8,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 9,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 7,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 217.61113023757935,
+ "top": 760.8055882453918
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "16": {
+ "annotation": "",
+ "id": 16,
+ "input_connections": {
+ "input1": {
+ "id": 0,
+ "output_name": "output"
+ },
+ "queries_0|input2": {
+ "id": 1,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 2,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 15,
+ "output_name": "out_file1"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 462.9583592414856,
+ "top": 194.15626573562622
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ }
+ }
+}
\ No newline at end of file
diff -r f4f50588c63807c1da91b5e820cfa15837a20d75 -r e7ba2469bca0cb7a1d5a8d754885537dc683d490 test/api/test_workflow_topoambigouity_auto_laidout.ga
--- /dev/null
+++ b/test/api/test_workflow_topoambigouity_auto_laidout.ga
@@ -0,0 +1,471 @@
+{
+ "a_galaxy_workflow": "true",
+ "annotation": "",
+ "format-version": "0.1",
+ "name": "topoambigouity2",
+ "steps": {
+ "0": {
+ "annotation": "",
+ "id": 0,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "l"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 193.7604217529297,
+ "top": 156.00001525878906
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"l\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "1": {
+ "annotation": "",
+ "id": 1,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "m"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 199.7639012336731,
+ "top": 282.9757237434387
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"m\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "2": {
+ "annotation": "",
+ "id": 2,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "n"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 213.73957872390747,
+ "top": 372.92363023757935
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"n\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "3": {
+ "annotation": "",
+ "id": 3,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "a"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 387.21183824539185,
+ "top": 414.39933824539185
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"a\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "4": {
+ "annotation": "",
+ "id": 4,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "b"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 389.2083592414856,
+ "top": 484.4514012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"b\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "5": {
+ "annotation": "",
+ "id": 5,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "c"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 402.2465672492981,
+ "top": 568.4618382453918
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"c\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "6": {
+ "annotation": "",
+ "id": 6,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "d"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 398.2881932258606,
+ "top": 641.5000462532043
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"d\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "7": {
+ "annotation": "",
+ "id": 7,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "k"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 931.6736912727356,
+ "top": 787.8889012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"k\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "8": {
+ "annotation": "",
+ "id": 8,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "h"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 923.6006932258606,
+ "top": 599.7986302375793
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"h\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "9": {
+ "annotation": "",
+ "id": 9,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "i"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 921.5694432258606,
+ "top": 694.7639012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"i\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "10": {
+ "annotation": "",
+ "id": 10,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "e"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 683.3750462532043,
+ "top": 600.5972752571106
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"e\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "11": {
+ "annotation": "",
+ "id": 11,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "f"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 692.3854222297668,
+ "top": 694.5729222297668
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"f\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "12": {
+ "annotation": "",
+ "id": 12,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "g"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 681.5173802375793,
+ "top": 760.7014012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"g\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "13": {
+ "annotation": "",
+ "id": 13,
+ "input_connections": {
+ "input1": {
+ "id": 3,
+ "output_name": "output"
+ },
+ "queries_0|input2": {
+ "id": 4,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 5,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 6,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 660.3368382453918,
+ "top": 404.57295274734497
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "14": {
+ "annotation": "",
+ "id": 14,
+ "input_connections": {
+ "input1": {
+ "id": 13,
+ "output_name": "out_file1"
+ },
+ "queries_0|input2": {
+ "id": 10,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 11,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 12,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 915.5451512336731,
+ "top": 394.7639012336731
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "15": {
+ "annotation": "",
+ "id": 15,
+ "input_connections": {
+ "input1": {
+ "id": 14,
+ "output_name": "out_file1"
+ },
+ "queries_0|input2": {
+ "id": 8,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 9,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 7,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 217.61113023757935,
+ "top": 760.8055882453918
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "16": {
+ "annotation": "",
+ "id": 16,
+ "input_connections": {
+ "input1": {
+ "id": 0,
+ "output_name": "output"
+ },
+ "queries_0|input2": {
+ "id": 1,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 2,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 15,
+ "output_name": "out_file1"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 462.9583592414856,
+ "top": 194.15626573562622
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ }
+ }
+}
\ No newline at end of file
diff -r f4f50588c63807c1da91b5e820cfa15837a20d75 -r e7ba2469bca0cb7a1d5a8d754885537dc683d490 test/api/test_workflows.py
--- a/test/api/test_workflows.py
+++ b/test/api/test_workflows.py
@@ -105,6 +105,30 @@
self.dataset_populator.wait_for_history( history_id, assert_ok=True )
self.assertEquals("1 2 3\n4 5 6\n7 8 9\n0 a b\n", self.dataset_populator.get_history_dataset_content( history_id ) )
+ def test_workflow_stability( self ):
+ # Run this index stability test with following command:
+ # ./run_tests.sh test/api/test_workflows.py:WorkflowsApiTestCase.test_workflow_stability
+ from pkg_resources import resource_string
+ for workflow_file in [ "test_workflow_topoambigouity.ga", "test_workflow_topoambigouity_auto_laidout.ga" ]:
+ workflow_str = resource_string( __name__, workflow_file )
+ workflow = self.workflow_populator.load_workflow( "test1", content=workflow_str )
+ last_step_map = self._step_map( workflow )
+ for i in range(10):
+ uploaded_workflow_id = self.workflow_populator.create_workflow( workflow )
+ download_response = self._get( "workflows/%s/download" % uploaded_workflow_id )
+ downloaded_workflow = download_response.json()
+ step_map = self._step_map(downloaded_workflow)
+ assert step_map == last_step_map
+ last_step_map = step_map
+
+ def _step_map(self, workflow):
+ # Build dict mapping 'tep index to input name.
+ step_map = {}
+ for step_index, step in workflow["steps"].iteritems():
+ if step[ "type" ] == "data_input":
+ step_map[step_index] = step["inputs"][0]["name"]
+ return step_map
+
@skip_without_tool( "cat1" )
def test_extract_from_history( self ):
history_id = self.dataset_populator.new_history()
https://bitbucket.org/galaxy/galaxy-central/commits/591f0366f034/
Changeset: 591f0366f034
Branch: next-stable
User: jmchilton
Date: 2014-08-04 15:33:40
Summary: Ensure topological sorting is 'stable' w.r.t to first element of tuple.
This improves correctness of 64a25838085978c250a0486b516bb2c8e7c3b850.
Affected #: 2 files
diff -r e7ba2469bca0cb7a1d5a8d754885537dc683d490 -r 591f0366f034f36e1536ec33afa26bed17ffe66c lib/galaxy/util/topsort.py
--- a/lib/galaxy/util/topsort.py
+++ b/lib/galaxy/util/topsort.py
@@ -12,12 +12,17 @@
topsort( [(1,2), (3,3)] )
-may return any of (but nothing other than)
+Valid topological sorts would be any of (but nothing other than)
[3, 1, 2]
[1, 3, 2]
[1, 2, 3]
+... however this variant ensures that 'key' order (first element of
+tuple) is preserved so the following will be result returned:
+
+ [1, 3, 2]
+
because those are the permutations of the input elements that
respect the "1 precedes 2" and "3 precedes 3" input constraints.
Note that a constraint of the form (x, x) is really just a trick
@@ -31,8 +36,9 @@
many methods to help analyze and break the cycles. This requires
a good deal more code than topsort itself!
"""
+from collections import OrderedDict
+from exceptions import Exception
-from exceptions import Exception
class CycleError(Exception):
def __init__(self, sofar, numpreds, succs):
@@ -83,7 +89,7 @@
def get_preds(self):
if self.preds is not None:
return self.preds
- self.preds = preds = {}
+ self.preds = preds = OrderedDict()
remaining_elts = self.get_elements()
for x in remaining_elts:
preds[x] = []
@@ -112,7 +118,7 @@
from random import choice
x = choice(remaining_elts)
answer = []
- index = {}
+ index = OrderedDict()
in_answer = index.has_key
while not in_answer(x):
index[x] = len(answer) # index of x in answer
@@ -124,8 +130,8 @@
return answer
def topsort(pairlist):
- numpreds = {} # elt -> # of predecessors
- successors = {} # elt -> list of successors
+ numpreds = OrderedDict() # elt -> # of predecessors
+ successors = OrderedDict() # elt -> list of successors
for first, second in pairlist:
# make sure every elt is a key in numpreds
if not numpreds.has_key(first):
@@ -174,8 +180,8 @@
return answer
def topsort_levels(pairlist):
- numpreds = {} # elt -> # of predecessors
- successors = {} # elt -> list of successors
+ numpreds = OrderedDict() # elt -> # of predecessors
+ successors = OrderedDict() # elt -> list of successors
for first, second in pairlist:
# make sure every elt is a key in numpreds
if not numpreds.has_key(first):
diff -r e7ba2469bca0cb7a1d5a8d754885537dc683d490 -r 591f0366f034f36e1536ec33afa26bed17ffe66c test/unit/test_topsort.py
--- /dev/null
+++ b/test/unit/test_topsort.py
@@ -0,0 +1,39 @@
+from galaxy.util import topsort
+
+
+def test_topsort_level_stability():
+ data = [
+ (0, 2),
+ (1, 2),
+ (2, 3),
+ (2, 4),
+ (3, 4),
+ (3, 5),
+ (6, 2),
+ ]
+ assert topsort.topsort_levels( data )[ 0 ] == [ 0, 1, 6 ]
+ assert topsort.topsort( data ) == [ 0, 1, 6, 2, 3, 4, 5 ]
+ # Swap first two edges - so 1 appears first
+ swap( data, 0, 1 )
+ assert topsort.topsort_levels( data )[ 0 ] == [ 1, 0, 6 ]
+ assert topsort.topsort( data ) == [ 1, 0, 6, 2, 3, 4, 5 ]
+
+ # Shouldn't really affect sorting of 1 0 6
+ swap( data, 3, 4 )
+ assert topsort.topsort_levels( data )[ 0 ] == [ 1, 0, 6 ]
+ assert topsort.topsort( data ) == [ 1, 0, 6, 2, 3, 4, 5 ]
+
+ # Place 0 before 6 in original list
+ swap( data, 1, 6 )
+ assert topsort.topsort_levels( data )[ 0 ] == [ 1, 6, 0 ]
+ assert topsort.topsort( data ) == [ 1, 6, 0, 2, 3, 4, 5 ]
+
+
+def test_topsort_doc():
+ assert topsort.topsort([(1, 2), (3, 3)]) == [1, 3, 2]
+
+
+def swap(lst, i, j):
+ tmp = lst[j]
+ lst[j] = lst[i]
+ lst[i] = tmp
https://bitbucket.org/galaxy/galaxy-central/commits/4aa37815f1fb/
Changeset: 4aa37815f1fb
Branch: next-stable
User: jmchilton
Date: 2014-08-04 15:33:40
Summary: More progress toward guarenteed workflow import step order stability.
Previous commit ensured that topsort is stable - but keys are reshuffled by position prior to being sent to topsort - in case their are "ties" when sorting by position ensure that import order is preserved before sorting on position.
This is all very dry and seemingly persnickety - but at any rate - after this commit I am fairly confident that Galaxy will import newly saved workflows that have been exported in the same order they were exported in. This means that 64a25838085978c250a0486b516bb2c8e7c3b850 is more correct.
Affected #: 1 file
diff -r 591f0366f034f36e1536ec33afa26bed17ffe66c -r 4aa37815f1fba179ac45c0a67eaffc319905cf0e lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -1693,8 +1693,18 @@
# the local Galaxy instance. Each tuple in the list of missing_tool_tups
# will be ( tool_id, tool_name, tool_version ).
missing_tool_tups = []
+ supplied_steps = data[ 'steps' ]
+ # Try to iterate through imported workflow in such a way as to
+ # preserve step order.
+ step_indices = supplied_steps.keys()
+ try:
+ step_indices = sorted( step_indices, key=int )
+ except ValueError:
+ # to defensive, were these ever or will they ever not be integers?
+ pass
# First pass to build step objects and populate basic values
- for step_dict in data[ 'steps' ].itervalues():
+ for step_index in step_indices:
+ step_dict = supplied_steps[ step_index ]
# Create the model class for the step
step = model.WorkflowStep()
steps.append( step )
https://bitbucket.org/galaxy/galaxy-central/commits/cde36ab1fe99/
Changeset: cde36ab1fe99
User: jmchilton
Date: 2014-08-04 15:34:07
Summary: Merge next-stable.
Affected #: 6 files
diff -r 65583750eedecdf26cd786f11809e9641c171d6f -r cde36ab1fe9934579d1fc03c7538853b0f533708 lib/galaxy/util/topsort.py
--- a/lib/galaxy/util/topsort.py
+++ b/lib/galaxy/util/topsort.py
@@ -12,12 +12,17 @@
topsort( [(1,2), (3,3)] )
-may return any of (but nothing other than)
+Valid topological sorts would be any of (but nothing other than)
[3, 1, 2]
[1, 3, 2]
[1, 2, 3]
+... however this variant ensures that 'key' order (first element of
+tuple) is preserved so the following will be result returned:
+
+ [1, 3, 2]
+
because those are the permutations of the input elements that
respect the "1 precedes 2" and "3 precedes 3" input constraints.
Note that a constraint of the form (x, x) is really just a trick
@@ -31,8 +36,9 @@
many methods to help analyze and break the cycles. This requires
a good deal more code than topsort itself!
"""
+from collections import OrderedDict
+from exceptions import Exception
-from exceptions import Exception
class CycleError(Exception):
def __init__(self, sofar, numpreds, succs):
@@ -83,7 +89,7 @@
def get_preds(self):
if self.preds is not None:
return self.preds
- self.preds = preds = {}
+ self.preds = preds = OrderedDict()
remaining_elts = self.get_elements()
for x in remaining_elts:
preds[x] = []
@@ -112,7 +118,7 @@
from random import choice
x = choice(remaining_elts)
answer = []
- index = {}
+ index = OrderedDict()
in_answer = index.has_key
while not in_answer(x):
index[x] = len(answer) # index of x in answer
@@ -124,8 +130,8 @@
return answer
def topsort(pairlist):
- numpreds = {} # elt -> # of predecessors
- successors = {} # elt -> list of successors
+ numpreds = OrderedDict() # elt -> # of predecessors
+ successors = OrderedDict() # elt -> list of successors
for first, second in pairlist:
# make sure every elt is a key in numpreds
if not numpreds.has_key(first):
@@ -174,8 +180,8 @@
return answer
def topsort_levels(pairlist):
- numpreds = {} # elt -> # of predecessors
- successors = {} # elt -> list of successors
+ numpreds = OrderedDict() # elt -> # of predecessors
+ successors = OrderedDict() # elt -> list of successors
for first, second in pairlist:
# make sure every elt is a key in numpreds
if not numpreds.has_key(first):
diff -r 65583750eedecdf26cd786f11809e9641c171d6f -r cde36ab1fe9934579d1fc03c7538853b0f533708 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -1693,8 +1693,18 @@
# the local Galaxy instance. Each tuple in the list of missing_tool_tups
# will be ( tool_id, tool_name, tool_version ).
missing_tool_tups = []
+ supplied_steps = data[ 'steps' ]
+ # Try to iterate through imported workflow in such a way as to
+ # preserve step order.
+ step_indices = supplied_steps.keys()
+ try:
+ step_indices = sorted( step_indices, key=int )
+ except ValueError:
+ # to defensive, were these ever or will they ever not be integers?
+ pass
# First pass to build step objects and populate basic values
- for step_dict in data[ 'steps' ].itervalues():
+ for step_index in step_indices:
+ step_dict = supplied_steps[ step_index ]
# Create the model class for the step
step = model.WorkflowStep()
steps.append( step )
diff -r 65583750eedecdf26cd786f11809e9641c171d6f -r cde36ab1fe9934579d1fc03c7538853b0f533708 test/api/test_workflow_topoambigouity.ga
--- /dev/null
+++ b/test/api/test_workflow_topoambigouity.ga
@@ -0,0 +1,471 @@
+{
+ "a_galaxy_workflow": "true",
+ "annotation": "",
+ "format-version": "0.1",
+ "name": "topoambigouity",
+ "steps": {
+ "0": {
+ "annotation": "",
+ "id": 0,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "l"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 193.7604217529297,
+ "top": 156.00001525878906
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"l\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "1": {
+ "annotation": "",
+ "id": 1,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "m"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 199.7639012336731,
+ "top": 282.9757237434387
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"m\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "2": {
+ "annotation": "",
+ "id": 2,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "n"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 213.73957872390747,
+ "top": 372.92363023757935
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"n\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "3": {
+ "annotation": "",
+ "id": 3,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "a"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 387.21183824539185,
+ "top": 414.39933824539185
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"a\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "4": {
+ "annotation": "",
+ "id": 4,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "b"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 389.2083592414856,
+ "top": 484.4514012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"b\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "5": {
+ "annotation": "",
+ "id": 5,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "c"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 402.2465672492981,
+ "top": 568.4618382453918
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"c\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "6": {
+ "annotation": "",
+ "id": 6,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "d"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 398.2881932258606,
+ "top": 641.5000462532043
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"d\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "7": {
+ "annotation": "",
+ "id": 7,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "k"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 931.6736912727356,
+ "top": 787.8889012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"k\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "8": {
+ "annotation": "",
+ "id": 8,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "h"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 923.6006932258606,
+ "top": 599.7986302375793
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"h\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "9": {
+ "annotation": "",
+ "id": 9,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "i"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 921.5694432258606,
+ "top": 694.7639012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"i\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "10": {
+ "annotation": "",
+ "id": 10,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "e"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 683.3750462532043,
+ "top": 600.5972752571106
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"e\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "11": {
+ "annotation": "",
+ "id": 11,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "f"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 692.3854222297668,
+ "top": 694.5729222297668
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"f\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "12": {
+ "annotation": "",
+ "id": 12,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "g"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 681.5173802375793,
+ "top": 760.7014012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"g\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "13": {
+ "annotation": "",
+ "id": 13,
+ "input_connections": {
+ "input1": {
+ "id": 3,
+ "output_name": "output"
+ },
+ "queries_0|input2": {
+ "id": 4,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 5,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 6,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 660.3368382453918,
+ "top": 404.57295274734497
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "14": {
+ "annotation": "",
+ "id": 14,
+ "input_connections": {
+ "input1": {
+ "id": 13,
+ "output_name": "out_file1"
+ },
+ "queries_0|input2": {
+ "id": 10,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 11,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 12,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 915.5451512336731,
+ "top": 394.7639012336731
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "15": {
+ "annotation": "",
+ "id": 15,
+ "input_connections": {
+ "input1": {
+ "id": 14,
+ "output_name": "out_file1"
+ },
+ "queries_0|input2": {
+ "id": 8,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 9,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 7,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 217.61113023757935,
+ "top": 760.8055882453918
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "16": {
+ "annotation": "",
+ "id": 16,
+ "input_connections": {
+ "input1": {
+ "id": 0,
+ "output_name": "output"
+ },
+ "queries_0|input2": {
+ "id": 1,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 2,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 15,
+ "output_name": "out_file1"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 462.9583592414856,
+ "top": 194.15626573562622
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ }
+ }
+}
\ No newline at end of file
diff -r 65583750eedecdf26cd786f11809e9641c171d6f -r cde36ab1fe9934579d1fc03c7538853b0f533708 test/api/test_workflow_topoambigouity_auto_laidout.ga
--- /dev/null
+++ b/test/api/test_workflow_topoambigouity_auto_laidout.ga
@@ -0,0 +1,471 @@
+{
+ "a_galaxy_workflow": "true",
+ "annotation": "",
+ "format-version": "0.1",
+ "name": "topoambigouity2",
+ "steps": {
+ "0": {
+ "annotation": "",
+ "id": 0,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "l"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 193.7604217529297,
+ "top": 156.00001525878906
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"l\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "1": {
+ "annotation": "",
+ "id": 1,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "m"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 199.7639012336731,
+ "top": 282.9757237434387
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"m\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "2": {
+ "annotation": "",
+ "id": 2,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "n"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 213.73957872390747,
+ "top": 372.92363023757935
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"n\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "3": {
+ "annotation": "",
+ "id": 3,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "a"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 387.21183824539185,
+ "top": 414.39933824539185
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"a\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "4": {
+ "annotation": "",
+ "id": 4,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "b"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 389.2083592414856,
+ "top": 484.4514012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"b\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "5": {
+ "annotation": "",
+ "id": 5,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "c"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 402.2465672492981,
+ "top": 568.4618382453918
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"c\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "6": {
+ "annotation": "",
+ "id": 6,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "d"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 398.2881932258606,
+ "top": 641.5000462532043
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"d\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "7": {
+ "annotation": "",
+ "id": 7,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "k"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 931.6736912727356,
+ "top": 787.8889012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"k\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "8": {
+ "annotation": "",
+ "id": 8,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "h"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 923.6006932258606,
+ "top": 599.7986302375793
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"h\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "9": {
+ "annotation": "",
+ "id": 9,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "i"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 921.5694432258606,
+ "top": 694.7639012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"i\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "10": {
+ "annotation": "",
+ "id": 10,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "e"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 683.3750462532043,
+ "top": 600.5972752571106
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"e\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "11": {
+ "annotation": "",
+ "id": 11,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "f"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 692.3854222297668,
+ "top": 694.5729222297668
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"f\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "12": {
+ "annotation": "",
+ "id": 12,
+ "input_connections": {},
+ "inputs": [
+ {
+ "description": "",
+ "name": "g"
+ }
+ ],
+ "name": "Input dataset",
+ "outputs": [],
+ "position": {
+ "left": 681.5173802375793,
+ "top": 760.7014012336731
+ },
+ "tool_errors": null,
+ "tool_id": null,
+ "tool_state": "{\"name\": \"g\"}",
+ "tool_version": null,
+ "type": "data_input",
+ "user_outputs": []
+ },
+ "13": {
+ "annotation": "",
+ "id": 13,
+ "input_connections": {
+ "input1": {
+ "id": 3,
+ "output_name": "output"
+ },
+ "queries_0|input2": {
+ "id": 4,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 5,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 6,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 660.3368382453918,
+ "top": 404.57295274734497
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "14": {
+ "annotation": "",
+ "id": 14,
+ "input_connections": {
+ "input1": {
+ "id": 13,
+ "output_name": "out_file1"
+ },
+ "queries_0|input2": {
+ "id": 10,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 11,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 12,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 915.5451512336731,
+ "top": 394.7639012336731
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "15": {
+ "annotation": "",
+ "id": 15,
+ "input_connections": {
+ "input1": {
+ "id": 14,
+ "output_name": "out_file1"
+ },
+ "queries_0|input2": {
+ "id": 8,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 9,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 7,
+ "output_name": "output"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 217.61113023757935,
+ "top": 760.8055882453918
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ },
+ "16": {
+ "annotation": "",
+ "id": 16,
+ "input_connections": {
+ "input1": {
+ "id": 0,
+ "output_name": "output"
+ },
+ "queries_0|input2": {
+ "id": 1,
+ "output_name": "output"
+ },
+ "queries_1|input2": {
+ "id": 2,
+ "output_name": "output"
+ },
+ "queries_2|input2": {
+ "id": 15,
+ "output_name": "out_file1"
+ }
+ },
+ "inputs": [],
+ "name": "Concatenate datasets",
+ "outputs": [
+ {
+ "name": "out_file1",
+ "type": "input"
+ }
+ ],
+ "position": {
+ "left": 462.9583592414856,
+ "top": 194.15626573562622
+ },
+ "post_job_actions": {},
+ "tool_errors": null,
+ "tool_id": "cat1",
+ "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}, {\\\"input2\\\": null, \\\"__index__\\\": 1}, {\\\"input2\\\": null, \\\"__index__\\\": 2}]\"}",
+ "tool_version": "1.0.0",
+ "type": "tool",
+ "user_outputs": []
+ }
+ }
+}
\ No newline at end of file
diff -r 65583750eedecdf26cd786f11809e9641c171d6f -r cde36ab1fe9934579d1fc03c7538853b0f533708 test/api/test_workflows.py
--- a/test/api/test_workflows.py
+++ b/test/api/test_workflows.py
@@ -105,6 +105,30 @@
self.dataset_populator.wait_for_history( history_id, assert_ok=True )
self.assertEquals("1 2 3\n4 5 6\n7 8 9\n0 a b\n", self.dataset_populator.get_history_dataset_content( history_id ) )
+ def test_workflow_stability( self ):
+ # Run this index stability test with following command:
+ # ./run_tests.sh test/api/test_workflows.py:WorkflowsApiTestCase.test_workflow_stability
+ from pkg_resources import resource_string
+ for workflow_file in [ "test_workflow_topoambigouity.ga", "test_workflow_topoambigouity_auto_laidout.ga" ]:
+ workflow_str = resource_string( __name__, workflow_file )
+ workflow = self.workflow_populator.load_workflow( "test1", content=workflow_str )
+ last_step_map = self._step_map( workflow )
+ for i in range(10):
+ uploaded_workflow_id = self.workflow_populator.create_workflow( workflow )
+ download_response = self._get( "workflows/%s/download" % uploaded_workflow_id )
+ downloaded_workflow = download_response.json()
+ step_map = self._step_map(downloaded_workflow)
+ assert step_map == last_step_map
+ last_step_map = step_map
+
+ def _step_map(self, workflow):
+ # Build dict mapping 'tep index to input name.
+ step_map = {}
+ for step_index, step in workflow["steps"].iteritems():
+ if step[ "type" ] == "data_input":
+ step_map[step_index] = step["inputs"][0]["name"]
+ return step_map
+
@skip_without_tool( "cat1" )
def test_extract_from_history( self ):
history_id = self.dataset_populator.new_history()
diff -r 65583750eedecdf26cd786f11809e9641c171d6f -r cde36ab1fe9934579d1fc03c7538853b0f533708 test/unit/test_topsort.py
--- /dev/null
+++ b/test/unit/test_topsort.py
@@ -0,0 +1,39 @@
+from galaxy.util import topsort
+
+
+def test_topsort_level_stability():
+ data = [
+ (0, 2),
+ (1, 2),
+ (2, 3),
+ (2, 4),
+ (3, 4),
+ (3, 5),
+ (6, 2),
+ ]
+ assert topsort.topsort_levels( data )[ 0 ] == [ 0, 1, 6 ]
+ assert topsort.topsort( data ) == [ 0, 1, 6, 2, 3, 4, 5 ]
+ # Swap first two edges - so 1 appears first
+ swap( data, 0, 1 )
+ assert topsort.topsort_levels( data )[ 0 ] == [ 1, 0, 6 ]
+ assert topsort.topsort( data ) == [ 1, 0, 6, 2, 3, 4, 5 ]
+
+ # Shouldn't really affect sorting of 1 0 6
+ swap( data, 3, 4 )
+ assert topsort.topsort_levels( data )[ 0 ] == [ 1, 0, 6 ]
+ assert topsort.topsort( data ) == [ 1, 0, 6, 2, 3, 4, 5 ]
+
+ # Place 0 before 6 in original list
+ swap( data, 1, 6 )
+ assert topsort.topsort_levels( data )[ 0 ] == [ 1, 6, 0 ]
+ assert topsort.topsort( data ) == [ 1, 6, 0, 2, 3, 4, 5 ]
+
+
+def test_topsort_doc():
+ assert topsort.topsort([(1, 2), (3, 3)]) == [1, 3, 2]
+
+
+def swap(lst, i, j):
+ tmp = lst[j]
+ lst[j] = lst[i]
+ lst[i] = tmp
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Add the new Galaxy integrated_tool_panel_config config entry to the Tool Shed so it will start up.
by commits-noreply@bitbucket.org 04 Aug '14
by commits-noreply@bitbucket.org 04 Aug '14
04 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/65583750eede/
Changeset: 65583750eede
User: greg
Date: 2014-08-04 15:27:51
Summary: Add the new Galaxy integrated_tool_panel_config config entry to the Tool Shed so it will start up.
Affected #: 1 file
diff -r 2aafb7e802530d1398a4a217d11744313bbbe732 -r 65583750eedecdf26cd786f11809e9641c171d6f lib/galaxy/webapps/tool_shed/config.py
--- a/lib/galaxy/webapps/tool_shed/config.py
+++ b/lib/galaxy/webapps/tool_shed/config.py
@@ -53,6 +53,7 @@
self.tool_data_path = resolve_path( kwargs.get( "tool_data_path", "shed-tool-data" ), os.getcwd() )
self.tool_data_table_config_path = resolve_path( kwargs.get( 'tool_data_table_config_path', 'tool_data_table_conf.xml' ), self.root )
self.shed_tool_data_table_config = resolve_path( kwargs.get( 'shed_tool_data_table_config', 'shed_tool_data_table_conf.xml' ), self.root )
+ self.integrated_tool_panel_config = resolve_path( kwargs.get( 'integrated_tool_panel_config', 'integrated_tool_panel.xml' ), self.root )
self.builds_file_path = resolve_path( kwargs.get( "builds_file_path", os.path.join( self.tool_data_path, 'shared', 'ucsc', 'builds.txt') ), self.root )
self.len_file_path = resolve_path( kwargs.get( "len_file_path", os.path.join( self.tool_data_path, 'shared','ucsc','chrom') ), self.root )
self.ftp_upload_dir = kwargs.get( 'ftp_upload_dir', None )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Add the new builds_file_path to the Tool Shed's config.
by commits-noreply@bitbucket.org 04 Aug '14
by commits-noreply@bitbucket.org 04 Aug '14
04 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2aafb7e80253/
Changeset: 2aafb7e80253
User: greg
Date: 2014-08-04 15:17:51
Summary: Add the new builds_file_path to the Tool Shed's config.
Affected #: 2 files
diff -r 1a24c68d1c7f2db103e454e52a40e338db57c4f2 -r 2aafb7e802530d1398a4a217d11744313bbbe732 lib/galaxy/webapps/tool_shed/config.py
--- a/lib/galaxy/webapps/tool_shed/config.py
+++ b/lib/galaxy/webapps/tool_shed/config.py
@@ -53,6 +53,7 @@
self.tool_data_path = resolve_path( kwargs.get( "tool_data_path", "shed-tool-data" ), os.getcwd() )
self.tool_data_table_config_path = resolve_path( kwargs.get( 'tool_data_table_config_path', 'tool_data_table_conf.xml' ), self.root )
self.shed_tool_data_table_config = resolve_path( kwargs.get( 'shed_tool_data_table_config', 'shed_tool_data_table_conf.xml' ), self.root )
+ self.builds_file_path = resolve_path( kwargs.get( "builds_file_path", os.path.join( self.tool_data_path, 'shared', 'ucsc', 'builds.txt') ), self.root )
self.len_file_path = resolve_path( kwargs.get( "len_file_path", os.path.join( self.tool_data_path, 'shared','ucsc','chrom') ), self.root )
self.ftp_upload_dir = kwargs.get( 'ftp_upload_dir', None )
# Install and test framework for testing tools contained in repositories.
diff -r 1a24c68d1c7f2db103e454e52a40e338db57c4f2 -r 2aafb7e802530d1398a4a217d11744313bbbe732 tool_shed_wsgi.ini.sample
--- a/tool_shed_wsgi.ini.sample
+++ b/tool_shed_wsgi.ini.sample
@@ -36,6 +36,9 @@
# Temporary storage for additional datasets, this should be shared through the cluster
new_file_path = database/tmp
+# File containing old-style genome builds
+#builds_file_path = tool-data/shared/ucsc/builds.txt
+
# Session support (beaker)
use_beaker_session = True
session_type = memory
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