galaxy-commits
Threads by month
- ----- 2026 -----
- October
- 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
20 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/b3342bc20de5/
Changeset: b3342bc20de5
Branch: next-stable
User: dan
Date: 2014-05-20 16:01:28
Summary: Cleanup for dbkey handling.
Affected #: 2 files
diff -r b29ac7cfd60ed2aaec658f520f3e47f1af4d1ab2 -r b3342bc20de522e5b98f9b97de69737b069d6d64 lib/galaxy/tools/actions/__init__.py
--- a/lib/galaxy/tools/actions/__init__.py
+++ b/lib/galaxy/tools/actions/__init__.py
@@ -193,7 +193,7 @@
# Collect chromInfo dataset and add as parameters to incoming
db_datasets = {}
- ( chrom_info, db_dataset ) = trans.app.genome_builds.get_chrom_info( input_dbkey, tool, trans=trans )
+ ( chrom_info, db_dataset ) = trans.app.genome_builds.get_chrom_info( input_dbkey, trans=trans, custom_build_hack_get_len_from_fasta_conversion=tool.id!='CONVERTER_fasta_to_len' )
if db_dataset:
inp_data.update( { "chromInfo": db_dataset } )
incoming[ "chromInfo" ] = chrom_info
diff -r b29ac7cfd60ed2aaec658f520f3e47f1af4d1ab2 -r b3342bc20de522e5b98f9b97de69737b069d6d64 lib/galaxy/util/dbkeys.py
--- a/lib/galaxy/util/dbkeys.py
+++ b/lib/galaxy/util/dbkeys.py
@@ -44,19 +44,18 @@
rval.append( ( key, "%s (%s) [Custom]" % ( chrom_dict['name'], key ) ) )
return rval
- def get_chrom_info( self, dbkey, tool, trans=None ):
+ def get_chrom_info( self, dbkey, trans=None, custom_build_hack_get_len_from_fasta_conversion=True ):
+ #FIXME: flag to turn off custom_build_hack_get_len_from_fasta_conversion should not be required
chrom_info = None
db_dataset = None
# Collect chromInfo from custom builds
if trans:
db_dataset = trans.db_dataset_for( dbkey )
if db_dataset:
- #incoming[ "chromInfo" ] = db_dataset.file_name
chrom_info = db_dataset.file_name
else:
- # -- Get chrom_info (len file) from either a custom or built-in build. --
+ # Do Custom Build handling
if trans.user and ( 'dbkeys' in trans.user.preferences ) and ( dbkey in from_json_string( trans.user.preferences[ 'dbkeys' ] ) ):
- # Custom build.
custom_build_dict = from_json_string( trans.user.preferences[ 'dbkeys' ] )[ dbkey ]
# HACK: the attempt to get chrom_info below will trigger the
# fasta-to-len converter if the dataset is not available or,
@@ -64,17 +63,19 @@
# running the fasta-to-len tool. So, use a hack in the second
# condition below to avoid getting chrom_info when running the
# fasta-to-len converter.
- if 'fasta' in custom_build_dict and tool.id != 'CONVERTER_fasta_to_len':
+ if 'fasta' in custom_build_dict and custom_build_hack_get_len_from_fasta_conversion:
# Build is defined by fasta; get len file, which is obtained from converting fasta.
build_fasta_dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'fasta' ] )
chrom_info = build_fasta_dataset.get_converted_dataset( trans, 'len' ).file_name
elif 'len' in custom_build_dict:
# Build is defined by len file, so use it.
chrom_info = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'len' ] ).file_name
+ # Check Data table
if not chrom_info:
dbkey_table = self._app.tool_data_tables.get( self._data_table_name, None )
if dbkey_table is not None:
chrom_info = dbkey_table.get_entry( 'value', dbkey, 'len_path', default=None )
+ #use configured len path
if not chrom_info:
# Default to built-in build.
chrom_info = os.path.join( self._static_chrom_info_path, "%s.len" % dbkey )
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/b29ac7cfd60e/
Changeset: b29ac7cfd60e
Branch: next-stable
User: dannon
Date: 2014-05-20 01:54:05
Summary: Additional anyjson requires (appeared to cause Toolshed issues for Greg)
Affected #: 2 files
diff -r faf07312a7daf640f5ecdddd531e90268404a4fd -r b29ac7cfd60ed2aaec658f520f3e47f1af4d1ab2 lib/galaxy/queue_worker.py
--- a/lib/galaxy/queue_worker.py
+++ b/lib/galaxy/queue_worker.py
@@ -9,6 +9,7 @@
import galaxy.queues
from galaxy import eggs, util
+eggs.require('anyjson')
if sys.version_info < (2, 7, 0):
# Kombu requires importlib and ordereddict to function under Python 2.6.
eggs.require('importlib')
diff -r faf07312a7daf640f5ecdddd531e90268404a4fd -r b29ac7cfd60ed2aaec658f520f3e47f1af4d1ab2 lib/galaxy/queues.py
--- a/lib/galaxy/queues.py
+++ b/lib/galaxy/queues.py
@@ -8,6 +8,7 @@
from galaxy import eggs
+eggs.require('anyjson')
if sys.version_info < (2, 7, 0):
# Kombu requires importlib and ordereddict to function in Python 2.6.
eggs.require('importlib')
https://bitbucket.org/galaxy/galaxy-central/commits/11403745e7ce/
Changeset: 11403745e7ce
User: dannon
Date: 2014-05-20 01:54:25
Summary: Merge next-stable
Affected #: 2 files
diff -r 4b3cfc947e1d151d61351d75397863760f1443f1 -r 11403745e7ceb0a6946af648dcd3ca24a638ca7e lib/galaxy/queue_worker.py
--- a/lib/galaxy/queue_worker.py
+++ b/lib/galaxy/queue_worker.py
@@ -9,6 +9,7 @@
import galaxy.queues
from galaxy import eggs, util
+eggs.require('anyjson')
if sys.version_info < (2, 7, 0):
# Kombu requires importlib and ordereddict to function under Python 2.6.
eggs.require('importlib')
diff -r 4b3cfc947e1d151d61351d75397863760f1443f1 -r 11403745e7ceb0a6946af648dcd3ca24a638ca7e lib/galaxy/queues.py
--- a/lib/galaxy/queues.py
+++ b/lib/galaxy/queues.py
@@ -8,6 +8,7 @@
from galaxy import eggs
+eggs.require('anyjson')
if sys.version_info < (2, 7, 0):
# Kombu requires importlib and ordereddict to function in Python 2.6.
eggs.require('importlib')
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/faf07312a7da/
Changeset: faf07312a7da
Branch: next-stable
User: dannon
Date: 2014-05-20 00:58:13
Summary: Kombu also requires ordereddict backport to support python2.6, more eggs.
Affected #: 3 files
diff -r 1ec7fa5ac5e379d308843d633d0bff3d83b34806 -r faf07312a7daf640f5ecdddd531e90268404a4fd eggs.ini
--- a/eggs.ini
+++ b/eggs.ini
@@ -51,6 +51,7 @@
nose = 0.11.1
NoseHTML = 0.4.1
NoseTestDiff = 0.1
+ordereddict = 1.1
paramiko = 1.11.1
Parsley = 1.1
Paste = 1.7.5.1
diff -r 1ec7fa5ac5e379d308843d633d0bff3d83b34806 -r faf07312a7daf640f5ecdddd531e90268404a4fd lib/galaxy/queue_worker.py
--- a/lib/galaxy/queue_worker.py
+++ b/lib/galaxy/queue_worker.py
@@ -10,8 +10,9 @@
import galaxy.queues
from galaxy import eggs, util
if sys.version_info < (2, 7, 0):
- # Kombu requires importlib to function under Python 2.6.
+ # Kombu requires importlib and ordereddict to function under Python 2.6.
eggs.require('importlib')
+ eggs.require('ordereddict')
eggs.require('kombu')
from kombu import Connection
diff -r 1ec7fa5ac5e379d308843d633d0bff3d83b34806 -r faf07312a7daf640f5ecdddd531e90268404a4fd lib/galaxy/queues.py
--- a/lib/galaxy/queues.py
+++ b/lib/galaxy/queues.py
@@ -9,8 +9,9 @@
from galaxy import eggs
if sys.version_info < (2, 7, 0):
- # Kombu requires importlib to function in Python 2.6.
+ # Kombu requires importlib and ordereddict to function in Python 2.6.
eggs.require('importlib')
+ eggs.require('ordereddict')
eggs.require('kombu')
from kombu import Exchange, Queue
https://bitbucket.org/galaxy/galaxy-central/commits/4b3cfc947e1d/
Changeset: 4b3cfc947e1d
User: dannon
Date: 2014-05-20 00:58:28
Summary: Merge from next-stable.
Affected #: 3 files
diff -r e170406ece79b72e991dd94345f5f1da9efd88a6 -r 4b3cfc947e1d151d61351d75397863760f1443f1 eggs.ini
--- a/eggs.ini
+++ b/eggs.ini
@@ -51,6 +51,7 @@
nose = 0.11.1
NoseHTML = 0.4.1
NoseTestDiff = 0.1
+ordereddict = 1.1
paramiko = 1.11.1
Parsley = 1.1
Paste = 1.7.5.1
diff -r e170406ece79b72e991dd94345f5f1da9efd88a6 -r 4b3cfc947e1d151d61351d75397863760f1443f1 lib/galaxy/queue_worker.py
--- a/lib/galaxy/queue_worker.py
+++ b/lib/galaxy/queue_worker.py
@@ -10,8 +10,9 @@
import galaxy.queues
from galaxy import eggs, util
if sys.version_info < (2, 7, 0):
- # Kombu requires importlib to function under Python 2.6.
+ # Kombu requires importlib and ordereddict to function under Python 2.6.
eggs.require('importlib')
+ eggs.require('ordereddict')
eggs.require('kombu')
from kombu import Connection
diff -r e170406ece79b72e991dd94345f5f1da9efd88a6 -r 4b3cfc947e1d151d61351d75397863760f1443f1 lib/galaxy/queues.py
--- a/lib/galaxy/queues.py
+++ b/lib/galaxy/queues.py
@@ -9,8 +9,9 @@
from galaxy import eggs
if sys.version_info < (2, 7, 0):
- # Kombu requires importlib to function in Python 2.6.
+ # Kombu requires importlib and ordereddict to function in Python 2.6.
eggs.require('importlib')
+ eggs.require('ordereddict')
eggs.require('kombu')
from kombu import Exchange, Queue
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/1ec7fa5ac5e3/
Changeset: 1ec7fa5ac5e3
Branch: next-stable
User: dannon
Date: 2014-05-20 00:11:52
Summary: Add conditional requirement of importlib for python 2.6/kombu.
Affected #: 3 files
diff -r 5c2c82003b8fe415f16182bd90398c4b0cbdecae -r 1ec7fa5ac5e379d308843d633d0bff3d83b34806 eggs.ini
--- a/eggs.ini
+++ b/eggs.ini
@@ -43,6 +43,7 @@
elementtree = 1.2.6_20050316
Fabric = 1.7.0
GeneTrack = 2.0.0_beta_1
+importlib = 1.0.3
kombu = 3.0.12
lrucache = 0.2
Mako = 0.4.1
diff -r 5c2c82003b8fe415f16182bd90398c4b0cbdecae -r 1ec7fa5ac5e379d308843d633d0bff3d83b34806 lib/galaxy/queue_worker.py
--- a/lib/galaxy/queue_worker.py
+++ b/lib/galaxy/queue_worker.py
@@ -5,8 +5,13 @@
import logging
import threading
+import sys
+
import galaxy.queues
from galaxy import eggs, util
+if sys.version_info < (2, 7, 0):
+ # Kombu requires importlib to function under Python 2.6.
+ eggs.require('importlib')
eggs.require('kombu')
from kombu import Connection
diff -r 5c2c82003b8fe415f16182bd90398c4b0cbdecae -r 1ec7fa5ac5e379d308843d633d0bff3d83b34806 lib/galaxy/queues.py
--- a/lib/galaxy/queues.py
+++ b/lib/galaxy/queues.py
@@ -4,9 +4,14 @@
"""
+import sys
+
from galaxy import eggs
-eggs.require("kombu")
+if sys.version_info < (2, 7, 0):
+ # Kombu requires importlib to function in Python 2.6.
+ eggs.require('importlib')
+eggs.require('kombu')
from kombu import Exchange, Queue
ALL_CONTROL = "control.*"
https://bitbucket.org/galaxy/galaxy-central/commits/e170406ece79/
Changeset: e170406ece79
User: dannon
Date: 2014-05-20 00:12:05
Summary: Merge next-stable
Affected #: 3 files
diff -r 3100a0f55b14c4193e2621009bb5e3f9d1c2e634 -r e170406ece79b72e991dd94345f5f1da9efd88a6 eggs.ini
--- a/eggs.ini
+++ b/eggs.ini
@@ -43,6 +43,7 @@
elementtree = 1.2.6_20050316
Fabric = 1.7.0
GeneTrack = 2.0.0_beta_1
+importlib = 1.0.3
kombu = 3.0.12
lrucache = 0.2
Mako = 0.4.1
diff -r 3100a0f55b14c4193e2621009bb5e3f9d1c2e634 -r e170406ece79b72e991dd94345f5f1da9efd88a6 lib/galaxy/queue_worker.py
--- a/lib/galaxy/queue_worker.py
+++ b/lib/galaxy/queue_worker.py
@@ -5,8 +5,13 @@
import logging
import threading
+import sys
+
import galaxy.queues
from galaxy import eggs, util
+if sys.version_info < (2, 7, 0):
+ # Kombu requires importlib to function under Python 2.6.
+ eggs.require('importlib')
eggs.require('kombu')
from kombu import Connection
diff -r 3100a0f55b14c4193e2621009bb5e3f9d1c2e634 -r e170406ece79b72e991dd94345f5f1da9efd88a6 lib/galaxy/queues.py
--- a/lib/galaxy/queues.py
+++ b/lib/galaxy/queues.py
@@ -4,9 +4,14 @@
"""
+import sys
+
from galaxy import eggs
-eggs.require("kombu")
+if sys.version_info < (2, 7, 0):
+ # Kombu requires importlib to function in Python 2.6.
+ eggs.require('importlib')
+eggs.require('kombu')
from kombu import Exchange, Queue
ALL_CONTROL = "control.*"
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/70f062a9e200/
Changeset: 70f062a9e200
User: dannon
Date: 2014-05-19 23:44:25
Summary: Merge from next-stable.
Affected #: 1 file
diff -r 05302ebc73772d383ef55781e7c59d7365258e5b -r 70f062a9e200c1b8d6ef5dc43a6c99f41ea70083 lib/galaxy/util/dbkeys.py
--- a/lib/galaxy/util/dbkeys.py
+++ b/lib/galaxy/util/dbkeys.py
@@ -55,9 +55,9 @@
chrom_info = db_dataset.file_name
else:
# -- Get chrom_info (len file) from either a custom or built-in build. --
- if trans.user and ( 'dbkeys' in trans.user.preferences ) and ( input_dbkey in from_json_string( trans.user.preferences[ 'dbkeys' ] ) ):
+ if trans.user and ( 'dbkeys' in trans.user.preferences ) and ( dbkey in from_json_string( trans.user.preferences[ 'dbkeys' ] ) ):
# Custom build.
- custom_build_dict = from_json_string( trans.user.preferences[ 'dbkeys' ] )[ input_dbkey ]
+ custom_build_dict = from_json_string( trans.user.preferences[ 'dbkeys' ] )[ dbkey ]
# HACK: the attempt to get chrom_info below will trigger the
# fasta-to-len converter if the dataset is not available or,
# which will in turn create a recursive loop when
https://bitbucket.org/galaxy/galaxy-central/commits/5c2c82003b8f/
Changeset: 5c2c82003b8f
Branch: next-stable
User: dannon
Date: 2014-05-19 23:47:20
Summary: Fix get_chrom_info to take (and use) the tool in question.
Affected #: 2 files
diff -r d62fd7469c626064d8fe9792ea4584c57b5ed431 -r 5c2c82003b8fe415f16182bd90398c4b0cbdecae lib/galaxy/tools/actions/__init__.py
--- a/lib/galaxy/tools/actions/__init__.py
+++ b/lib/galaxy/tools/actions/__init__.py
@@ -193,7 +193,7 @@
# Collect chromInfo dataset and add as parameters to incoming
db_datasets = {}
- ( chrom_info, db_dataset ) = trans.app.genome_builds.get_chrom_info( input_dbkey, trans=trans )
+ ( chrom_info, db_dataset ) = trans.app.genome_builds.get_chrom_info( input_dbkey, tool, trans=trans )
if db_dataset:
inp_data.update( { "chromInfo": db_dataset } )
incoming[ "chromInfo" ] = chrom_info
diff -r d62fd7469c626064d8fe9792ea4584c57b5ed431 -r 5c2c82003b8fe415f16182bd90398c4b0cbdecae lib/galaxy/util/dbkeys.py
--- a/lib/galaxy/util/dbkeys.py
+++ b/lib/galaxy/util/dbkeys.py
@@ -2,7 +2,7 @@
Functionality for dealing with dbkeys.
"""
#dbkeys read from disk using builds.txt
-from galaxy.util import dbnames, galaxy_directory
+from galaxy.util import dbnames
from galaxy.util.json import from_json_string
from galaxy.util.odict import odict
import os.path
@@ -44,7 +44,7 @@
rval.append( ( key, "%s (%s) [Custom]" % ( chrom_dict['name'], key ) ) )
return rval
- def get_chrom_info( self, dbkey, trans=None ):
+ def get_chrom_info( self, dbkey, tool, trans=None ):
chrom_info = None
db_dataset = None
# Collect chromInfo from custom builds
https://bitbucket.org/galaxy/galaxy-central/commits/3100a0f55b14/
Changeset: 3100a0f55b14
User: dannon
Date: 2014-05-19 23:47:36
Summary: Merge next-stable.
Affected #: 2 files
diff -r 70f062a9e200c1b8d6ef5dc43a6c99f41ea70083 -r 3100a0f55b14c4193e2621009bb5e3f9d1c2e634 lib/galaxy/tools/actions/__init__.py
--- a/lib/galaxy/tools/actions/__init__.py
+++ b/lib/galaxy/tools/actions/__init__.py
@@ -193,7 +193,7 @@
# Collect chromInfo dataset and add as parameters to incoming
db_datasets = {}
- ( chrom_info, db_dataset ) = trans.app.genome_builds.get_chrom_info( input_dbkey, trans=trans )
+ ( chrom_info, db_dataset ) = trans.app.genome_builds.get_chrom_info( input_dbkey, tool, trans=trans )
if db_dataset:
inp_data.update( { "chromInfo": db_dataset } )
incoming[ "chromInfo" ] = chrom_info
diff -r 70f062a9e200c1b8d6ef5dc43a6c99f41ea70083 -r 3100a0f55b14c4193e2621009bb5e3f9d1c2e634 lib/galaxy/util/dbkeys.py
--- a/lib/galaxy/util/dbkeys.py
+++ b/lib/galaxy/util/dbkeys.py
@@ -2,7 +2,7 @@
Functionality for dealing with dbkeys.
"""
#dbkeys read from disk using builds.txt
-from galaxy.util import dbnames, galaxy_directory
+from galaxy.util import dbnames
from galaxy.util.json import from_json_string
from galaxy.util.odict import odict
import os.path
@@ -44,7 +44,7 @@
rval.append( ( key, "%s (%s) [Custom]" % ( chrom_dict['name'], key ) ) )
return rval
- def get_chrom_info( self, dbkey, trans=None ):
+ def get_chrom_info( self, dbkey, tool, trans=None ):
chrom_info = None
db_dataset = None
# Collect chromInfo from custom builds
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Fix (kind of a guess as to the intended functionality) input_dbkey error.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d62fd7469c62/
Changeset: d62fd7469c62
Branch: next-stable
User: dannon
Date: 2014-05-19 23:42:05
Summary: Fix (kind of a guess as to the intended functionality) input_dbkey error.
Affected #: 1 file
diff -r e7bcba2bec53e16c8e11bb136da9f8aad9e430ba -r d62fd7469c626064d8fe9792ea4584c57b5ed431 lib/galaxy/util/dbkeys.py
--- a/lib/galaxy/util/dbkeys.py
+++ b/lib/galaxy/util/dbkeys.py
@@ -55,9 +55,9 @@
chrom_info = db_dataset.file_name
else:
# -- Get chrom_info (len file) from either a custom or built-in build. --
- if trans.user and ( 'dbkeys' in trans.user.preferences ) and ( input_dbkey in from_json_string( trans.user.preferences[ 'dbkeys' ] ) ):
+ if trans.user and ( 'dbkeys' in trans.user.preferences ) and ( dbkey in from_json_string( trans.user.preferences[ 'dbkeys' ] ) ):
# Custom build.
- custom_build_dict = from_json_string( trans.user.preferences[ 'dbkeys' ] )[ input_dbkey ]
+ custom_build_dict = from_json_string( trans.user.preferences[ 'dbkeys' ] )[ dbkey ]
# HACK: the attempt to get chrom_info below will trigger the
# fasta-to-len converter if the dataset is not available or,
# which will in turn create a recursive loop when
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/e7bcba2bec53/
Changeset: e7bcba2bec53
Branch: next-stable
User: jmchilton
Date: 2014-05-19 23:18:02
Summary: HACK: Fix circular dependency non-sense related to tools and dataset collections.
https://gist.github.com/jmchilton/6e19d248002b1080e8ba.
Affected #: 1 file
diff -r c822084e6e5407c6ac80f999fa313808049e58f7 -r e7bcba2bec53e16c8e11bb136da9f8aad9e430ba lib/galaxy/tools/parameters/meta.py
--- a/lib/galaxy/tools/parameters/meta.py
+++ b/lib/galaxy/tools/parameters/meta.py
@@ -2,8 +2,6 @@
from galaxy import model
from galaxy import util
from galaxy import exceptions
-from galaxy.dataset_collections import matching
-from galaxy.dataset_collections import subcollections
import logging
log = logging.getLogger( __name__ )
@@ -29,6 +27,7 @@
else:
return permutations.input_classification.SINGLE, incoming[ input_key ]
+ from galaxy.dataset_collections import matching
collections_to_match = matching.CollectionsToMatch()
def collection_classifier( input_key ):
@@ -52,6 +51,7 @@
hdc = trans.sa_session.query( model.HistoryDatasetCollectionAssociation ).get( hdc_id )
collections_to_match.add( input_key, hdc, subcollection_type=subcollection_type )
if subcollection_type is not None:
+ from galaxy.dataset_collections import subcollections
subcollection_elements = subcollections.split_dataset_collection_instance( hdc, subcollection_type )
return permutations.input_classification.MATCHED, subcollection_elements
else:
https://bitbucket.org/galaxy/galaxy-central/commits/05302ebc7377/
Changeset: 05302ebc7377
User: jmchilton
Date: 2014-05-19 23:18:31
Summary: Merge next-stable.
Affected #: 1 file
diff -r 35afd36f9014915c4c82f65b1c52a6636f48328e -r 05302ebc73772d383ef55781e7c59d7365258e5b lib/galaxy/tools/parameters/meta.py
--- a/lib/galaxy/tools/parameters/meta.py
+++ b/lib/galaxy/tools/parameters/meta.py
@@ -2,8 +2,6 @@
from galaxy import model
from galaxy import util
from galaxy import exceptions
-from galaxy.dataset_collections import matching
-from galaxy.dataset_collections import subcollections
import logging
log = logging.getLogger( __name__ )
@@ -29,6 +27,7 @@
else:
return permutations.input_classification.SINGLE, incoming[ input_key ]
+ from galaxy.dataset_collections import matching
collections_to_match = matching.CollectionsToMatch()
def collection_classifier( input_key ):
@@ -52,6 +51,7 @@
hdc = trans.sa_session.query( model.HistoryDatasetCollectionAssociation ).get( hdc_id )
collections_to_match.add( input_key, hdc, subcollection_type=subcollection_type )
if subcollection_type is not None:
+ from galaxy.dataset_collections import subcollections
subcollection_elements = subcollections.split_dataset_collection_instance( hdc, subcollection_type )
return permutations.input_classification.MATCHED, subcollection_elements
else:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/35afd36f9014/
Changeset: 35afd36f9014
User: dannon
Date: 2014-05-19 22:56:28
Summary: Merge from next-stable.
Affected #: 7 files
diff -r 174b6a2281e53793a8188ba2b2792d0dd220d362 -r 35afd36f9014915c4c82f65b1c52a6636f48328e lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -18,6 +18,7 @@
from galaxy.tools.data_manager.manager import DataManagers
from galaxy.jobs import metrics as job_metrics
from galaxy.web.base import pluginframework
+from galaxy.queue_worker import GalaxyQueueWorker
import logging
log = logging.getLogger( __name__ )
@@ -146,6 +147,10 @@
# Initialize the external service types
self.external_service_types = external_service_types.ExternalServiceTypesCollection( self.config.external_service_type_config_file, self.config.external_service_type_path, self )
self.model.engine.dispose()
+ self.control_worker = GalaxyQueueWorker(self,
+ galaxy.queues.control_queue_from_config(self.config),
+ galaxy.queue_worker.control_message_to_task)
+ self.control_worker.start()
def shutdown( self ):
self.job_manager.shutdown()
diff -r 174b6a2281e53793a8188ba2b2792d0dd220d362 -r 35afd36f9014915c4c82f65b1c52a6636f48328e lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -340,6 +340,17 @@
amqp_config = {}
for k, v in amqp_config:
self.amqp[k] = v
+ # Galaxy internal control queue configuration.
+ # If specified in universe, use it, otherwise we use whatever 'real'
+ # database is specified. Lastly, we create and use new sqlite database
+ # (to minimize locking) as a final option.
+ if 'amqp_internal_connection' in kwargs:
+ self.amqp_internal_connection = kwargs.get('amqp_internal_connection')
+ # TODO Get extra amqp args as necessary for ssl
+ elif 'database_connection' in kwargs:
+ self.amqp_internal_connection = "sqlalchemy+"+self.database_connection
+ else:
+ self.amqp_internal_connection = "sqlalchemy+sqlite:///%s?isolation_level=IMMEDIATE" % resolve_path( "database/control.sqlite", self.root )
self.biostar_url = kwargs.get( 'biostar_url', None )
self.biostar_key_name = kwargs.get( 'biostar_key_name', None )
self.biostar_key = kwargs.get( 'biostar_key', None )
diff -r 174b6a2281e53793a8188ba2b2792d0dd220d362 -r 35afd36f9014915c4c82f65b1c52a6636f48328e lib/galaxy/queue_worker.py
--- /dev/null
+++ b/lib/galaxy/queue_worker.py
@@ -0,0 +1,94 @@
+"""
+Galaxy control queue and worker. This is used to handle 'app' control like
+reloading the toolbox, etc., across multiple processes.
+"""
+
+import logging
+import threading
+import galaxy.queues
+from galaxy import eggs, util
+eggs.require('kombu')
+
+from kombu import Connection
+from kombu.mixins import ConsumerMixin
+from kombu.pools import producers
+
+
+log = logging.getLogger(__name__)
+
+
+class GalaxyQueueWorker(ConsumerMixin, threading.Thread):
+ """
+ This is a flexible worker for galaxy's queues. Each process, web or
+ handler, will have one of these used for dispatching so called 'control'
+ tasks.
+ """
+ def __init__(self, app, queue, task_mapping):
+ super(GalaxyQueueWorker, self).__init__()
+ log.info("Initalizing Galaxy Queue Worker on %s" % app.config.amqp_internal_connection)
+ self.connection = Connection(app.config.amqp_internal_connection)
+ self.app = app
+ # Eventually we may want different workers w/ their own queues and task
+ # mappings. Right now, there's only the one.
+ self.control_queue = queue
+ self.task_mapping = task_mapping
+ self.declare_queues = galaxy.queues.all_control_queues_for_declare(app.config)
+ # TODO we may want to purge the queue at the start to avoid executing
+ # stale 'reload_tool', etc messages. This can happen if, say, a web
+ # process goes down and messages get sent before it comes back up.
+ # Those messages will no longer be useful (in any current case)
+
+ def get_consumers(self, Consumer, channel):
+ return [Consumer(queues=self.control_queue,
+ callbacks=[self.process_task])]
+
+ def process_task(self, body, message):
+ if body['task'] in self.task_mapping:
+ if body.get('noop', None) != self.app.config.server_name:
+ try:
+ f = self.task_mapping[body['task']]
+ log.debug("Instance recieved '%s' task, executing now." % body['task'])
+ f(self.app, **body['kwargs'])
+ except Exception:
+ # this shouldn't ever throw an exception, but...
+ log.exception("Error running control task type: %s" % body['task'])
+ else:
+ log.warning("Recieved a malformed task message:\n%s" % body)
+ message.ack()
+
+
+def send_control_task(trans, task, noop_self=False, kwargs={}):
+ log.info("Sending %s control task." % task)
+ payload = {'task': task,
+ 'kwargs': kwargs}
+ if noop_self:
+ payload['noop'] = trans.app.config.server_name
+ c = Connection(trans.app.config.amqp_internal_connection)
+ with producers[c].acquire(block=True) as producer:
+ producer.publish(payload, exchange=galaxy.queues.galaxy_exchange,
+ declare=[galaxy.queues.galaxy_exchange] + galaxy.queues.all_control_queues_for_declare(trans.app.config),
+ routing_key='control')
+
+
+# Tasks -- to be reorganized into a separate module as appropriate. This is
+# just an example method. Ideally this gets pushed into atomic tasks, whether
+# where they're currently invoked, or elsewhere. (potentially using a dispatch
+# decorator).
+def reload_tool(app, **kwargs):
+ params = util.Params(kwargs)
+ tool_id = params.get('tool_id', None)
+ log.debug("Executing reload tool task for %s" % tool_id)
+ if tool_id:
+ app.toolbox.reload_tool_by_id( tool_id )
+ else:
+ log.error("Reload tool invoked without tool id.")
+
+
+def reload_tool_data_tables(app, **kwargs):
+ params = util.Params(kwargs)
+ log.debug("Executing tool data table reload for %s" % params.get('table_names', 'all tables'))
+ table_names = app.tool_data_tables.reload_tables( table_names=params.get('table_name', None))
+ log.debug("Finished data table reload for %s" % table_names)
+
+control_message_to_task = { 'reload_tool': reload_tool,
+ 'reload_tool_data_tables': reload_tool_data_tables}
diff -r 174b6a2281e53793a8188ba2b2792d0dd220d362 -r 35afd36f9014915c4c82f65b1c52a6636f48328e lib/galaxy/queues.py
--- /dev/null
+++ b/lib/galaxy/queues.py
@@ -0,0 +1,32 @@
+"""
+
+All message queues used by Galaxy
+
+"""
+
+from galaxy import eggs
+
+eggs.require("kombu")
+from kombu import Exchange, Queue
+
+ALL_CONTROL = "control.*"
+galaxy_exchange = Exchange('galaxy_core_exchange', type='topic')
+
+
+def all_control_queues_for_declare(config):
+ """
+ For in-memory routing (used by sqlalchemy-based transports), we need to be able to
+ build the entire routing table in producers.
+
+ Refactor later to actually persist this somewhere instead of building it repeatedly.
+ """
+ return [Queue('control.%s' % q, galaxy_exchange, routing_key='control') for q in config.server_names]
+
+
+def control_queue_from_config(config):
+ """
+ Returns a Queue instance with the correct name and routing key for this
+ galaxy process's config
+ """
+ return Queue("control.%s" % config.server_name, galaxy_exchange,
+ routing_key='control')
diff -r 174b6a2281e53793a8188ba2b2792d0dd220d362 -r 35afd36f9014915c4c82f65b1c52a6636f48328e lib/galaxy/web/base/controllers/admin.py
--- a/lib/galaxy/web/base/controllers/admin.py
+++ b/lib/galaxy/web/base/controllers/admin.py
@@ -5,6 +5,7 @@
from galaxy.util import inflector
from galaxy.web.form_builder import CheckboxField
from string import punctuation as PUNCTUATION
+import galaxy.queue_worker
log = logging.getLogger( __name__ )
@@ -62,8 +63,9 @@
toolbox = self.app.toolbox
tool_id = None
if params.get( 'reload_tool_button', False ):
- tool_id = params.tool_id
- message, status = toolbox.reload_tool_by_id( tool_id )
+ tool_id = params.get('tool_id', None)
+ galaxy.queue_worker.send_control_task(trans, 'reload_tool', noop_self=True, kwargs={'tool_id': tool_id} )
+ message, status = trans.app.toolbox.reload_tool_by_id( tool_id)
return trans.fill_template( '/admin/reload_tool.mako',
tool_id=tool_id,
toolbox=toolbox,
diff -r 174b6a2281e53793a8188ba2b2792d0dd220d362 -r 35afd36f9014915c4c82f65b1c52a6636f48328e lib/galaxy/webapps/galaxy/controllers/data_manager.py
--- a/lib/galaxy/webapps/galaxy/controllers/data_manager.py
+++ b/lib/galaxy/webapps/galaxy/controllers/data_manager.py
@@ -1,6 +1,7 @@
+import galaxy.queue_worker
from galaxy import web
+from galaxy.util.json import from_json_string
from galaxy.web.base.controller import BaseUIController
-from galaxy.util.json import from_json_string
import pkg_resources;
pkg_resources.require( "Paste" )
@@ -90,6 +91,9 @@
table_name = table_name.split( "," )
# Reload the tool data tables
table_names = self.app.tool_data_tables.reload_tables( table_names=table_name )
+ galaxy.queue_worker.send_control_task(trans, 'reload_tool_data_tables',
+ noop_self=True,
+ kwargs={'table_name': table_name} )
redirect_url = None
if table_names:
status = 'done'
diff -r 174b6a2281e53793a8188ba2b2792d0dd220d362 -r 35afd36f9014915c4c82f65b1c52a6636f48328e universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -821,7 +821,21 @@
#user_tool_section_filters = examples:restrict_text
#user_tool_label_filters = examples:restrict_upload_to_admins, examples:restrict_encode
-# ---- Galaxy Message Queue -------------------------------------------------
+# Galaxy Application Internal Message Queue
+
+# Galaxy uses AMQP internally TODO more documentation on what for.
+# For examples, see http://ask.github.io/kombu/userguide/connections.html
+#
+# Without specifying anything here, galaxy will first attempt to use your
+# specified database_connection above. If that's not specified either, Galaxy
+# will automatically create and use a separate sqlite database located in your
+# <galaxy>/database folder (indicated in the commented out line below).
+
+#amqp_internal_connection = "sqlite:///./database/control.sqlite?isolation_level=IMMEDIATE"
+
+
+
+# ---- Galaxy External Message Queue -------------------------------------------------
# Galaxy uses AMQ protocol to receive messages from external sources like
# bar code scanners. Galaxy has been tested against RabbitMQ AMQP implementation.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Initial internal control message queue for IPC implementation. Needs significant refactoring, as noted in some TODOs, but this is a minimally functional version so it makes the next-stable cutoff. Currently only handles reloading tools and data tables, but adding additional tasks is simple and should be straightforward.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c822084e6e54/
Changeset: c822084e6e54
Branch: next-stable
User: dannon
Date: 2014-05-19 22:56:08
Summary: Initial internal control message queue for IPC implementation. Needs significant refactoring, as noted in some TODOs, but this is a minimally functional version so it makes the next-stable cutoff. Currently only handles reloading tools and data tables, but adding additional tasks is simple and should be straightforward.
Affected #: 7 files
diff -r da128dd1ab03d905da0cf8dafec70443267cff64 -r c822084e6e5407c6ac80f999fa313808049e58f7 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -18,6 +18,7 @@
from galaxy.tools.data_manager.manager import DataManagers
from galaxy.jobs import metrics as job_metrics
from galaxy.web.base import pluginframework
+from galaxy.queue_worker import GalaxyQueueWorker
import logging
log = logging.getLogger( __name__ )
@@ -146,6 +147,10 @@
# Initialize the external service types
self.external_service_types = external_service_types.ExternalServiceTypesCollection( self.config.external_service_type_config_file, self.config.external_service_type_path, self )
self.model.engine.dispose()
+ self.control_worker = GalaxyQueueWorker(self,
+ galaxy.queues.control_queue_from_config(self.config),
+ galaxy.queue_worker.control_message_to_task)
+ self.control_worker.start()
def shutdown( self ):
self.job_manager.shutdown()
diff -r da128dd1ab03d905da0cf8dafec70443267cff64 -r c822084e6e5407c6ac80f999fa313808049e58f7 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -340,6 +340,17 @@
amqp_config = {}
for k, v in amqp_config:
self.amqp[k] = v
+ # Galaxy internal control queue configuration.
+ # If specified in universe, use it, otherwise we use whatever 'real'
+ # database is specified. Lastly, we create and use new sqlite database
+ # (to minimize locking) as a final option.
+ if 'amqp_internal_connection' in kwargs:
+ self.amqp_internal_connection = kwargs.get('amqp_internal_connection')
+ # TODO Get extra amqp args as necessary for ssl
+ elif 'database_connection' in kwargs:
+ self.amqp_internal_connection = "sqlalchemy+"+self.database_connection
+ else:
+ self.amqp_internal_connection = "sqlalchemy+sqlite:///%s?isolation_level=IMMEDIATE" % resolve_path( "database/control.sqlite", self.root )
self.biostar_url = kwargs.get( 'biostar_url', None )
self.biostar_key_name = kwargs.get( 'biostar_key_name', None )
self.biostar_key = kwargs.get( 'biostar_key', None )
diff -r da128dd1ab03d905da0cf8dafec70443267cff64 -r c822084e6e5407c6ac80f999fa313808049e58f7 lib/galaxy/queue_worker.py
--- /dev/null
+++ b/lib/galaxy/queue_worker.py
@@ -0,0 +1,94 @@
+"""
+Galaxy control queue and worker. This is used to handle 'app' control like
+reloading the toolbox, etc., across multiple processes.
+"""
+
+import logging
+import threading
+import galaxy.queues
+from galaxy import eggs, util
+eggs.require('kombu')
+
+from kombu import Connection
+from kombu.mixins import ConsumerMixin
+from kombu.pools import producers
+
+
+log = logging.getLogger(__name__)
+
+
+class GalaxyQueueWorker(ConsumerMixin, threading.Thread):
+ """
+ This is a flexible worker for galaxy's queues. Each process, web or
+ handler, will have one of these used for dispatching so called 'control'
+ tasks.
+ """
+ def __init__(self, app, queue, task_mapping):
+ super(GalaxyQueueWorker, self).__init__()
+ log.info("Initalizing Galaxy Queue Worker on %s" % app.config.amqp_internal_connection)
+ self.connection = Connection(app.config.amqp_internal_connection)
+ self.app = app
+ # Eventually we may want different workers w/ their own queues and task
+ # mappings. Right now, there's only the one.
+ self.control_queue = queue
+ self.task_mapping = task_mapping
+ self.declare_queues = galaxy.queues.all_control_queues_for_declare(app.config)
+ # TODO we may want to purge the queue at the start to avoid executing
+ # stale 'reload_tool', etc messages. This can happen if, say, a web
+ # process goes down and messages get sent before it comes back up.
+ # Those messages will no longer be useful (in any current case)
+
+ def get_consumers(self, Consumer, channel):
+ return [Consumer(queues=self.control_queue,
+ callbacks=[self.process_task])]
+
+ def process_task(self, body, message):
+ if body['task'] in self.task_mapping:
+ if body.get('noop', None) != self.app.config.server_name:
+ try:
+ f = self.task_mapping[body['task']]
+ log.debug("Instance recieved '%s' task, executing now." % body['task'])
+ f(self.app, **body['kwargs'])
+ except Exception:
+ # this shouldn't ever throw an exception, but...
+ log.exception("Error running control task type: %s" % body['task'])
+ else:
+ log.warning("Recieved a malformed task message:\n%s" % body)
+ message.ack()
+
+
+def send_control_task(trans, task, noop_self=False, kwargs={}):
+ log.info("Sending %s control task." % task)
+ payload = {'task': task,
+ 'kwargs': kwargs}
+ if noop_self:
+ payload['noop'] = trans.app.config.server_name
+ c = Connection(trans.app.config.amqp_internal_connection)
+ with producers[c].acquire(block=True) as producer:
+ producer.publish(payload, exchange=galaxy.queues.galaxy_exchange,
+ declare=[galaxy.queues.galaxy_exchange] + galaxy.queues.all_control_queues_for_declare(trans.app.config),
+ routing_key='control')
+
+
+# Tasks -- to be reorganized into a separate module as appropriate. This is
+# just an example method. Ideally this gets pushed into atomic tasks, whether
+# where they're currently invoked, or elsewhere. (potentially using a dispatch
+# decorator).
+def reload_tool(app, **kwargs):
+ params = util.Params(kwargs)
+ tool_id = params.get('tool_id', None)
+ log.debug("Executing reload tool task for %s" % tool_id)
+ if tool_id:
+ app.toolbox.reload_tool_by_id( tool_id )
+ else:
+ log.error("Reload tool invoked without tool id.")
+
+
+def reload_tool_data_tables(app, **kwargs):
+ params = util.Params(kwargs)
+ log.debug("Executing tool data table reload for %s" % params.get('table_names', 'all tables'))
+ table_names = app.tool_data_tables.reload_tables( table_names=params.get('table_name', None))
+ log.debug("Finished data table reload for %s" % table_names)
+
+control_message_to_task = { 'reload_tool': reload_tool,
+ 'reload_tool_data_tables': reload_tool_data_tables}
diff -r da128dd1ab03d905da0cf8dafec70443267cff64 -r c822084e6e5407c6ac80f999fa313808049e58f7 lib/galaxy/queues.py
--- /dev/null
+++ b/lib/galaxy/queues.py
@@ -0,0 +1,32 @@
+"""
+
+All message queues used by Galaxy
+
+"""
+
+from galaxy import eggs
+
+eggs.require("kombu")
+from kombu import Exchange, Queue
+
+ALL_CONTROL = "control.*"
+galaxy_exchange = Exchange('galaxy_core_exchange', type='topic')
+
+
+def all_control_queues_for_declare(config):
+ """
+ For in-memory routing (used by sqlalchemy-based transports), we need to be able to
+ build the entire routing table in producers.
+
+ Refactor later to actually persist this somewhere instead of building it repeatedly.
+ """
+ return [Queue('control.%s' % q, galaxy_exchange, routing_key='control') for q in config.server_names]
+
+
+def control_queue_from_config(config):
+ """
+ Returns a Queue instance with the correct name and routing key for this
+ galaxy process's config
+ """
+ return Queue("control.%s" % config.server_name, galaxy_exchange,
+ routing_key='control')
diff -r da128dd1ab03d905da0cf8dafec70443267cff64 -r c822084e6e5407c6ac80f999fa313808049e58f7 lib/galaxy/web/base/controllers/admin.py
--- a/lib/galaxy/web/base/controllers/admin.py
+++ b/lib/galaxy/web/base/controllers/admin.py
@@ -5,6 +5,7 @@
from galaxy.util import inflector
from galaxy.web.form_builder import CheckboxField
from string import punctuation as PUNCTUATION
+import galaxy.queue_worker
log = logging.getLogger( __name__ )
@@ -62,8 +63,9 @@
toolbox = self.app.toolbox
tool_id = None
if params.get( 'reload_tool_button', False ):
- tool_id = params.tool_id
- message, status = toolbox.reload_tool_by_id( tool_id )
+ tool_id = params.get('tool_id', None)
+ galaxy.queue_worker.send_control_task(trans, 'reload_tool', noop_self=True, kwargs={'tool_id': tool_id} )
+ message, status = trans.app.toolbox.reload_tool_by_id( tool_id)
return trans.fill_template( '/admin/reload_tool.mako',
tool_id=tool_id,
toolbox=toolbox,
diff -r da128dd1ab03d905da0cf8dafec70443267cff64 -r c822084e6e5407c6ac80f999fa313808049e58f7 lib/galaxy/webapps/galaxy/controllers/data_manager.py
--- a/lib/galaxy/webapps/galaxy/controllers/data_manager.py
+++ b/lib/galaxy/webapps/galaxy/controllers/data_manager.py
@@ -1,6 +1,7 @@
+import galaxy.queue_worker
from galaxy import web
+from galaxy.util.json import from_json_string
from galaxy.web.base.controller import BaseUIController
-from galaxy.util.json import from_json_string
import pkg_resources;
pkg_resources.require( "Paste" )
@@ -90,6 +91,9 @@
table_name = table_name.split( "," )
# Reload the tool data tables
table_names = self.app.tool_data_tables.reload_tables( table_names=table_name )
+ galaxy.queue_worker.send_control_task(trans, 'reload_tool_data_tables',
+ noop_self=True,
+ kwargs={'table_name': table_name} )
redirect_url = None
if table_names:
status = 'done'
diff -r da128dd1ab03d905da0cf8dafec70443267cff64 -r c822084e6e5407c6ac80f999fa313808049e58f7 universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -821,7 +821,21 @@
#user_tool_section_filters = examples:restrict_text
#user_tool_label_filters = examples:restrict_upload_to_admins, examples:restrict_encode
-# ---- Galaxy Message Queue -------------------------------------------------
+# Galaxy Application Internal Message Queue
+
+# Galaxy uses AMQP internally TODO more documentation on what for.
+# For examples, see http://ask.github.io/kombu/userguide/connections.html
+#
+# Without specifying anything here, galaxy will first attempt to use your
+# specified database_connection above. If that's not specified either, Galaxy
+# will automatically create and use a separate sqlite database located in your
+# <galaxy>/database folder (indicated in the commented out line below).
+
+#amqp_internal_connection = "sqlite:///./database/control.sqlite?isolation_level=IMMEDIATE"
+
+
+
+# ---- Galaxy External Message Queue -------------------------------------------------
# Galaxy uses AMQ protocol to receive messages from external sources like
# bar code scanners. Galaxy has been tested against RabbitMQ AMQP implementation.
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/da128dd1ab03/
Changeset: da128dd1ab03
Branch: next-stable
User: davebgx
Date: 2014-05-19 22:38:58
Summary: Remove migrated tools from main's tool_conf.xml
Affected #: 1 file
diff -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 -r da128dd1ab03d905da0cf8dafec70443267cff64 tool_conf.xml.main
--- a/tool_conf.xml.main
+++ b/tool_conf.xml.main
@@ -41,12 +41,10 @@
</section><section id="convert" name="Convert Formats"><tool file="filters/bed2gff.xml" />
- <tool file="fasta_tools/fasta_to_tabular.xml" /><tool file="filters/gff2bed.xml" /><tool file="maf/maf_to_bed.xml" /><tool file="maf/maf_to_interval.xml" /><tool file="maf/maf_to_fasta.xml" />
- <tool file="fasta_tools/tabular_to_fasta.xml" /><tool file="filters/sff_extractor.xml" /><tool file="filters/wig_to_bigwig.xml" /><tool file="filters/bed_to_bigbed.xml" />
https://bitbucket.org/galaxy/galaxy-central/commits/174b6a2281e5/
Changeset: 174b6a2281e5
User: davebgx
Date: 2014-05-19 22:39:25
Summary: Merge with next-stable.
Affected #: 1 file
diff -r 9b33b543fb1448f8f775ac975e2605ac610c8f63 -r 174b6a2281e53793a8188ba2b2792d0dd220d362 tool_conf.xml.main
--- a/tool_conf.xml.main
+++ b/tool_conf.xml.main
@@ -41,12 +41,10 @@
</section><section id="convert" name="Convert Formats"><tool file="filters/bed2gff.xml" />
- <tool file="fasta_tools/fasta_to_tabular.xml" /><tool file="filters/gff2bed.xml" /><tool file="maf/maf_to_bed.xml" /><tool file="maf/maf_to_interval.xml" /><tool file="maf/maf_to_fasta.xml" />
- <tool file="fasta_tools/tabular_to_fasta.xml" /><tool file="filters/sff_extractor.xml" /><tool file="filters/wig_to_bigwig.xml" /><tool file="filters/bed_to_bigbed.xml" />
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Open next-stable for upcoming June release.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9ebe5ccabe02/
Changeset: 9ebe5ccabe02
Branch: next-stable
User: natefoo
Date: 2014-05-19 21:55:21
Summary: Open next-stable for upcoming June release.
Affected #: 740 files
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -6,3 +6,4 @@
1ae95b3aa98d1ccf15b243ac3ce6a895eb7efc53 release_2013.08.12
26f58e05aa1068761660681583821e21e6cbf7ab release_2013.11.04
5e605ed6069fe4c5ca9875e95e91b2713499e8ca release_2014.02.10
+9e53251b0b7e93b9563008a2b112f2e815a04bbc release_2014.04.14
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/app.css
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/app.css
@@ -0,0 +1,67 @@
+.charts-grid .item {
+ padding: 5px;
+ margin: 5px;
+ float: left;
+ cursor: pointer;
+ border-radius:5px
+}
+
+.charts-grid .current {
+ border-color:#66afe9;
+ background-color:#EEEEFF;
+ outline:0;
+ -webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+ box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+}
+
+.charts-grid .image {
+ padding: 10px;
+ width: 100px;
+}
+
+.charts-grid .title {
+ text-align: center;
+ font-size: 0.9em;
+ word-wrap: break-work;
+ font-weight: bold;
+ width: 100px;
+}
+
+.charts-grid .header {
+ font-size: 0.9em;
+ font-weight: bold;
+}
+
+.charts-viewport {
+ height: inherit;
+ min-height: 50px;
+}
+
+.charts-viewport .info {
+ position: absolute;
+ margin: 10px 20px 50px 10px;
+}
+
+.charts-viewport .text {
+ position: relative;
+ margin-left: 5px;
+ top: -1px;
+ font-size: 1.0em;
+}
+
+.charts-viewport .icon {
+ font-size: 1.2em;
+ display: inline-block;
+}
+
+.charts-viewport .charts-viewport-container {
+ float: left;
+ display: block;
+ height: 100%;
+}
+
+.charts-viewport .charts-viewport-canvas {
+ display: block;
+ width:100%;
+ height: inherit;
+}
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/app.js
--- a/config/plugins/visualizations/charts/static/app.js
+++ b/config/plugins/visualizations/charts/static/app.js
@@ -51,7 +51,7 @@
// append views
this.$el.append(this.viewer_view.$el);
this.$el.append(this.editor_view.$el);
-
+
// pick start screen
if (!this.storage.load()) {
// show editor
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/build-app.js
--- a/config/plugins/visualizations/charts/static/build-app.js
+++ b/config/plugins/visualizations/charts/static/build-app.js
@@ -3,4 +3,4 @@
// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore may be freely distributed under the MIT license.
-(function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-modal",["utils/utils"],function(e){var t=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast")},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup.ui-modal")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&($(document).on("keyup.ui-modal",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:t}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm portlet-view no-highlight">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">',e.icon&&(t+='<div class="portlet-title-icon fa '+e.icon+'"> </div>'),t+='<div id="title-text" class="portlet-title-text">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody portlet-body">',e.placement=="top"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+='<div id="content" class="portlet-content"/>',e.placement=="bottom"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return"<label><b>"+e.title+"</b></label>"},value:function(){return options.title}}),r=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),i=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),s=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),o=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),u=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),f=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),l=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),c=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:n,Button:r,Icon:i,ButtonIcon:s,Input:c,Anchor:o,Message:u,Searchbox:a,Title:f,Select:t,ButtonMenu:l}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},cleanup:function(t){var n=t.get("dataset_id_job");if(n!=""){var r=this;e.request("PUT",config.root+"api/histories/none/contents/"+n,{deleted:!0},function(){r._refreshHdas()}),t.set("dataset_id_job","")}},submit:function(t,n,r,i,s){var o=this,u=t.id,a=t.get("type"),f=this.app.types.get(a);data={tool_id:"chartskit",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:a,columns:r,settings:n}},t.state("wait","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response."),s&&s();else{o._refreshHdas();var n=e.outputs[0];t.state("wait","Job has been queued..."),t.set("dataset_id_job",n.id),this.app.storage.save(),o._loop(n.id,function(e){switch(e.state){case"ok":return t.state("wait","Job completed successfully..."),i(e),!0;case"error":return t.state("failed","Job has failed. Please check the history for details."),s&&s(),!0;case"running":return t.state("wait","Job is running..."),!1}})}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires the Charts-Kit. Please make sure it is installed. "+n),s&&s()})},_loop:function(t,n){var r=this;e.request("GET",config.root+"api/datasets/"+t,{},function(e){n(e)||setTimeout(function(){r._loop(t,n)},r.app.config.get("query_timeout"))})},_refreshHdas:function(){Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshHdas()}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._fetch(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o="",u={},a=0;for(var f in t.groups){var l=t.groups[f];for(var c in l.columns){var h=l.columns[c];o+=h+",",u[h]=a,a++}}if(a==0){n({});return}o=o.substring(0,o.length-1);var p=t.groups.slice(0);for(var f in p)p[f].values=[];var d=this;e.request("GET",config.root+"api/datasets/"+t.id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:o},function(e){for(var i in e.data){var s=e.data[i];for(var o in t.groups){var a=t.groups[o],f={x:parseInt(i)+r};for(var l in a.columns){var c=a.columns[l],h=u[c],d=s[h];if(isNaN(d)||!d)d=0;f[l]=d}p[o].values.push(f)}}n(p)})}})}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})}),define("plugin/library/deferred",["utils/utils"],function(e){return Backbone.Model.extend({queue:[],process:{},counter:0,initialize:function(){this.on("refresh",function(){if(this.counter==0)for(var e in this.queue)this.queue[e](),this.queue.splice(e,1)})},execute:function(e){this.queue.push(e),this.trigger("refresh")},register:function(){var t=e.uuid();return this.process[t]=!0,this.counter++,console.debug("Deferred:register() - Registering "+t),t},done:function(e){delete this.process[e],this.counter--,console.debug("Deferred:done() - Unregistering "+e),this.trigger("refresh")},ready:function(){return this.counter==0?!0:!1}})});var Visualization=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","plugin/library/deferred","mvc/visualization/visualization-model"],function(e,t){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"",state_info:"",modified:!1,dataset_id:"",dataset_id_job:""},initialize:function(n){this.groups=new e,this.settings=new Backbone.Model,this.deferred=new t},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state",e),this.set("state_info",t),this.trigger("set:state"),console.debug("Chart:state() - "+t+" ("+e+")")}})}),define("plugin/library/storage",["utils/utils","plugin/models/chart","plugin/models/group"],function(e,t,n){return Backbone.Model.extend({vis:null,initialize:function(e){this.app=e,this.chart=this.app.chart,this.options=this.app.options,this.id=this.options.id,this.vis=new Visualization({type:"charts",config:{dataset_id:this.options.config.dataset_id,chart_dict:{}}}),this.id&&(this.vis.id=this.id);var t=this.options.config.chart_dict;t&&(this.vis.get("config").chart_dict=t)},save:function(){var e=this.app.chart;this.vis.get("config").chart_dict={};var t=e.get("title");t!=""&&this.vis.set("title",t);var n={attributes:e.attributes,settings:e.settings.attributes,groups:[]};e.groups.each(function(e){n.groups.push(e.attributes)}),this.vis.get("config").chart_dict=n;var r=this;this.vis.save().fail(function(e,t,n){console.error(e,t,n)}).then(function(e){e&&e.id&&(r.id=e.id)})},load:function(){var e=this.vis.get("config").chart_dict;if(!e.attributes)return!1;this.chart.set(e.attributes),this.chart.state("ok","Loading saved visualization..."),this.chart.settings.set(e.settings);for(var t in e.groups)this.chart.groups.add(new n(e.groups[t]));return this.chart.set("modified",!1),!0}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,t){this.app=e,this.chart=this.app.chart,this.options=n.merge(t,this.optionsDefault),this.setElement($(this._template())),this._create_svg();var r=this;this.chart.on("redraw",function(){r._draw(r.chart)}),this.chart.on("set:state",function(){var e=r.$el.find("#info"),t=e.find("#icon");t.removeClass(),e.show(),e.find("#text").html(r.chart.get("state_info"));var n=r.chart.get("state");switch(n){case"ok":e.hide();break;case"failed":t.addClass("fa fa-warning");break;default:t.addClass("fa fa-spinner fa-spin")}})},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_create_svg:function(){this.svg&&this.svg.remove(),this.$el.append($(this._template_svg())),this.svg_el=this.$el.find("svg"),this.svg=d3.select(this.svg_el[0])},_draw:function(e){var t=this;this._create_svg(),e.state("wait","Please wait...");var n=e.deferred.register(),r=e.get("type"),i=this.app.types.get(r);if(!i.execute||i.execute&&e.get("modified"))this.app.jobs.cleanup(e),e.set("modified",!1);var t=this;require(["plugin/charts/"+r+"/"+r],function(r){var s=new r(t.app,{svg:t.svg});i.execute?e.get("dataset_id_job")==""?t.app.jobs.submit(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){s.draw(n,e,t._defaultRequestDictionary(e))},function(){e.deferred.done(n)}):s.draw(n,e,t._defaultRequestDictionary(e)):s.draw(n,e,t._defaultRequestDictionary(e))})},_defaultRequestString:function(e){var t=this.app.types.get(e.get("type")),n="",r=0;return e.groups.each(function(e){for(var i in t.columns)n+=i+"_"+ ++r+":"+(parseInt(e.get(i))+1)+", "}),n.substring(0,n.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t=this.app.types.get(e.get("type")),n={groups:[]};t.execute?n.id=e.get("dataset_id_job"):n.id=e.get("dataset_id");var r=0;return e.groups.each(function(e){var i={};for(var s in t.columns)i[s]=e.get(s);n.groups.push({key:++r+":"+e.get("key"),columns:i})}),n},_template:function(){return'<div style="height: 100%; min-height: 50px;"><div id="info" style="position: absolute; margin-left: 10px; margin-top: 10px; margin-bottom: 50px;"><span id="icon" style="font-size: 1.2em; display: inline-block;"/><span id="text" style="position: relative; margin-left: 5px; top: -1px; font-size: 1.0em;"/></div></div>'},_template_svg:function(){return'<svg style="height: calc(100% - 80px)"/>'}})}),define("plugin/views/viewer",["utils/utils","plugin/library/ui","mvc/ui/ui-portlet","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i){return Backbone.View.extend({initialize:function(e,r){this.app=e,this.chart=this.app.chart,this.viewport_view=new i(e);var s=this;this.portlet=new n.View({icon:"fa-bar-chart-o",title:"Viewport",operations:{edit_button:new t.ButtonIcon({icon:"fa-edit",tooltip:"Customize this chart",title:"Customize",onclick:function(){s._wait(s.chart,function(){s.app.go("editor")})}})}}),this.portlet.append(this.viewport_view.$el),this.setElement(this.portlet.$el);var s=this;this.chart.on("change:title",function(){s._refreshTitle()})},show:function(){this.$el.show(),$(window).trigger("resize")},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");this.portlet.title(e)},_screenshot:function(){var e=new XMLSerializer,t=e.serializeToString(this.viewport_view.svg.node()),n="data:image/svg+xml;base64,"+btoa(t);window.location.href="data:application/x-download/;charset=utf-8,"+encodeURIComponent(t)},_wait:function(e,t){if(e.deferred.ready())t();else{var n=this;this.app.modal.show({title:"Please wait!",body:"Your chart is currently being processed. Please wait and try again.",buttons:{Close:function(){n.app.modal.hide()},Retry:function(){n.app.modal.hide(),setTimeout(function(){n._wait(e,t)},n.app.config.get("query_timeout"))}}})}}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/library/ui-table",["utils/utils"],function(e){var t=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t){var n=$("<td></td>");t&&n.css("width",t),n.append(e),this.row.append(n)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}});return{View:t}}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({columns:[],initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e.View({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e),r.chart.set("modified",!0)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.chart.state("wait","Loading metadata...");var l=this.chart.deferred.register();this.app.datasets.request({id:e},function(e){r.columns=[];var t=e.metadata_column_types;for(var n in t)(t[n]=="int"||t[n]=="float")&&r.columns.push({label:"Column: "+(parseInt(n)+1)+" ["+t[n]+"]",value:n});for(var n in s)s[n].update(r.columns),s[n].show();r.chart.state("wait","Metadata initialized..."),r.chart.deferred.done(l)})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({list:[],initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e.View({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll(),this.list=[];for(var n in e)this._add(n,e[n],t);for(var n in this.list){var r=this.list[n].options.onchange;r&&r()}},_add:function(e,n,r){var i=this,s=null,o=n.type;switch(o){case"text":s=new t.Input({id:e,placeholder:n.placeholder,onchange:function(){r.set(e,s.value())}});break;case"select":s=new t.Select.View({id:e,data:n.data,onchange:function(){var t=s.value();r.set(e,t);var o=_.findWhere(n.data,{value:t});o&&(o.show&&i.$el.find("#"+o.show).fadeIn("fast"),o.hide&&i.$el.find("#"+o.hide).fadeOut("fast"))}});break;case"separator":s=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(o!="separator"){r.get(e)||r.set(e,n.init),s.value(r.get(e)),this.list[e]=s;var u=$("<div/>");u.append(s.$el),u.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(u)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/editor",["mvc/ui/ui-tabs","plugin/library/ui-table","plugin/library/ui","mvc/ui/ui-portlet","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings"],function(e,t,n,r,i,s,o,u,a){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(s,o){var u=this;this.app=s,this.chart=this.app.chart,this.options=i.merge(o,this.optionsDefault),this.portlet=new r.View({icon:"fa-bar-chart-o",title:"Editor",operations:{save:new n.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){u.app.go("viewer"),u._saveChart()}}),back:new n.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){u.app.go("viewer"),u.app.storage.load()}})}}),this.table=new t.View({header:!1,onconfirm:function(e){u.chart.groups.length>0?u.app.modal.show({title:"Switching to another chart type?",body:"If you continue your settings and selections will be cleared.",buttons:{Cancel:function(){u.app.modal.hide()},Continue:function(){u.app.modal.hide(),u.table.value(e)}}}):u.table.value(e)},onchange:function(e){u.chart.groups.reset(),u.chart.settings.clear(),u.chart.set({type:e})},ondblclick:function(e){u.tabs.show("settings")},content:"No chart types available"});var f=0,l=s.types.attributes;for(var c in l){var h=l[c];this.table.add(++f+"."),h.execute?this.table.add(h.title+" (requires processing)"):this.table.add(h.title),this.table.append(c)}this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=u._addGroupModel();u.tabs.show(e.id)}}),this.title=new n.Input({placeholder:"Chart title",onchange:function(){u.chart.set("title",u.title.value())}});var p=$("<div/>");p.append(i.wrap((new n.Label({title:"Provide a chart title:"})).$el)),p.append(i.wrap(this.title.$el)),p.append(i.wrap((new n.Label({title:"Select a chart type:"})).$el)),p.append(i.wrap(this.table.$el)),this.tabs.add({id:"main",title:"Start",$el:p}),this.settings=new a(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.portlet.append(this.tabs.$el),this.setElement(this.portlet.$el),this.tabs.hideOperation("back");var u=this;this.chart.on("change:title",function(e){u._refreshTitle()}),this.chart.on("change:type",function(e){u.table.value(e.get("type"))}),this.chart.on("reset",function(e){u._resetChart()}),this.app.chart.on("redraw",function(e){u.portlet.showOperation("back")}),this.app.chart.groups.on("add",function(e){u._addGroup(e)}),this.app.chart.groups.on("remove",function(e){u._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){u._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){u._refreshGroupKey()}),this._resetChart()},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");this.portlet.title(e),this.title.value(e)},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new o({id:i.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new u(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey(),this.chart.set("modified",!0)},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",i.uuid()),this.chart.set("type","bardiagram"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart"),this.portlet.hideOperation("back")},_saveChart:function(){this.chart.set({type:this.table.value(),title:this.title.value(),date:i.time()}),this.chart.groups.length==0&&this._addGroupModel();var e=this;this.chart.deferred.execute(function(){e.app.storage.save(),e.chart.trigger("redraw")})}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:1e3,query_timeout:500}})}),define("plugin/charts/_nvd3/config",[],function(){return{title:"",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"auto",data:[{label:"-- Do not show values --",value:"hide",hide:"x_axis_tick"},{label:"Auto",value:"auto",hide:"x_axis_tick"},{label:"Float",value:"f",show:"x_axis_tick"},{label:"Exponent",value:"e",show:"x_axis_tick"},{label:"Integer",value:"d",hide:"x_axis_tick"},{label:"Percentage",value:"p",show:"x_axis_tick"},{label:"Rounded",value:"r",show:"x_axis_tick"},{label:"SI-prefix",value:"s",show:"x_axis_tick"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"auto",data:[{label:"-- Do not show values --",value:"hide",hide:"y_axis_tick"},{label:"Auto",value:"auto",hide:"y_axis_tick"},{label:"Float",value:"f",show:"y_axis_tick"},{label:"Exponent",value:"e",show:"y_axis_tick"},{label:"Integer",value:"d",hide:"y_axis_tick"},{label:"Percentage",value:"p",show:"y_axis_tick"},{label:"Rounded",value:"r",show:"y_axis_tick"},{label:"SI-prefix",value:"s",show:"y_axis_tick"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/bardiagram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram"})}),define("plugin/charts/histogram/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",execute:!0,columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"}}})}),define("plugin/charts/horizontal/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Bar diagram (horizontal)",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/line/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart"})}),define("plugin/charts/linewithfocus/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus"})}),define("plugin/charts/piechart/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Pie chart"})}),define("plugin/charts/scatterplot/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/stackedarea/config",["plugin/charts/_nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked area"})}),define("plugin/charts/types",["plugin/charts/bardiagram/config","plugin/charts/histogram/config","plugin/charts/horizontal/config","plugin/charts/line/config","plugin/charts/linewithfocus/config","plugin/charts/piechart/config","plugin/charts/scatterplot/config","plugin/charts/stackedarea/config"],function(e,t,n,r,i,s,o,u){return Backbone.Model.extend({defaults:{bardiagram:e,horizontal:n,histogram:t,line:r,linewithfocus:i,piechart:s,scatterplot:o,stackedarea:u}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/library/storage","plugin/views/viewer","plugin/views/editor","plugin/models/config","plugin/models/chart","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(t){this.options=t,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new f,this.types=new c,this.chart=new l,this.jobs=new i(this),this.datasets=new s(this),this.storage=new o(this),this.viewer_view=new u(this),this.editor_view=new a(this),this.$el.append(this.viewer_view.$el),this.$el.append(this.editor_view.$el);if(!this.storage.load())this.go("editor");else{this.go("viewer");var n=this;this.chart.deferred.execute(function(){n.chart.trigger("redraw")})}},go:function(e){$(".tooltip").hide();switch(e){case"editor":this.editor_view.show(),this.viewer_view.hide();break;case"viewer":this.editor_view.hide(),this.viewer_view.show()}},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
+define("mvc/ui/ui-modal",[],function(){var e=Backbone.View.extend({elMain:"body",optionsDefault:{title:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1,closing_callback:null},buttonList:{},initialize:function(e){e&&this._create(e)},show:function(e){this.initialize(e),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width),this.visible?this.$el.show():this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.visible=!1,this.$el.fadeOut("fast"),this.options.closing_callback&&this.options.closing_callback()},enableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).prop("disabled",!0)},showButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).show()},hideButton:function(e){var t=this.buttonList[e];this.$buttons.find("#"+t).hide()},getButton:function(e){var t=this.buttonList[e];return this.$buttons.find("#"+t)},scrollTop:function(){return this.$body.scrollTop()},_create:function(e){var t=this;this.options=_.defaults(e,this.optionsDefault),this.options.body=="progress"&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"></div></div>')),this.$el&&(this.$el.remove(),$(document).off("keyup.ui-modal")),this.setElement(this._template(this.options.title)),this.$dialog=this.$el.find(".modal-dialog"),this.$body=this.$el.find(".modal-body"),this.$footer=this.$el.find(".modal-footer"),this.$buttons=this.$el.find(".buttons"),this.$backdrop=this.$el.find(".modal-backdrop"),this.$body.html(this.options.body),this.options.backdrop||this.$backdrop.removeClass("in");if(this.options.buttons){this.buttonList={};var n=0;$.each(this.options.buttons,function(e,r){var i="button-"+n++;t.$buttons.append($('<button id="'+i+'"></button>').text(e).click(r)).append(" "),t.buttonList[e]=i})}else this.$footer.hide();$(this.elMain).append($(this.el)),this.options.closing_events&&($(document).on("keyup.ui-modal",function(e){e.keyCode==27&&t.hide()}),this.$el.find(".modal-backdrop").on("click",function(){t.hide()}))},_template:function(e){return'<div class="modal"><div class="modal-backdrop fade in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" style="display: none;">×</button><h4 class="title">'+e+"</h4>"+"</div>"+'<div class="modal-body" style="position: static;"></div>'+'<div class="modal-footer">'+'<div class="buttons" style="float: right;"></div>'+"</div>"+"</div"+"</div>"+"</div>"}});return{View:e}}),function(){var e=this,t=e._,n={},r=Array.prototype,i=Object.prototype,s=Function.prototype,o=r.push,u=r.slice,a=r.concat,f=i.toString,l=i.hasOwnProperty,c=r.forEach,h=r.map,p=r.reduce,d=r.reduceRight,v=r.filter,m=r.every,g=r.some,y=r.indexOf,b=r.lastIndexOf,w=Array.isArray,E=Object.keys,S=s.bind,x=function(e){if(e instanceof x)return e;if(!(this instanceof x))return new x(e);this._wrapped=e};typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(exports=module.exports=x),exports._=x):e._=x,x.VERSION="1.4.4";var T=x.each=x.forEach=function(e,t,r){if(e==null)return;if(c&&e.forEach===c)e.forEach(t,r);else if(e.length===+e.length){for(var i=0,s=e.length;i<s;i++)if(t.call(r,e[i],i,e)===n)return}else for(var o in e)if(x.has(e,o)&&t.call(r,e[o],o,e)===n)return};x.map=x.collect=function(e,t,n){var r=[];return e==null?r:h&&e.map===h?e.map(t,n):(T(e,function(e,i,s){r.push(t.call(n,e,i,s))}),r)};var N="Reduce of empty array with no initial value";x.reduce=x.foldl=x.inject=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(p&&e.reduce===p)return r&&(t=x.bind(t,r)),i?e.reduce(t,n):e.reduce(t);T(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(N);return n},x.reduceRight=x.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(d&&e.reduceRight===d)return r&&(t=x.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=x.keys(e);s=o.length}T(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(N);return n},x.find=x.detect=function(e,t,n){var r;return C(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},x.filter=x.select=function(e,t,n){var r=[];return e==null?r:v&&e.filter===v?e.filter(t,n):(T(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},x.reject=function(e,t,n){return x.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},x.every=x.all=function(e,t,r){t||(t=x.identity);var i=!0;return e==null?i:m&&e.every===m?e.every(t,r):(T(e,function(e,s,o){if(!(i=i&&t.call(r,e,s,o)))return n}),!!i)};var C=x.some=x.any=function(e,t,r){t||(t=x.identity);var i=!1;return e==null?i:g&&e.some===g?e.some(t,r):(T(e,function(e,s,o){if(i||(i=t.call(r,e,s,o)))return n}),!!i)};x.contains=x.include=function(e,t){return e==null?!1:y&&e.indexOf===y?e.indexOf(t)!=-1:C(e,function(e){return e===t})},x.invoke=function(e,t){var n=u.call(arguments,2),r=x.isFunction(t);return x.map(e,function(e){return(r?t:e[t]).apply(e,n)})},x.pluck=function(e,t){return x.map(e,function(e){return e[t]})},x.where=function(e,t,n){return x.isEmpty(t)?n?void 0:[]:x[n?"find":"filter"](e,function(e){for(var n in t)if(t[n]!==e[n])return!1;return!0})},x.findWhere=function(e,t){return x.where(e,t,!0)},x.max=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);if(!t&&x.isEmpty(e))return-Infinity;var r={computed:-Infinity,value:-Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o>=r.computed&&(r={value:e,computed:o})}),r.value},x.min=function(e,t,n){if(!t&&x.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);if(!t&&x.isEmpty(e))return Infinity;var r={computed:Infinity,value:Infinity};return T(e,function(e,i,s){var o=t?t.call(n,e,i,s):e;o<r.computed&&(r={value:e,computed:o})}),r.value},x.shuffle=function(e){var t,n=0,r=[];return T(e,function(e){t=x.random(n++),r[n-1]=r[t],r[t]=e}),r};var k=function(e){return x.isFunction(e)?e:function(t){return t[e]}};x.sortBy=function(e,t,n){var r=k(t);return x.pluck(x.map(e,function(e,t,i){return{value:e,index:t,criteria:r.call(n,e,t,i)}}).sort(function(e,t){var n=e.criteria,r=t.criteria;if(n!==r){if(n>r||n===void 0)return 1;if(n<r||r===void 0)return-1}return e.index<t.index?-1:1}),"value")};var L=function(e,t,n,r){var i={},s=k(t==null?x.identity:t);return T(e,function(t,o){var u=s.call(n,t,o,e);r(i,u,t)}),i};x.groupBy=function(e,t,n){return L(e,t,n,function(e,t,n){(x.has(e,t)?e[t]:e[t]=[]).push(n)})},x.countBy=function(e,t,n){return L(e,t,n,function(e,t){x.has(e,t)||(e[t]=0),e[t]++})},x.sortedIndex=function(e,t,n,r){n=n==null?x.identity:k(n);var i=n.call(r,t),s=0,o=e.length;while(s<o){var u=s+o>>>1;n.call(r,e[u])<i?s=u+1:o=u}return s},x.toArray=function(e){return e?x.isArray(e)?u.call(e):e.length===+e.length?x.map(e,x.identity):x.values(e):[]},x.size=function(e){return e==null?0:e.length===+e.length?e.length:x.keys(e).length},x.first=x.head=x.take=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,0,t):e[0]},x.initial=function(e,t,n){return u.call(e,0,e.length-(t==null||n?1:t))},x.last=function(e,t,n){return e==null?void 0:t!=null&&!n?u.call(e,Math.max(e.length-t,0)):e[e.length-1]},x.rest=x.tail=x.drop=function(e,t,n){return u.call(e,t==null||n?1:t)},x.compact=function(e){return x.filter(e,x.identity)};var A=function(e,t,n){return T(e,function(e){x.isArray(e)?t?o.apply(n,e):A(e,t,n):n.push(e)}),n};x.flatten=function(e,t){return A(e,t,[])},x.without=function(e){return x.difference(e,u.call(arguments,1))},x.uniq=x.unique=function(e,t,n,r){x.isFunction(t)&&(r=n,n=t,t=!1);var i=n?x.map(e,n,r):e,s=[],o=[];return T(i,function(n,r){if(t?!r||o[o.length-1]!==n:!x.contains(o,n))o.push(n),s.push(e[r])}),s},x.union=function(){return x.uniq(a.apply(r,arguments))},x.intersection=function(e){var t=u.call(arguments,1);return x.filter(x.uniq(e),function(e){return x.every(t,function(t){return x.indexOf(t,e)>=0})})},x.difference=function(e){var t=a.apply(r,u.call(arguments,1));return x.filter(e,function(e){return!x.contains(t,e)})},x.zip=function(){var e=u.call(arguments),t=x.max(x.pluck(e,"length")),n=new Array(t);for(var r=0;r<t;r++)n[r]=x.pluck(e,""+r);return n},x.unzip=function(e){var t=[];return x.each(e,function(e,n){x.each(e,function(e,r){t.length<=r&&(t[r]=[]),t[r][n]=e})}),t},x.object=function(e,t){if(e==null)return{};var n={};for(var r=0,i=e.length;r<i;r++)t?n[e[r]]=t[r]:n[e[r][0]]=e[r][1];return n},x.indexOf=function(e,t,n){if(e==null)return-1;var r=0,i=e.length;if(n){if(typeof n!="number")return r=x.sortedIndex(e,t),e[r]===t?r:-1;r=n<0?Math.max(0,i+n):n}if(y&&e.indexOf===y)return e.indexOf(t,n);for(;r<i;r++)if(e[r]===t)return r;return-1},x.lastIndexOf=function(e,t,n){if(e==null)return-1;var r=n!=null;if(b&&e.lastIndexOf===b)return r?e.lastIndexOf(t,n):e.lastIndexOf(t);var i=r?n:e.length;while(i--)if(e[i]===t)return i;return-1},x.range=function(e,t,n){arguments.length<=1&&(t=e||0,e=0),n=arguments[2]||1;var r=Math.max(Math.ceil((t-e)/n),0),i=0,s=new Array(r);while(i<r)s[i++]=e,e+=n;return s};var O=function(){};x.bind=function(e,t){var n,r;if(e.bind===S&&S)return S.apply(e,u.call(arguments,1));if(!x.isFunction(e))throw new TypeError;return n=u.call(arguments,2),r=function(){if(this instanceof r){O.prototype=e.prototype;var i=new O;O.prototype=null;var s=e.apply(i,n.concat(u.call(arguments)));return Object(s)===s?s:i}return e.apply(t,n.concat(u.call(arguments)))}},x.partial=function(e){var t=u.call(arguments,1);return function(){return e.apply(this,t.concat(u.call(arguments)))}},x.bindAll=function(e){var t=u.call(arguments,1);if(t.length===0)throw new Error("bindAll must be passed function names");return T(t,function(t){e[t]=x.bind(e[t],e)}),e},x.memoize=function(e,t){var n={};return t||(t=x.identity),function(){var r=t.apply(this,arguments);return x.has(n,r)?n[r]:n[r]=e.apply(this,arguments)}},x.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},x.defer=function(e){return x.delay.apply(x,[e,1].concat(u.call(arguments,1)))},x.throttle=function(e,t,n){var r,i,s,o,u=0,a=function(){u=new Date,s=null,o=e.apply(r,i)};return function(){var f=new Date;!u&&n===!1&&(u=f);var l=t-(f-u);return r=this,i=arguments,l<=0?(clearTimeout(s),s=null,u=f,o=e.apply(r,i)):s||(s=setTimeout(a,l)),o}},x.debounce=function(e,t,n){var r,i;return function(){var s=this,o=arguments,u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r;return clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},x.once=function(e){var t=!1,n;return function(){return t?n:(t=!0,n=e.apply(this,arguments),e=null,n)}},x.wrap=function(e,t){return function(){var n=[e];return o.apply(n,arguments),t.apply(this,n)}},x.compose=function(){var e=arguments;return function(){var t=arguments;for(var n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},x.after=function(e,t){return e<=0?t():function(){if(--e<1)return t.apply(this,arguments)}},x.keys=E||function(e){if(e!==Object(e))throw new TypeError("Invalid object");var t=[];for(var n in e)x.has(e,n)&&t.push(n);return t},x.values=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push(e[n]);return t},x.pairs=function(e){var t=[];for(var n in e)x.has(e,n)&&t.push([n,e[n]]);return t},x.invert=function(e){var t={};for(var n in e)x.has(e,n)&&(t[e[n]]=n);return t},x.functions=x.methods=function(e){var t=[];for(var n in e)x.isFunction(e[n])&&t.push(n);return t.sort()},x.extend=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]=t[n]}),e},x.pick=function(e){var t={},n=a.apply(r,u.call(arguments,1));return T(n,function(n){n in e&&(t[n]=e[n])}),t},x.omit=function(e){var t={},n=a.apply(r,u.call(arguments,1));for(var i in e)x.contains(n,i)||(t[i]=e[i]);return t},x.defaults=function(e){return T(u.call(arguments,1),function(t){if(t)for(var n in t)e[n]===void 0&&(e[n]=t[n])}),e},x.clone=function(e){return x.isObject(e)?x.isArray(e)?e.slice():x.extend({},e):e},x.tap=function(e,t){return t(e),e};var M=function(e,t,n,r){if(e===t)return e!==0||1/e==1/t;if(e==null||t==null)return e===t;e instanceof x&&(e=e._wrapped),t instanceof x&&(t=t._wrapped);var i=f.call(e);if(i!=f.call(t))return!1;switch(i){case"[object String]":return e==String(t);case"[object Number]":return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case"[object Date]":case"[object Boolean]":return+e==+t;case"[object RegExp]":return e.source==t.source&&e.global==t.global&&e.multiline==t.multiline&&e.ignoreCase==t.ignoreCase}if(typeof e!="object"||typeof t!="object")return!1;var s=n.length;while(s--)if(n[s]==e)return r[s]==t;n.push(e),r.push(t);var o=0,u=!0;if(i=="[object Array]"){o=e.length,u=o==t.length;if(u)while(o--)if(!(u=M(e[o],t[o],n,r)))break}else{var a=e.constructor,l=t.constructor;if(a!==l&&!(x.isFunction(a)&&a instanceof a&&x.isFunction(l)&&l instanceof l))return!1;for(var c in e)if(x.has(e,c)){o++;if(!(u=x.has(t,c)&&M(e[c],t[c],n,r)))break}if(u){for(c in t)if(x.has(t,c)&&!(o--))break;u=!o}}return n.pop(),r.pop(),u};x.isEqual=function(e,t){return M(e,t,[],[])},x.isEmpty=function(e){if(e==null)return!0;if(x.isArray(e)||x.isString(e))return e.length===0;for(var t in e)if(x.has(e,t))return!1;return!0},x.isElement=function(e){return!!e&&e.nodeType===1},x.isArray=w||function(e){return f.call(e)=="[object Array]"},x.isObject=function(e){return e===Object(e)},T(["Arguments","Function","String","Number","Date","RegExp"],function(e){x["is"+e]=function(t){return f.call(t)=="[object "+e+"]"}}),x.isArguments(arguments)||(x.isArguments=function(e){return!!e&&!!x.has(e,"callee")}),typeof /./!="function"&&(x.isFunction=function(e){return typeof e=="function"}),x.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},x.isNaN=function(e){return x.isNumber(e)&&e!=+e},x.isBoolean=function(e){return e===!0||e===!1||f.call(e)=="[object Boolean]"},x.isNull=function(e){return e===null},x.isUndefined=function(e){return e===void 0},x.has=function(e,t){return l.call(e,t)},x.noConflict=function(){return e._=t,this},x.identity=function(e){return e},x.times=function(e,t,n){var r=Array(e);for(var i=0;i<e;i++)r[i]=t.call(n,i);return r},x.random=function(e,t){return t==null&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))};var _={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};_.unescape=x.invert(_.escape);var D={escape:new RegExp("["+x.keys(_.escape).join("")+"]","g"),unescape:new RegExp("("+x.keys(_.unescape).join("|")+")","g")};x.each(["escape","unescape"],function(e){x[e]=function(t){return t==null?"":(""+t).replace(D[e],function(t){return _[e][t]})}}),x.result=function(e,t){if(e==null)return void 0;var n=e[t];return x.isFunction(n)?n.call(e):n},x.mixin=function(e){T(x.functions(e),function(t){var n=x[t]=e[t];x.prototype[t]=function(){var e=[this._wrapped];return o.apply(e,arguments),F.call(this,n.apply(x,e))}})};var P=0;x.uniqueId=function(e){var t=++P+"";return e?e+t:t},x.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var H=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},j=/\\|'|\r|\n|\t|\u2028|\u2029/g;x.template=function(e,t,n){var r;n=x.defaults({},n,x.templateSettings);var i=new RegExp([(n.escape||H).source,(n.interpolate||H).source,(n.evaluate||H).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(j,function(e){return"\\"+B[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,x);var a=function(e){return r.call(this,e,x)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},x.chain=function(e){return x(e).chain()};var F=function(e){return this._chain?x(e).chain():e};x.mixin(x),T(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=r[e];x.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],F.call(this,n)}}),T(["concat","join","slice"],function(e){var t=r[e];x.prototype[e]=function(){return F.call(this,t.apply(this._wrapped,arguments))}}),x.extend(x.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}.call(this),define("libs/underscore",function(e){return function(){var t,n;return t||e._}}(this)),define("utils/utils",["libs/underscore"],function(e){function t(e,t,r){n("GET",e,{},t,r)}function n(e,t,n,r,i){if(e=="GET"||e=="DELETE")t.indexOf("?")==-1?t+="?":t+="&",t+=$.param(n);var s=new XMLHttpRequest;s.open(e,t,!0),s.setRequestHeader("Accept","application/json"),s.setRequestHeader("Cache-Control","no-cache"),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-Type","application/json"),s.onloadend=function(){var e=s.status;try{response=jQuery.parseJSON(s.responseText)}catch(t){response=s.responseText}e==200?r&&r(response):i&&i(response)},e=="GET"||e=="DELETE"?s.send():s.send(JSON.stringify(n))}function r(e,t){var n=$('<div class="'+e+'"></div>');n.appendTo(":eq(0)");var r=n.css(t);return n.remove(),r}function i(e){$('link[href^="'+e+'"]').length||$('<link href="'+galaxy_config.root+e+'" rel="stylesheet">').appendTo("head")}function s(t,n){return t?e.defaults(t,n):n}function o(e,t){var n="";if(e>=1e11)e/=1e11,n="TB";else if(e>=1e8)e/=1e8,n="GB";else if(e>=1e5)e/=1e5,n="MB";else if(e>=100)e/=100,n="KB";else{if(!(e>0))return"<strong>-</strong>";e*=10,n="b"}var r=Math.round(e)/10;return t?r+" "+n:"<strong>"+r+"</strong> "+n}function u(){return(new Date).getTime().toString(36)}function a(e){var t=$("<p></p>");return t.append(e),t}function f(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),n=(e.getMinutes()<10?"0":"")+e.getMinutes(),r=e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+n;return r}return{cssLoadFile:i,cssGetAttribute:r,get:t,merge:s,bytesToString:o,uuid:u,time:f,wrap:a,request:n}}),define("mvc/ui/ui-portlet",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,optionsDefault:{title:"",icon:"",buttons:null,body:null,height:null,operations:null,placement:"bottom",overflow:"auto"},$title:null,$content:null,$buttons:null,$operations:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$content=this.$el.find("#content"),this.$title=this.$el.find("#title-text"),this.options.height&&(this.$el.find("#body").css("height",this.options.height),this.$el.find("#content").css("overflow",this.options.overflow)),this.$buttons=$(this.el).find("#buttons");if(this.options.buttons){var n=this;$.each(this.options.buttons,function(e,t){t.$el.prop("id",e),n.$buttons.append(t.$el)})}else this.$buttons.remove();this.$operations=$(this.el).find("#operations");if(this.options.operations){var n=this;$.each(this.options.operations,function(e,t){t.$el.prop("id",e),n.$operations.append(t.$el)})}this.options.body&&this.append(this.options.body)},append:function(t){this.$content.append(e.wrap(t))},content:function(){return this.$content},show:function(){this.$el.fadeIn("fast"),this.visible=!0},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},enableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!1)},disableButton:function(e){this.$buttons.find("#"+e).prop("disabled",!0)},hideOperation:function(e){this.$operations.find("#"+e).hide()},showOperation:function(e){this.$operations.find("#"+e).show()},setOperation:function(e,t){var n=this.$operations.find("#"+e);n.off("click"),n.on("click",t)},title:function(e){var t=this.$title;return e&&t.html(e),t.html()},_template:function(e){var t='<div class="toolForm portlet-view no-highlight">';if(e.title||e.icon)t+='<div id="title" class="toolFormTitle portlet-title"><div id="operations" class="portlet-operations"/><div style="overflow: hidden;">',e.icon&&(t+='<div class="portlet-title-icon fa '+e.icon+'"> </div>'),t+='<div id="title-text" class="portlet-title-text">'+e.title+"</div>",t+="</div></div>";return t+='<div id="body" class="toolFormBody portlet-body">',e.placement=="top"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+='<div id="content" class="portlet-content"/>',e.placement=="bottom"&&(t+='<div id="buttons" class="portlet-buttons"/>'),t+="</div></div>",t}});return{View:t}}),define("plugin/library/ui-select",["utils/utils"],function(e){var t=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:!0,wait:!1},selected:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.$select=this.$el.find("#select"),this.$icon=this.$el.find("#icon"),this.selected=this.options.value;var n=this;this.options.onchange&&this.$select.on("change",function(){n.value(n.$select.val())}),this._refresh(),this.options.visible||this.hide(),this.options.wait?this.wait():this.show()},value:function(e){var t=this.selected;e!==undefined&&(this.selected=e,this.$select.val(e));var n=this.selected;return n&&n!=t&&this.options.onchange&&this.options.onchange(n),n},text:function(){return this.$select.find("option:selected").text()},show:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-caret-down"),this.$select.show(),this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass(),this.$icon.addClass("fa fa-spinner fa-spin"),this.$select.hide()},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",!1)},disable:function(){this.$select.prop("disabled",!0)},add:function(e){this.$select.append(this._templateOption(e)),this._refresh()},del:function(e){this.$select.find("option[value="+e+"]").remove(),this.$select.trigger("change"),this._refresh()},update:function(e){this.$select.find("option").remove();for(var t in e)this.$select.append(this._templateOption(e[t]));!this.selected&&e.length>0&&this.value(e[0].value),this._refresh()},_refresh:function(){this.$select.find("option[value=null]").remove();var e=this.$select.find("option").length;e==0?(this.$select.append(this._templateOption({value:"null",label:this.options.empty})),this.disable()):(this.enable(),this.selected&&this.$select.val(this.selected))},_exists:function(e){return 0!=this.$select.find("option[value="+e+"]").length},_templateOption:function(e){return'<option value="'+e.value+'">'+e.label+"</option>"},_template:function(e){var t='<div id="'+e.id+'" class="styled-select">'+'<div class="button">'+'<i id="icon"/>'+"</div>"+'<select id="select" class="select '+e.cls+" "+e.id+'">';for(key in e.data){var n=e.data[key],r="";if(n.value==e.value||n.value=="")r="selected";t+='<option value="'+n.value+'" '+r+">"+n.label+"</option>"}return t+="</select></div>",t}});return{View:t}}),define("plugin/library/ui",["utils/utils","plugin/library/ui-select"],function(e,t){var n=Backbone.View.extend({optionsDefault:{url:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},_template:function(e){return'<img src="'+e.url+'"/>'}}),r=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.find("b").html(e)},_template:function(e){return'<label class="'+e.cls+'"><b>'+e.title+"</b></label>"},value:function(){return options.title}}),i=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options))},title:function(e){this.$el.html(e)},_template:function(e){return'<div class="'+e.cls+'">'+e.title+"</div>"},value:function(){return options.title}}),s=Backbone.View.extend({optionsDefault:{id:null,title:"","float":"right",cls:"btn-default",icon:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t='<button id="'+e.id+'" type="submit" style="margin-right: 5px; float: '+e.float+';" type="button" class="btn '+e.cls+'">';return e.icon&&(t+='<i class="icon fa '+e.icon+'"></i> '),t+=e.title+"</button>",t}}),o=Backbone.View.extend({optionsDefault:{title:"",id:null,"float":"right",cls:"icon-btn",icon:"",tooltip:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){var t="";e.title&&(t="width: auto;");var n='<div id="'+e.id+'" style="margin-right: 5px; float: '+e.float+"; "+t+'" class="'+e.cls+'">';return e.title?n+='<div style="margin-right: 5px; margin-left: 5px;"><i class="icon fa '+e.icon+'"/> '+'<span style="position: relative; font-size: 0.8em; font-weight: normal; top: -1px;">'+e.title+"</span>"+"</div>":n+='<i class="icon fa '+e.icon+'"/>',n+="</div>",n}}),u=Backbone.View.extend({optionsDefault:{"float":"right",icon:"",tooltip:"",placement:"bottom",title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).tooltip({title:t.tooltip,placement:"bottom"})},_template:function(e){return'<div><span class="fa '+e.icon+'" style="font-size: 1.2em;"/> '+e.title+"</div>"}}),a=Backbone.View.extend({optionsDefault:{title:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),$(this.el).on("click",t.onclick)},_template:function(e){return'<div><a href="javascript:void(0)">'+e.title+"</a></div>"}}),f=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:!1},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement("<div></div>")},update:function(t){this.options=e.merge(t,this.optionsDefault);if(t.message!=""){this.$el.html(this._template(this.options)),this.$el.fadeIn();if(!t.persistent){var n=this;window.setTimeout(function(){n.$el.is(":visible")?n.$el.fadeOut():n.$el.hide()},3e3)}}else this.$el.fadeOut()},_template:function(e){return'<div class="alert alert-'+e.status+'" style="padding: 2px 2px 2px 10px;">'+e.message+"</div>"}}),l=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options));var n=this;this.options.onclick&&this.$el.on("submit",function(e){var t=n.$el.find("#search");n.options.onclick(t.val())})},_template:function(e){return'<div class="search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+e.searchword+'">'+'<button type="submit" class="btn search-btn">'+'<i class="fa fa-search"></i>'+"</button>"+"</form>"+"</div>"}}),c=Backbone.View.extend({optionsDefault:{title:"Unlabeled",body:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.body&&this.$el.find(".body").append(this.options.body)},_template:function(e){return'<div id="title" class="title">'+e.title+":"+"</div>"}}),h=Backbone.View.extend({optionsDefault:{id:"",title:"",target:"",href:"",onunload:null,onclick:null,visible:!0,icon:null,tag:""},$menu:null,initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement($(this._template(this.options)));var n=$(this.el).find(".root"),r=this;n.on("click",function(e){e.preventDefault(),r.options.onclick&&r.options.onclick()}),this.options.visible||this.hide()},show:function(){$(this.el).show()},hide:function(){$(this.el).hide()},addMenu:function(t){var n={title:"",target:"",href:"",onclick:null,divider:!1,icon:null};n=e.merge(t,n),this.$menu||($(this.el).append(this._templateMenu()),this.$menu=$(this.el).find(".menu"));var r=$(this._templateMenuItem(n));r.on("click",function(e){e.preventDefault(),n.onclick&&n.onclick()}),this.$menu.append(r),n.divider&&this.$menu.append($(this._templateDivider()))},_templateMenuItem:function(e){var t='<li><a href="'+e.href+'" target="'+e.target+'">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),t+=" "+e.title+"</a>"+"</li>",t},_templateMenu:function(){return'<ul class="menu dropdown-menu pull-right" role="menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(e){var t='<div id="'+e.id+'" class="button-menu btn-group">'+'<button type="button" class="root btn btn-default dropdown-toggle" data-toggle="dropdown">';return e.icon&&(t+='<i class="fa '+e.icon+'"></i>'),"</button></div>",t}}),p=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:!1,visible:!0},initialize:function(t){this.options=e.merge(t,this.optionsDefault),this.setElement(this._template(this.options)),this.options.disabled&&this.$el.prop("disabled",!0),this.options.visible||this.$el.hide();var n=this;this.options.onchange&&this.$el.on("input",function(){n.options.onchange()})},value:function(e){return e!==undefined&&this.$el.val(e),this.$el.val()},_template:function(e){return'<input id="'+e.id+'" type="'+e.type+'" value="'+e.value+'" placeholder="'+e.placeholder+'" class="form-control">'}});return{Label:r,Image:n,Button:s,Icon:u,ButtonIcon:o,Input:p,Anchor:a,Message:f,Searchbox:l,Title:c,Text:i,Select:t,ButtonMenu:h}}),define("plugin/library/jobs",["utils/utils"],function(e){return Backbone.Model.extend({initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(e,t,n,r,i){var s=this;e.state("wait","Requesting job results...");var o=e.get("dataset_id_job");o!=""?s._wait(e,r,i):s._submit(e,t,n,r,i)},cleanup:function(t){var n=this,r=t.get("dataset_id_job");r!=""&&(e.request("PUT",config.root+"api/histories/none/contents/"+r,{deleted:!0},function(){n._refreshHdas()}),t.set("dataset_id_job",""))},_submit:function(t,n,r,i,s){var o=this,u=t.id,a=t.get("type"),f=this.app.types.get(a);data={tool_id:"charts",inputs:{input:{id:t.get("dataset_id"),src:"hda"},module:f.execute,columns:r,settings:n}},t.state("wait","Sending job request..."),e.request("POST",config.root+"api/tools",data,function(e){if(!e.outputs||e.outputs.length==0)t.state("failed","Job submission failed. No response."),s&&s();else{o._refreshHdas();var n=e.outputs[0];t.state("wait","Your job has been queued. You may close the browser window. The job will run in the background."),t.set("dataset_id_job",n.id),this.app.storage.save(),o._wait(t,i,s)}},function(e){var n="";e&&e.message&&e.message.data&&e.message.data.input&&(n=e.message.data.input+"."),t.state("failed","This visualization requires the 'charts' tool. Please make sure it is installed. "+n),s&&s()})},_wait:function(t,n,r){var i=this;e.request("GET",config.root+"api/datasets/"+t.get("dataset_id_job"),{},function(e){var s=!1;switch(e.state){case"ok":t.state("wait","Job completed successfully..."),n&&n(e),s=!0;break;case"error":t.state("failed","Job has failed. Please check the history for details."),r&&r(e),s=!0;break;case"running":t.state("wait","Your job is running. You may close the browser window. The job will continue in the background.")}s||setTimeout(function(){i._wait(t,n,r)},i.app.config.get("query_timeout"))})},_refreshHdas:function(){Galaxy&&Galaxy.currHistoryPanel&&Galaxy.currHistoryPanel.refreshContents()}})}),define("plugin/library/datasets",["utils/utils"],function(e){return Backbone.Collection.extend({list:{},cache:{},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault)},request:function(t,n,r){var i=this;if(t.groups)this._get(t,n);else{var s=this.list[t.id];if(s){n(s);return}e.request("GET",config.root+"api/datasets/"+t.id,{},function(e){switch(e.state){case"error":r&&r(e);break;default:i.list[t.id]=e,n(e)}})}},_block_id:function(e,t){return e.id+"_"+e.start+"_"+e.end+"_"+t},_get:function(e,t){e.start||(e.start=0),e.end||(e.end=this.app.config.get("query_limit"));var n=[],r={},i=0;for(var s in e.groups){var o=e.groups[s];for(var u in o.columns){var a=o.columns[u].index,f=this._block_id(e,a);if(this.cache[f])continue;!r[a]&&a!==undefined&&(r[a]=i,n.push(a),i++)}}if(n.length==0){this._fill_from_cache(e),t(e);return}var l={dataset_id:e.id,start:e.start,end:e.end,columns:n},c=this;this._fetch(l,function(r){for(var i in r){var s=n[i],o=c._block_id(e,s);c.cache[o]=r[i]}c._fill_from_cache(e),t(e)})},_fill_from_cache:function(e){console.debug("Datasets::_fill_from_cache() - Filling request from cache.");for(var t in e.groups){var n=e.groups[t];n.values=[];for(var r in n.columns){var i=n.columns[r],s=this._block_id(e,i.index),o=this.cache[s];for(k in o){var u=n.values[k];u===undefined&&(u={x:parseInt(k)+e.start},n.values[k]=u);var a=o[k];isNaN(a)&&!i.is_label&&(a=0),u[r]=a}}}},_fetch:function(t,n){var r=t.start?t.start:0,i=Math.abs(t.end-t.start),s=this.app.config.get("query_limit");if(!i||i>s)i=s;var o=0;t.columns&&(o=t.columns.length,console.debug("Datasets::_fetch() - Fetching "+o+" column(s)")),o==0&&console.debug("Datasets::_fetch() - No columns requested");var u="";for(var a in t.columns)u+=t.columns[a]+",";u=u.substring(0,u.length-1);var f=this;e.request("GET",config.root+"api/datasets/"+t.dataset_id,{data_type:"raw_data",provider:"dataset-column",limit:i,offset:r,indeces:u},function(e){var t=new Array(o);for(var r=0;r<o;r++)t[r]=[];for(var r in e.data){var i=e.data[r];for(var s in i){var u=i[s];u!==undefined&&u!=2147483647&&t[s].push(u)}}console.debug("Datasets::_fetch() - Fetching complete."),n(t)})}})}),define("plugin/models/group",[],function(){return Backbone.Model.extend({defaults:{key:"Data label",date:""},reset:function(){this.clear({silent:!0}).set(this.defaults),this.trigger("reset",this)}})}),define("plugin/models/groups",["plugin/models/group"],function(e){return Backbone.Collection.extend({model:e})}),define("plugin/library/deferred",["utils/utils"],function(e){return Backbone.Model.extend({queue:[],process:{},counter:0,initialize:function(){this.on("refresh",function(){if(this.counter==0)for(var e in this.queue)this.queue[e](),this.queue.splice(e,1)})},execute:function(e){this.queue.push(e),this.trigger("refresh")},register:function(){var t=e.uuid();return this.process[t]=!0,this.counter++,console.debug("Deferred:register() - Registering "+t),t},done:function(e){this.process[e]&&(delete this.process[e],this.counter--,console.debug("Deferred:done() - Unregistering "+e),this.trigger("refresh"))},ready:function(){return this.counter==0}})});var Visualization=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){var e="/api/visualizations";return window.galaxy_config&&galaxy_config.root?galaxy_config.root+e:e},initialize:function(e){_.isObject(e.config)&&_.isObject(this.defaults.config)&&_.defaults(e.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(e,t){if(e==="config"){var n=this.get("config");_.isObject(n)&&(t=_.extend(_.clone(n),t))}return Backbone.Model.prototype.set.call(this,e,t),this},toString:function(){var e=this.get("id")||"";return this.get("title")&&(e+=":"+this.get("title")),"Visualization("+e+")"}}),VisualizationCollection=Backbone.Collection.extend({model:Visualization,url:function(){return galaxy_config.root+"api/visualizations"},initialize:function(e,t){t=t||{}},set:function(e,t){var n=this;e=_.map(e,function(e){var t=n.get(e.id);if(!t)return e;var r=t.toJSON();return _.extend(r,e),r}),Backbone.Collection.prototype.set.call(this,e,t)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}});define("mvc/visualization/visualization-model",function(){}),define("plugin/models/chart",["plugin/models/groups","plugin/library/deferred","mvc/visualization/visualization-model"],function(e,t){return Backbone.Model.extend({defaults:{id:null,title:"",type:"",date:null,state:"",state_info:"",modified:!1,dataset_id:"",dataset_id_job:""},initialize:function(n){this.groups=new e,this.settings=new Backbone.Model,this.deferred=new t},reset:function(){this.clear({silent:!0}).set(this.defaults),this.groups.reset(),this.settings.clear(),this.trigger("reset",this)},copy:function(e){var t=this;t.clear({silent:!0}).set(this.defaults),t.set(e.attributes),t.settings=e.settings.clone(),t.groups.reset(),e.groups.each(function(e){t.groups.add(e.clone())}),t.trigger("change",t)},state:function(e,t){this.set("state",e),this.set("state_info",t),this.trigger("set:state"),console.debug("Chart:state() - "+t+" ("+e+")")}})}),define("plugin/library/storage",["utils/utils","plugin/models/chart","plugin/models/group"],function(e,t,n){return Backbone.Model.extend({vis:null,initialize:function(e){this.app=e,this.chart=this.app.chart,this.options=this.app.options,this.id=this.options.id,this.vis=new Visualization({type:"charts",config:{dataset_id:this.options.config.dataset_id,chart_dict:{}}}),this.id&&(this.vis.id=this.id);var t=this.options.config.chart_dict;t&&(this.vis.get("config").chart_dict=t)},save:function(){var e=this.app.chart;this.vis.get("config").chart_dict={};var t=e.get("title");t!=""&&this.vis.set("title",t);var n={attributes:e.attributes,settings:e.settings.attributes,groups:[]};e.groups.each(function(e){n.groups.push(e.attributes)}),this.vis.get("config").chart_dict=n;var r=this;this.vis.save().fail(function(e,t,n){console.error(e,t,n)}).then(function(e){e&&e.id&&(r.id=e.id)})},load:function(){var e=this.vis.get("config").chart_dict;if(!e.attributes)return!1;this.chart.set(e.attributes),this.chart.state("ok","Loading saved visualization..."),this.chart.settings.set(e.settings);for(var t in e.groups)this.chart.groups.add(new n(e.groups[t]));return this.chart.set("modified",!1),!0}})}),define("plugin/views/viewport",["mvc/ui/ui-portlet","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({container_list:[],canvas_list:[],initialize:function(e,t){this.app=e,this.chart=this.app.chart,this.options=n.merge(t,this.optionsDefault),this.setElement($(this._template())),this._fullscreen(this.$el,80),this._createContainer("div");var r=this;this.chart.on("redraw",function(){r._draw(r.chart)}),this.chart.on("set:state",function(){var e=r.$el.find("#info"),t=r.$el.find("container"),n=e.find("#icon");n.removeClass(),e.show(),e.find("#text").html(r.chart.get("state_info")),t.hide();var i=r.chart.get("state");switch(i){case"ok":e.hide(),t.show();break;case"failed":n.addClass("icon fa fa-warning");break;default:n.addClass("icon fa fa-spinner fa-spin")}})},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_fullscreen:function(e,t){e.css("height",$(window).height()-t),$(window).resize(function(){e.css("height",$(window).height()-t)})},_createContainer:function(e,t){t=t||1;for(var n in this.container_list)this.container_list[n].remove();this.container_list=[],this.canvas_list=[];for(var n=0;n<t;n++){var r=$(this._templateContainer(e,parseInt(100/t)));this.$el.append(r),this.container_list[n]=r,e=="svg"?this.canvas_list[n]=d3.select(r.find("#canvas")[0]):this.canvas_list[n]=r.find("#canvas")}},_draw:function(e){var t=this,n=e.deferred.register(),r=e.get("type");this.chart_settings=this.app.types.get(r);var i=this.chart_settings.use_panels,s=1;i&&(s=e.groups.length),this._createContainer(this.chart_settings.tag,s),e.state("wait","Please wait...");if(!this.chart_settings.execute||this.chart_settings.execute&&e.get("modified"))this.app.jobs.cleanup(e),e.set("modified",!1);var t=this;require(["plugin/charts/"+r+"/wrapper"],function(r){var i=new r(t.app,{canvas:t.canvas_list});t.chart_settings.execute?t.app.jobs.request(e,t._defaultSettingsString(e),t._defaultRequestString(e),function(){i.draw(n,e,t._defaultRequestDictionary(e))},function(){e.deferred.done(n)}):i.draw(n,e,t._defaultRequestDictionary(e))})},_defaultRequestString:function(e){var t="",n=0,r=this;return e.groups.each(function(e){n++;for(var i in r.chart_settings.columns)t+=i+"_"+n+":"+(parseInt(e.get(i))+1)+", "}),t.substring(0,t.length-2)},_defaultSettingsString:function(e){var t="";for(key in e.settings.attributes)t+=key+":"+e.settings.get(key)+", ";return t.substring(0,t.length-2)},_defaultRequestDictionary:function(e){var t={groups:[]};this.chart_settings.execute?t.id=e.get("dataset_id_job"):t.id=e.get("dataset_id");var n=0,r=this;return e.groups.each(function(e){var i={};for(var s in r.chart_settings.columns){var o=r.chart_settings.columns[s];i[s]={index:e.get(s),is_label:o.is_label}}t.groups.push({key:++n+":"+e.get("key"),columns:i})}),t},_template:function(){return'<div class="charts-viewport"><div id="info" class="info"><span id="icon" class="icon" /><span id="text" class="text" /></div></div>'},_templateContainer:function(e,t){return'<div class="charts-viewport-container" style="width:'+t+'%;">'+'<div id="menu"/>'+"<"+e+' id="canvas" class="charts-viewport-canvas">'+"</div>"}})}),define("plugin/views/viewer",["utils/utils","plugin/library/ui","mvc/ui/ui-portlet","plugin/models/group","plugin/views/viewport"],function(e,t,n,r,i){return Backbone.View.extend({initialize:function(e,r){this.app=e,this.chart=this.app.chart,this.viewport_view=new i(e);var s=this;this.portlet=new n.View({icon:"fa-bar-chart-o",title:"Viewport",operations:{edit_button:new t.ButtonIcon({icon:"fa-edit",tooltip:"Customize this chart",title:"Editor",onclick:function(){s._wait(s.chart,function(){s.app.go("editor")})}})}}),this.portlet.append(this.viewport_view.$el),this.setElement(this.portlet.$el);var s=this;this.chart.on("change:title",function(){s._refreshTitle()})},show:function(){this.$el.show(),$(window).trigger("resize")},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");this.portlet.title(e)},_screenshot:function(){var e=new XMLSerializer,t=e.serializeToString(this.viewport_view.svg.node()),n="data:image/svg+xml;base64,"+btoa(t);window.location.href="data:application/x-download/;charset=utf-8,"+encodeURIComponent(t)},_wait:function(e,t){if(e.deferred.ready())t();else{var n=this;this.app.modal.show({title:"Please wait!",body:"Your chart is currently being processed. Please wait and try again.",buttons:{Close:function(){n.app.modal.hide()},Retry:function(){n.app.modal.hide(),setTimeout(function(){n._wait(e,t)},n.app.config.get("query_timeout"))}}})}}})}),define("mvc/ui/ui-tabs",["utils/utils"],function(e){var t=Backbone.View.extend({visible:!1,list:{},$nav:null,$content:null,first_tab:null,optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(this.options));this.$nav=n.find(".tab-navigation"),this.$content=n.find(".tab-content"),this.setElement(n),this.list={};var r=this;this.options.operations&&$.each(this.options.operations,function(e,t){t.$el.prop("id",e),r.$nav.find(".operations").append(t.$el)});if(this.options.onnew){var i=$(this._template_tab_new(this.options));this.$nav.append(i),i.tooltip({title:"Add a new tab",placement:"bottom",container:r.$el}),i.on("click",function(e){i.tooltip("hide"),r.options.onnew()})}},add:function(e){var t=e.id,n={$title:$(this._template_tab(e)),$content:$(this._template_tab_content(e)),removable:e.ondel?!0:!1};this.list[t]=n,this.options.onnew?this.$nav.find("#new-tab").before(n.$title):this.$nav.append(n.$title),n.$content.append(e.$el),this.$content.append(n.$content),_.size(this.list)==1&&(n.$title.addClass("active"),n.$content.addClass("active"),this.first_tab=t);if(e.ondel){var r=this,i=n.$title.find("#delete");i.tooltip({title:"Delete this tab",placement:"bottom",container:r.$el}),i.on("click",function(){return i.tooltip("destroy"),r.$el.find(".tooltip").remove(),e.ondel(),!1})}e.onclick&&n.$title.on("click",function(){e.onclick()})},del:function(e){var t=this.list[e];t.$title.remove(),t.$content.remove(),delete t,this.first_tab==e&&(this.first_tab=null),this.first_tab!=null&&this.show(this.first_tab)},delRemovable:function(){for(var e in this.list){var t=this.list[e];t.removable&&this.del(e)}},show:function(e){this.$el.fadeIn("fast"),this.visible=!0,e&&this.list[e].$title.find("a").tab("show")},hide:function(){this.$el.fadeOut("fast"),this.visible=!1},hideOperation:function(e){this.$nav.find("#"+e).hide()},showOperation:function(e){this.$nav.find("#"+e).show()},setOperation:function(e,t){var n=this.$nav.find("#"+e);n.off("click"),n.on("click",t)},title:function(e,t){var n=this.list[e].$title.find("#text");return t&&n.html(t),n.html()},_template:function(e){return'<div class="tabbable tabs-left"><ul class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div class="tab-content"/></div>'},_template_tab_new:function(e){return'<li id="new-tab"><a href="javascript:void(0);"><i style="font-size: 0.8em; margin-right: 5px;" class="fa fa-plus-circle"/>'+e.title_new+"</a>"+"</li>"},_template_tab:function(e){var t='<li id="title-'+e.id+'">'+'<a title="" href="#tab-'+e.id+'" data-toggle="tab" data-original-title="">'+'<span id="text">'+e.title+"</span>";return e.ondel&&(t+='<i id="delete" style="font-size: 0.8em; margin-left: 5px; cursor: pointer;" class="fa fa-minus-circle"/>'),t+="</a></li>",t},_template_tab_content:function(e){return'<div id="tab-'+e.id+'" class="tab-pane"/>'}});return{View:t}}),define("plugin/library/ui-table",["utils/utils"],function(e){var t=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null},events:{click:"_onclick",dblclick:"_ondblclick"},first:!0,initialize:function(t){this.options=e.merge(t,this.optionsDefault);var n=$(this._template(t));this.$thead=n.find("thead"),this.$tbody=n.find("tbody"),this.$tmessage=n.find("tmessage"),this.setElement(n),this.row=$("<tr></tr>")},addHeader:function(e){var t=$("<th></th>");t.append(e),this.row.append(t)},appendHeader:function(){this.$thead.append(this.row),this.row=$("<tr></tr>")},add:function(e,t,n){var r=$("<td></td>");t&&r.css("width",t),n&&r.css("text-align",n),r.append(e),this.row.append(r)},append:function(e){this._commit(e)},prepend:function(e){this._commit(e,!0)},remove:function(e){var t=this.$tbody.find("#"+e);t.length>0&&(t.remove(),this.row_count--,this._refresh())},removeAll:function(){this.$tbody.html(""),this.row_count=0,this._refresh()},value:function(e){this.before=this.$tbody.find(".current").attr("id"),e!==undefined&&(this.$tbody.find("tr").removeClass("current"),e&&this.$tbody.find("#"+e).addClass("current"));var t=this.$tbody.find(".current").attr("id");return t===undefined?null:(t!=this.before&&this.options.onchange&&this.options.onchange(e),t)},size:function(){return this.$tbody.find("tr").length},_commit:function(e,t){this.remove(e),this.row.attr("id",e),t?this.$tbody.prepend(this.row):this.$tbody.append(this.row),this.row=$("<tr></tr>"),this.row_count++,this._refresh()},_onclick:function(e){var t=this.value(),n=$(e.target).closest("tr").attr("id");n!=""&&n&&t!=n&&(this.options.onconfirm?this.options.onconfirm(n):this.value(n))},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_refresh:function(){this.row_count==0?this.$tmessage.show():this.$tmessage.hide()},_template:function(e){return'<div><table class="grid"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+e.content+"</tmessage>"+"<div>"}});return{View:t}}),define("plugin/views/group",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(r,i){this.app=r;var s=this;this.chart=this.app.chart,this.group=i.group,this.group_key=new t.Input({placeholder:"Data label",onchange:function(){s.group.set("key",s.group_key.value())}}),this.table=new e.View({content:"No data column."});var o=$("<div/>");o.append(n.wrap((new t.Label({title:"Provide a label:"})).$el)),o.append(n.wrap(this.group_key.$el)),o.append(n.wrap((new t.Label({title:"Select columns:"})).$el)),o.append(n.wrap(this.table.$el)),this.setElement(o);var s=this;this.chart.on("change:dataset_id",function(){s._refreshTable()}),this.chart.on("change:type",function(){s._refreshTable()}),this.group.on("change:key",function(){s._refreshGroupKey()}),this.group.on("change",function(){s._refreshGroup()}),this._refreshTable(),this._refreshGroupKey(),this._refreshGroup()},_refreshTable:function(){var e=this.chart.get("dataset_id"),n=this.chart.get("type");if(!e||!n)return;var r=this,i=this.app.types.get(n);this.table.removeAll();var s={};for(var o in i.columns){var u=this.group.get(o);u||this.group.set(o,0);var a=i.columns[o],f=new t.Select.View({id:"select_"+o,gid:o,onchange:function(e){r.group.set(this.gid,e),r.chart.set("modified",!0)},value:u,wait:!0});this.table.add(a.title,"25%"),this.table.add(f.$el),this.table.append(o),s[o]=f}this.chart.state("wait","Loading metadata...");var l=this.chart.deferred.register();this.app.datasets.request({id:e},function(e){for(var t in s){var n=i.columns[t].is_label,o=[],u=e.metadata_column_types;for(var a in u)(!n&&(u[a]=="int"||u[a]=="float")||n)&&o.push({label:"Column: "+(parseInt(a)+1)+" ["+u[a]+"]",value:a});s[t].update(o),s[t].show()}r.chart.state("ok","Metadata initialized..."),r.chart.deferred.done(l)})},_refreshGroup:function(){this.group.set("date",n.time())},_refreshGroupKey:function(){var e=this.group.get("key");e===undefined&&(e=""),this.group_key.value(e)}})}),define("plugin/library/ui-table-form",["plugin/library/ui-table","plugin/library/ui","utils/utils"],function(e,t,n){var r=Backbone.View.extend({list:[],initialize:function(r){this.table_title=new t.Label({title:r.title}),this.table=new e.View({content:r.content});var i=$("<div/>");i.append(n.wrap(this.table_title.$el)),i.append(n.wrap(this.table.$el)),this.setElement(i)},title:function(e){this.table_title.title(e)},update:function(e,t){this.table.removeAll(),this.list=[];for(var n in e)this._add(n,e[n],t);for(var n in this.list){var r=this.list[n].options.onchange;r&&r()}},_add:function(e,n,r){var i=this,s=null,o=n.type;switch(o){case"text":s=new t.Input({id:e,placeholder:n.placeholder,onchange:function(){r.set(e,s.value())}});break;case"select":s=new t.Select.View({id:e,data:n.data,onchange:function(){var t=s.value();r.set(e,t);var o=_.findWhere(n.data,{value:t});o&&(o.show&&i.$el.find("#"+o.show).fadeIn("fast"),o.hide&&i.$el.find("#"+o.hide).fadeOut("fast"))}});break;case"separator":s=$("<div/>");break;default:console.log("ui-table-form:_add","Unknown setting type ("+n.type+")");return}if(o!="separator"){r.get(e)||r.set(e,n.init),s.value(r.get(e)),this.list[e]=s;var u=$("<div/>");u.append(s.$el),u.append('<div class="toolParamHelp" style="font-size: 0.9em;">'+n.info+"</div>"),this.table.add('<span style="white-space: nowrap;">'+n.title+"</span>","25%"),this.table.add(u)}else this.table.add('<h6 style="white-space: nowrap;">'+n.title+":<h6/>"),this.table.add($("<div/>"));this.table.append(e)}});return{View:r}}),define("plugin/views/settings",["plugin/library/ui","plugin/library/ui-table-form","utils/utils"],function(e,t,n){return Backbone.View.extend({initialize:function(e,n){this.app=e;var r=this;this.chart=this.app.chart,this.form=new t.View({title:"Chart options:",content:"This chart type does not provide any options."}),this.setElement(this.form.$el);var r=this;this.chart.on("change",function(){r._refreshTable()})},_refreshTable:function(){var e=this.chart.get("type");if(!e)return;var t=this.app.types.get(e);this.form.title(t.category+" - "+t.title+":"),this.form.update(t.settings,this.chart.settings)}})}),define("plugin/views/types",["utils/utils","plugin/library/ui"],function(e,t){return Backbone.View.extend({optionsDefault:{onchange:null,ondblclick:null},events:{click:"_onclick",dblclick:"_ondblclick"},initialize:function(t,n){this.app=t,this.options=e.merge(n,this.optionsDefault);var r=$('<div class="charts-grid"/>');this.setElement(r);var i={},s=t.types.attributes;for(var o in s){var u=s[o],a=u.category;i[a]||(i[a]={}),i[a][o]=u}for(var a in i){var r=$('<div style="clear: both;"/>');r.append(e.wrap(this._template_header({title:a})));for(var o in i[a]){var u=i[a][o];r.append(e.wrap(this._template_item({id:o,title:u.title,url:config.app_root+"charts/"+o+"/logo.png"})))}this.$el.append(e.wrap(r))}},value:function(e){var t=this.$el.find(".current").attr("id");e!==undefined&&(this.$el.find(".current").removeClass("current"),this.$el.find("#"+e).addClass("current"));var n=this.$el.find(".current").attr("id");return n===undefined?null:(n!=t&&this.options.onchange&&this.options.onchange(e),n)},_onclick:function(e){var t=this.value(),n=$(e.target).closest(".item").attr("id");n!=""&&n&&t!=n&&this.value(n)},_ondblclick:function(e){var t=this.value();t&&this.options.ondblclick&&this.options.ondblclick(t)},_template_header:function(e){return'<div class="header">• '+e.title+"<div>"},_template_item:function(e){return'<div id="'+e.id+'" class="item">'+'<img class="image" src="'+e.url+'">'+'<div class="title">'+e.title+"</div>"+"<div>"}})}),define("plugin/views/editor",["mvc/ui/ui-tabs","plugin/library/ui","mvc/ui/ui-portlet","utils/utils","plugin/models/chart","plugin/models/group","plugin/views/group","plugin/views/settings","plugin/views/types"],function(e,t,n,r,i,s,o,u,a){return Backbone.View.extend({optionsDefault:{header:!0,content:"No content available."},initialize:function(i,s){var o=this;this.app=i,this.chart=this.app.chart,this.options=r.merge(s,this.optionsDefault),this.portlet=new n.View({icon:"fa-bar-chart-o",title:"Editor",operations:{save:new t.ButtonIcon({icon:"fa-save",tooltip:"Draw Chart",title:"Draw",onclick:function(){o.app.go("viewer"),o._saveChart()}}),back:new t.ButtonIcon({icon:"fa-caret-left",tooltip:"Return to Viewer",title:"Return",onclick:function(){o.app.go("viewer"),o.app.storage.load()}})}}),this.types=new a(i,{onchange:function(e){o.chart.settings.clear(),o.chart.set({type:e}),o.chart.set("modified",!0)},ondblclick:function(e){o.app.go("viewer"),o._saveChart()}}),this.tabs=new e.View({title_new:"Add Data",onnew:function(){var e=o._addGroupModel();o.tabs.show(e.id)}}),this.title=new t.Input({placeholder:"Chart title",onchange:function(){o.chart.set("title",o.title.value())}});var f=$("<div/>");f.append(r.wrap((new t.Label({title:"Provide a chart title:"})).$el)),f.append(r.wrap(this.title.$el)),f.append(r.wrap((new t.Label({title:"Select a chart type:"})).$el)),f.append(r.wrap(this.types.$el)),this.tabs.add({id:"main",title:"Start",$el:f}),this.settings=new u(this.app),this.tabs.add({id:"settings",title:"Configuration",$el:this.settings.$el}),this.portlet.append(this.tabs.$el),this.setElement(this.portlet.$el),this.tabs.hideOperation("back");var o=this;this.chart.on("change:title",function(e){o._refreshTitle()}),this.chart.on("change:type",function(e){o.types.value(e.get("type"))}),this.chart.on("reset",function(e){o._resetChart()}),this.app.chart.on("redraw",function(e){o.portlet.showOperation("back")}),this.app.chart.groups.on("add",function(e){o._addGroup(e)}),this.app.chart.groups.on("remove",function(e){o._removeGroup(e)}),this.app.chart.groups.on("reset",function(e){o._removeAllGroups()}),this.app.chart.groups.on("change:key",function(e){o._refreshGroupKey()}),this._resetChart()},show:function(){this.$el.show()},hide:function(){this.$el.hide()},_refreshTitle:function(){var e=this.chart.get("title");this.portlet.title(e),this.title.value(e)},_refreshGroupKey:function(){var e=this,t=0;this.chart.groups.each(function(n){var r=n.get("key","");r==""&&(r="Chart data"),e.tabs.title(n.id,++t+": "+r)})},_addGroupModel:function(){var e=new s({id:r.uuid()});return this.chart.groups.add(e),e},_addGroup:function(e){var t=this,n=new o(this.app,{group:e}),r=t.chart.groups.length;this.tabs.add({id:e.id,$el:n.$el,ondel:function(){t.chart.groups.remove(e.id)}}),this._refreshGroupKey()},_removeGroup:function(e){this.tabs.del(e.id),this._refreshGroupKey(),this.chart.set("modified",!0)},_removeAllGroups:function(e){this.tabs.delRemovable()},_resetChart:function(){this.chart.set("id",r.uuid()),this.chart.set("type","nvd3_bar"),this.chart.set("dataset_id",this.app.options.config.dataset_id),this.chart.set("title","New Chart"),this.portlet.hideOperation("back")},_saveChart:function(){this.chart.set({type:this.types.value(),title:this.title.value(),date:r.time()}),this.chart.groups.length==0&&this._addGroupModel();var e=this;this.chart.deferred.execute(function(){e.app.storage.save(),e.chart.trigger("redraw")})}})}),define("plugin/models/config",[],function(){return Backbone.Model.extend({defaults:{query_limit:5e3,query_timeout:500}})}),define("plugin/charts/nvd3/config",[],function(){return{title:"",category:"",library:"nvd3.js",tag:"svg",columns:{y:{title:"Values for y-axis"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},x_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"auto",data:[{label:"-- Do not show values --",value:"hide",hide:"x_axis_tick"},{label:"Auto",value:"auto",hide:"x_axis_tick"},{label:"Float",value:"f",show:"x_axis_tick"},{label:"Exponent",value:"e",show:"x_axis_tick"},{label:"Integer",value:"d",hide:"x_axis_tick"},{label:"Percentage",value:"p",show:"x_axis_tick"},{label:"Rounded",value:"r",show:"x_axis_tick"},{label:"SI-prefix",value:"s",show:"x_axis_tick"}]},x_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"},y_axis_type:{title:"Axis value type",info:"Select the value type of the axis.",type:"select",init:"auto",data:[{label:"-- Do not show values --",value:"hide",hide:"y_axis_tick"},{label:"Auto",value:"auto",hide:"y_axis_tick"},{label:"Float",value:"f",show:"y_axis_tick"},{label:"Exponent",value:"e",show:"y_axis_tick"},{label:"Integer",value:"d",hide:"y_axis_tick"},{label:"Percentage",value:"p",show:"y_axis_tick"},{label:"Rounded",value:"r",show:"y_axis_tick"},{label:"SI-prefix",value:"s",show:"y_axis_tick"}]},y_axis_tick:{title:"Axis tick format",info:"Select the tick format for the axis.",type:"select",init:".1",data:[{label:"0.00001",value:".5"},{label:"0.0001",value:".4"},{label:"0.001",value:".3"},{label:"0.01",value:".2"},{label:"0.1",value:".1"},{label:"1",value:"1"}]},separator_legend:{title:"Others",type:"separator"},show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"true",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/nvd3_bar/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Regular",category:"Bar diagrams"})}),define("plugin/charts/nvd3_bar_stacked/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked",category:"Bar diagrams"})}),define("plugin/charts/nvd3_bar_horizontal/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Horizontal",category:"Bar diagrams",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/nvd3_bar_horizontal_stacked/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stacked horizontal",category:"Bar diagrams",settings:{x_axis_type:{init:"hide"}}})}),define("plugin/charts/nvd3_histogram/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram",category:"Data processing (requires 'charts' tool from Toolshed)",execute:"histogram",columns:{y:{title:"Observations"}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_type:{init:"f"},y_axis_tick:{init:".2"}}})}),define("plugin/charts/nvd3_histogram_discrete/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Histogram (discrete)",category:"Data processing (requires 'charts' tool from Toolshed)",execute:"histogramdiscrete",columns:{y:{title:"Observations",is_label:!0}},settings:{x_axis_label:{init:"Breaks"},y_axis_label:{init:"Density"},y_axis_type:{init:"f"},y_axis_tick:{init:".2"}}})}),define("plugin/charts/nvd3_line/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line chart",category:"Others"})}),define("plugin/charts/nvd3_line_focus/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Line with focus",category:"Others"})}),define("plugin/charts/nvd3_pie/config",[],function(){return{title:"Pie chart",library:"nvd3.js",category:"Area charts",tag:"svg",use_panels:!0,columns:{label:{title:"Labels",is_label:!0},y:{title:"Values"}},settings:{show_legend:{title:"Show legend",info:"Would you like to add a legend?",type:"select",init:"false",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]},donut_ratio:{title:"Donut ratio",info:"Determine how large the donut hole will be.",type:"select",init:"0.5",data:[{label:"50%",value:"0.5"},{label:"25%",value:"0.25"},{label:"10%",value:"0.10"},{label:"0%",value:"0"}]},label_separator:{type:"separator",title:"Label settings"},label_type:{title:"Donut label",info:"What would you like to show for each slice?",type:"select",init:"percent",data:[{label:"-- Nothing --",value:"hide",hide:"label_outside"},{label:"Label column",value:"key",show:"label_outside"},{label:"Value column",value:"value",show:"label_outside"},{label:"Percentage",value:"percent",show:"label_outside"}]},label_outside:{title:"Show outside",info:"Would you like to show labels outside the donut?",type:"select",init:"false",data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]}}}}),define("plugin/charts/nvd3_scatter/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Scatter plot",category:"Others",columns:{x:{title:"Values for x-axis"}}})}),define("plugin/charts/nvd3_stackedarea/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Regular",category:"Area charts"})}),define("plugin/charts/nvd3_stackedarea_full/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Expanded",category:"Area charts"})}),define("plugin/charts/nvd3_stackedarea_stream/config",["plugin/charts/nvd3/config"],function(e){return $.extend(!0,{},e,{title:"Stream",category:"Area charts"})}),define("plugin/charts/highcharts_boxplot/config",[],function(){return{title:"Box plot",category:"Data processing (requires 'charts' tool from Toolshed)",library:"highcharts.js",tag:"div",execute:"boxplot",columns:{y:{title:"Observations"}},settings:{separator_label:{title:"X axis",type:"separator"},x_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"X-axis",placeholder:"Axis label"},separator_tick:{title:"Y axis",type:"separator"},y_axis_label:{title:"Axis label",info:"Provide a label for the axis.",type:"text",init:"Y-axis",placeholder:"Axis label"}}}}),define("plugin/charts/heatmap/config",[],function(){return{title:"Heatmap",category:"Data processing (requires 'charts' tool from Toolshed)",library:"",tag:"div",use_panels:!0,execute:"heatmap",columns:{row_label:{title:"Row labels",is_label:!0},col_label:{title:"Column labels",is_label:!0},value:{title:"Observations"}},settings:{color_set:{title:"Color scheme",info:"Select a color scheme for your heatmap",type:"select",init:"ocean",data:[{label:"Cold-to-Hot",value:"hot"},{label:"Cool",value:"cool"},{label:"Copper",value:"copper"},{label:"Gebco",value:"gebco"},{label:"Globe",value:"globe"},{label:"Gray scale",value:"gray"},{label:"Haxby",value:"haxby"},{label:"Jet",value:"jet"},{label:"No-Green",value:"no_green"},{label:"Ocean",value:"ocean"},{label:"Polar",value:"polar"},{label:"Rainbow",value:"rainbow"},{label:"Red-to-Green",value:"redgreen"},{label:"Red-to-green (saturated)",value:"red2green"},{label:"Relief",value:"relief"},{label:"Seismograph",value:"seis"},{label:"Sealand",value:"sealand"},{label:"Split",value:"split"},{label:"Topo",value:"topo"},{label:"Wysiwyg",value:"wysiwyg"}]},sorting:{title:"Sorting",info:"How should the columns be clustered?",type:"select",init:"hclust",data:[{label:"Read from dataset",value:"hclust"},{label:"Sort column and row labels",value:"byboth"},{label:"Sort column labels",value:"bycolumns"},{label:"Sort by rows",value:"byrow"}]}},menu:function(){return{color_set:this.settings.color_set}}}}),define("plugin/charts/types",["plugin/charts/nvd3_bar/config","plugin/charts/nvd3_bar_stacked/config","plugin/charts/nvd3_bar_horizontal/config","plugin/charts/nvd3_bar_horizontal_stacked/config","plugin/charts/nvd3_histogram/config","plugin/charts/nvd3_histogram_discrete/config","plugin/charts/nvd3_line/config","plugin/charts/nvd3_line_focus/config","plugin/charts/nvd3_pie/config","plugin/charts/nvd3_scatter/config","plugin/charts/nvd3_stackedarea/config","plugin/charts/nvd3_stackedarea_full/config","plugin/charts/nvd3_stackedarea_stream/config","plugin/charts/highcharts_boxplot/config","plugin/charts/heatmap/config"],function(e,t,n,r,i,s,o,u,a,f,l,c,h,p,d){return Backbone.Model.extend({defaults:{nvd3_bar:e,nvd3_bar_stacked:t,nvd3_bar_horizontal:n,nvd3_bar_horizontal_stacked:r,nvd3_stackedarea:l,nvd3_stackedarea_full:c,nvd3_stackedarea_stream:h,nvd3_line:o,nvd3_line_focus:u,nvd3_scatter:f,nvd3_pie:a,nvd3_histogram:i,highcharts_boxplot:p,heatmap:d}})}),define("plugin/app",["mvc/ui/ui-modal","mvc/ui/ui-portlet","plugin/library/ui","utils/utils","plugin/library/jobs","plugin/library/datasets","plugin/library/storage","plugin/views/viewer","plugin/views/editor","plugin/models/config","plugin/models/chart","plugin/charts/types"],function(e,t,n,r,i,s,o,u,a,f,l,c){return Backbone.View.extend({initialize:function(t){this.options=t,Galaxy&&Galaxy.modal?this.modal=Galaxy.modal:this.modal=new e.View,this.config=new f,this.types=new c,this.chart=new l,this.jobs=new i(this),this.datasets=new s(this),this.storage=new o(this),this.viewer_view=new u(this),this.editor_view=new a(this),this.$el.append(this.viewer_view.$el),this.$el.append(this.editor_view.$el);if(!this.storage.load())this.go("editor");else{this.go("viewer");var n=this;this.chart.deferred.execute(function(){n.chart.trigger("redraw")})}},go:function(e){$(".tooltip").hide();switch(e){case"editor":this.editor_view.show(),this.viewer_view.hide();break;case"viewer":this.editor_view.hide(),this.viewer_view.show()}},execute:function(e){},onunload:function(){},log:function(e,t){console.log(e+" "+t)}})});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/_nvd3/config.js
--- a/config/plugins/visualizations/charts/static/charts/_nvd3/config.js
+++ /dev/null
@@ -1,218 +0,0 @@
-define([], function() {
-
-return {
- title : '',
- columns : {
- y : {
- title : 'Values for y-axis'
- }
- },
- settings : {
- separator_label : {
- title : 'X axis',
- type : 'separator'
- },
- x_axis_label : {
- title : 'Axis label',
- info : 'Provide a label for the axis.',
- type : 'text',
- init : 'X-axis',
- placeholder : 'Axis label'
- },
- x_axis_type : {
- title : 'Axis value type',
- info : 'Select the value type of the axis.',
- type : 'select',
- init : 'auto',
- data : [
- {
- label : '-- Do not show values --',
- value : 'hide',
- hide : 'x_axis_tick'
- },
- {
- label : 'Auto',
- value : 'auto',
- hide : 'x_axis_tick'
- },
- {
- label : 'Float',
- value : 'f',
- show : 'x_axis_tick'
- },
- {
- label : 'Exponent',
- value : 'e',
- show : 'x_axis_tick'
- },
- {
- label : 'Integer',
- value : 'd',
- hide : 'x_axis_tick'
- },
- {
- label : 'Percentage',
- value : 'p',
- show : 'x_axis_tick'
- },
- {
- label : 'Rounded',
- value : 'r',
- show : 'x_axis_tick'
- },
- {
- label : 'SI-prefix',
- value : 's',
- show : 'x_axis_tick'
- }
- ]
- },
- x_axis_tick : {
- title : 'Axis tick format',
- info : 'Select the tick format for the axis.',
- type : 'select',
- init : '.1',
- data : [
- {
- label : '0.00001',
- value : '.5'
- },
- {
- label : '0.0001',
- value : '.4'
- },
- {
- label : '0.001',
- value : '.3'
- },
- {
- label : '0.01',
- value : '.2'
- },
- {
- label : '0.1',
- value : '.1'
- },
- {
- label : '1',
- value : '1'
- }
- ]
-
- },
- separator_tick : {
- title : 'Y axis',
- type : 'separator'
- },
- y_axis_label : {
- title : 'Axis label',
- info : 'Provide a label for the axis.',
- type : 'text',
- init : 'Y-axis',
- placeholder : 'Axis label'
- },
- y_axis_type : {
- title : 'Axis value type',
- info : 'Select the value type of the axis.',
- type : 'select',
- init : 'auto',
- data : [
- {
- label : '-- Do not show values --',
- value : 'hide',
- hide : 'y_axis_tick'
- },
- {
- label : 'Auto',
- value : 'auto',
- hide : 'y_axis_tick'
- },
- {
- label : 'Float',
- value : 'f',
- show : 'y_axis_tick'
- },
- {
- label : 'Exponent',
- value : 'e',
- show : 'y_axis_tick'
- },
- {
- label : 'Integer',
- value : 'd',
- hide : 'y_axis_tick'
- },
- {
- label : 'Percentage',
- value : 'p',
- show : 'y_axis_tick'
- },
- {
- label : 'Rounded',
- value : 'r',
- show : 'y_axis_tick'
- },
- {
- label : 'SI-prefix',
- value : 's',
- show : 'y_axis_tick'
- }
- ]
- },
- y_axis_tick : {
- title : 'Axis tick format',
- info : 'Select the tick format for the axis.',
- type : 'select',
- init : '.1',
- data : [
- {
- label : '0.00001',
- value : '.5'
- },
- {
- label : '0.0001',
- value : '.4'
- },
- {
- label : '0.001',
- value : '.3'
- },
- {
- label : '0.01',
- value : '.2'
- },
- {
- label : '0.1',
- value : '.1'
- },
- {
- label : '1',
- value : '1'
- }
- ]
-
- },
- separator_legend : {
- title : 'Others',
- type : 'separator'
- },
- show_legend : {
- title : 'Show legend',
- info : 'Would you like to add a legend?',
- type : 'select',
- init : 'true',
- data : [
- {
- label : 'Yes',
- value : 'true'
- },
- {
- label : 'No',
- value : 'false'
- }
- ]
- },
- }
-};
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/_nvd3/nvd3.js
--- a/config/plugins/visualizations/charts/static/charts/_nvd3/nvd3.js
+++ /dev/null
@@ -1,80 +0,0 @@
-// dependencies
-define([], function() {
-
-// widget
-return Backbone.View.extend(
-{
- // initialize
- initialize: function(app, options) {
- this.app = app;
- this.options = options;
- },
-
- // render
- draw : function(process_id, nvd3_model, chart, request_dictionary, callback)
- {
- // request data
- var self = this;
- this.app.datasets.request(request_dictionary, function(data) {
- nv.addGraph(function() {
- // x axis
- self._axis(nvd3_model.xAxis, chart.settings.get('x_axis_type'), chart.settings.get('x_axis_tick'));
-
- // x axis label
- nvd3_model.xAxis.axisLabel(chart.settings.get('x_axis_label'));
-
- // y axis
- self._axis(nvd3_model.yAxis, chart.settings.get('y_axis_type'), chart.settings.get('y_axis_tick'));
-
- // y axis label
- nvd3_model.yAxis.axisLabel(chart.settings.get('y_axis_label'))
- .axisLabelDistance(30);
-
- // controls
- if (chart.groups.length == 1) {
- nvd3_model.options({ showControls: false });
- }
-
- // legend
- var legend_visible = true;
- if (chart.settings.get('show_legend') == 'false') {
- legend_visible = false;
- }
- nvd3_model.showLegend(legend_visible);
-
- // custom callback
- if (callback) {
- callback(nvd3_model);
- }
-
- // parse data to svg
- self.options.svg.datum(data)
- .call(nvd3_model);
-
- // refresh on window resize
- nv.utils.windowResize(nvd3_model.update);
-
- // set chart state
- chart.state('ok', 'Chart has been drawn.');
-
- // unregister process
- chart.deferred.done(process_id);
- });
- });
- },
-
- // make axis
- _axis: function(axis, type, tick) {
- switch (type) {
- case 'hide':
- axis.tickFormat(function() { return '' });
- break;
- case 'auto':
- break;
- default:
- axis.tickFormat(d3.format(tick + type));
- }
- }
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/bardiagram/bardiagram.js
--- a/config/plugins/visualizations/charts/static/charts/bardiagram/bardiagram.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// dependencies
-define(['plugin/charts/_nvd3/nvd3'], function(NVD3) {
-
-// widget
-return Backbone.View.extend(
-{
- // initialize
- initialize: function(app, options) {
- this.app = app;
- this.options = options;
- },
-
- // render
- draw : function(process_id, chart, request_dictionary)
- {
- var nvd3 = new NVD3(this.app, this.options);
- nvd3.draw(process_id, nv.models.multiBarChart(), chart, request_dictionary);
- }
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/bardiagram/config.js
--- a/config/plugins/visualizations/charts/static/charts/bardiagram/config.js
+++ /dev/null
@@ -1,7 +0,0 @@
-define(['plugin/charts/_nvd3/config'], function(nvd3_config) {
-
-return $.extend(true, {}, nvd3_config, {
- title : 'Bar diagram',
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/heatmap/config.js
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/charts/heatmap/config.js
@@ -0,0 +1,195 @@
+define([], function() {
+
+return {
+ title : 'Heatmap',
+ category : 'Data processing (requires \'charts\' tool from Toolshed)',
+ library : '',
+ tag : 'div',
+ use_panels : true,
+ execute : 'heatmap',
+
+ // columns
+ columns : {
+ row_label : {
+ title : 'Row labels',
+ is_label : true
+ },
+ col_label : {
+ title : 'Column labels',
+ is_label : true
+ },
+ value : {
+ title : 'Observations'
+ },
+ },
+
+ // settings
+ settings: {
+ /*limit : {
+ title : 'Limit',
+ info : 'Which to ranked clusters would you like to visualize',
+ type : 'select',
+ init : '20',
+ data : [
+ {
+ label : '20',
+ value : '20'
+ },
+ {
+ label : '30',
+ value : '30'
+ },
+ {
+ label : '40',
+ value : '40'
+ },
+ {
+ label : '50',
+ value : '50'
+ },
+ {
+ label : '60',
+ value : '60'
+ },
+ {
+ label : '70',
+ value : '70'
+ },
+ {
+ label : '80',
+ value : '80'
+ },
+ {
+ label : '90',
+ value : '90'
+ },
+ {
+ label : '100',
+ value : '100'
+ }
+ ]
+ },*/
+ color_set : {
+ title : 'Color scheme',
+ info : 'Select a color scheme for your heatmap',
+ type : 'select',
+ init : 'ocean',
+ data : [
+ {
+ label : 'Cold-to-Hot',
+ value : 'hot'
+ },
+ {
+ label : 'Cool',
+ value : 'cool'
+ },
+ {
+ label : 'Copper',
+ value : 'copper'
+ },
+ {
+ label : 'Gebco',
+ value : 'gebco'
+ },
+ {
+ label : 'Globe',
+ value : 'globe'
+ },
+ {
+ label : 'Gray scale',
+ value : 'gray'
+ },
+ {
+ label : 'Haxby',
+ value : 'haxby'
+ },
+ {
+ label : 'Jet',
+ value : 'jet'
+ },
+ {
+ label : 'No-Green',
+ value : 'no_green'
+ },
+ {
+ label : 'Ocean',
+ value : 'ocean'
+ },
+ {
+ label : 'Polar',
+ value : 'polar'
+ },
+ {
+ label : 'Rainbow',
+ value : 'rainbow'
+ },
+ {
+ label : 'Red-to-Green',
+ value : 'redgreen'
+ },
+ {
+ label : 'Red-to-green (saturated)',
+ value : 'red2green'
+ },
+ {
+ label : 'Relief',
+ value : 'relief'
+ },
+ {
+ label : 'Seismograph',
+ value : 'seis'
+ },
+ {
+ label : 'Sealand',
+ value : 'sealand'
+ },
+ {
+ label : 'Split',
+ value : 'split'
+ },
+ {
+ label : 'Topo',
+ value : 'topo'
+ },
+ {
+ label : 'Wysiwyg',
+ value : 'wysiwyg'
+ }
+ ]
+ },
+
+ sorting : {
+ title : 'Sorting',
+ info : 'How should the columns be clustered?',
+ type : 'select',
+ init : 'hclust',
+ data : [
+ {
+ label : 'Read from dataset',
+ value : 'hclust'
+ },
+ {
+ label : 'Sort column and row labels',
+ value : 'byboth'
+ },
+ {
+ label : 'Sort column labels',
+ value : 'bycolumns'
+ },
+ {
+ label : 'Sort by rows',
+ value : 'byrow'
+ }
+ ]
+ }
+ },
+
+ // menu definition
+ menu : function() {
+ return {
+ color_set : this.settings.color_set
+ }
+ }
+};
+
+});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/heatmap/heatmap-parameters.js
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/charts/heatmap/heatmap-parameters.js
@@ -0,0 +1,52 @@
+// dependencies
+define(['utils/utils', 'plugin/charts/heatmap/heatmap-plugin'], function(Utils, HeatmapPlugin) {
+
+// color palettes
+var colorSets = {
+ seis: ['#AA0000', '#D00000', '#F70000', '#FF1D00', '#FF4400', '#FF6A00', '#FF9000', '#FFB700', '#FFDD00', '#FFFF00', '#FFFF00', '#FFFF00', '#BDFF0C', '#73FF1A', '#3FFA36', '#16F45A', '#00D08B', '#0087CD', '#0048FA', '#0024E3'],
+
+ sealand: ['#8C66FF', '#6A66FF', '#6684FF', '#66A7FF', '#66CAFF', '#66ECFF', '#66FFF0', '#66FFCE', '#66FFAB', '#66FF88', '#66FF66', '#88FF66', '#ABFF66', '#CEFF66', '#FFEEA6', '#FFD3A6', '#FFB8A6', '#FFAAB0', '#FFB5CB', '#FFC0E1'],
+
+ redgreen: ['#005824', '#1A693B', '#347B53', '#4F8D6B', '#699F83', '#83B09B', '#9EC2B3', '#B8D4CB', '#D2E6E3', '#EDF8FB', '#FFFFFF', '#F1EEF6', '#E6D3E1','#DBB9CD', '#D19EB9', '#C684A4', '#BB6990', '#B14F7C', '#A63467', '#9B1A53', '#91003F'],
+
+ ocean: ['#000000', '#000209', '#000413', '#00061E', '#000728', '#000932', '#002650', '#00426E', '#005E8C', '#007AAA', '#0096C8', '#22A9C2', '#45BCBB', '#67CFB5', '#8AE2AE', '#ACF6A8', '#BCF8B9', '#CBF9CA', '#DBFBDC', '#EBFDED'],
+
+ cool: ['#00FFFF', '#0DF2FF', '#19E6FF', '#26D9FF', '#33CCFF', '#3FBFFF', '#4CB3FF', '#59A6FF', '#6699FF', '#738CFF', '#7F7FFF', '#8C73FF', '#9966FF', '#A659FF', '#B24DFF', '#BF3FFF', '#CC33FF', '#D926FF', '#E619FF', '#F20DFF'],
+
+ copper: ['#000000', '#100906', '#1F130D', '#301E13', '#40281A', '#50321F', '#603C26', '#70462D', '#805033', '#905A3A', '#A06440', '#B06E46', '#C0784D', '#D08253', '#E08C5A', '#F09660', '#FFA066', '#FFAA6D', '#FFB473', '#FFBE7A'],
+
+ gebco: ['#00F0FF', '#00F0FF', '#00F0FF', '#23FFFF', '#23FFFF', '#23FFFF', '#5AFFFF', '#5AFFFF', '#5AFFFF', '#8CFFE6', '#8CFFE6', '#8CFFE6', '#A5FFD7', '#A5FFD7', '#A5FFD7', '#C3FFD7', '#C3FFD7', '#C3FFD7', '#D2FFD7', '#E6FFF0'],
+
+ globe: ['#9900FF', '#9900FF', '#7722FF', '#5544FF', '#3366FF', '#1188FF', '#1BA4FF', '#51BAFF', '#86D0FF', '#BCE6FF', '#336600', '#F3CA89', '#D9A627', '#A49019', '#9F7B0D', '#996600', '#B27676', '#C2B0B0', '#E5E5E5', '#FFFFFF'],
+
+ gray: ['#000000', '#0D0D0D', '#191919', '#262626', '#333333', '#3F3F3F', '#4C4C4C', '#595959', '#666666', '#737373', '#7F7F7F', '#8C8C8C', '#999999', '#A6A6A6', '#B2B2B2', '#BFBFBF', '#CCCCCC', '#D9D9D9', '#E6E6E6', '#F2F2F2'],
+
+ haxby: ['#090079', '#280096', '#0009C8', '#0019D4', '#1A66F0', '#19AFFF', '#32BEFF', '#61E1F0', '#6AECE1', '#8AECAE', '#CDFFA2', '#DFF68D', '#F8D768', '#FFBD57', '#F4754B', '#FF5A5A', '#FF7C7C', '#F6B3AE', '#FFC4C4', '#FFECEC'],
+
+ hot: ['#000000', '#220000', '#440000', '#660000', '#880000', '#AA0000', '#CC0000', '#EE0000', '#FF1100', '#FF3300', '#FF5500', '#FF7700', '#FF9900', '#FFBB00', '#FFDD00', '#FFFF00', '#FFFF33', '#FFFF66', '#FFFF99', '#FFFFCC'],
+
+ jet: ['#00007F', '#0000B2', '#0000E5', '#0019FF', '#004DFF', '#007FFF', '#00B2FF', '#00E5FF', '#FFFFF2', '#FFFFD9', '#FFFFBF', '#FFFFA5', '#FFFF8C', '#FFE500', '#FFB300', '#FF7F00', '#FF4C00', '#FF1900', '#E50000', '#B20000'],
+
+ no_green: ['#1F60FF', '#1F60FF', '#1F9FFF', '#1FBFFF', '#00CFFF', '#2AFFFF', '#2AFFFF', '#55FFFF', '#7FFFFF', '#AAFFFF', '#FFFF54', '#FFFF54', '#FFF000', '#FFBF00', '#FFA800', '#FF8A00', '#FF8A00', '#FF7000', '#FF4D00', '#FF0000'],
+
+ polar: ['#0000FF', '#1919FF', '#3333FF', '#4C4CFF', '#6666FF', '#7F7FFF', '#9999FF', '#B2B2FF', '#CCCCFF', '#E6E6FF', '#FFFFFF', '#FFE5E5', '#FFCCCC', '#FFB2B2', '#FF9999', '#FF7F7F', '#FF6666', '#FF4C4C', '#FF3333', '#FF1A1A'],
+
+ rainbow: ['#FF00FF', '#BF00FF', '#7F00FF', '#3F00FF', '#0000FF', '#003FFF', '#007FFF', '#00BFFF', '#00FFFF', '#00FFBF', '#00FF7F', '#00FF3F', '#00FF00', '#3FFF00', '#7FFF00', '#BFFF00', '#FFFF00', '#FFBF00', '#FF7F00', '#FF3F00'],
+
+ red2green: ['#FF0000', '#FF1919', '#FF3333', '#FF4C4C', '#FF6666', '#FF7F7F', '#FF9999', '#FFB2B2', '#FFCCCC', '#FFE6E6', '#FFFFFF', '#E5FFE5', '#CCFFCC', '#B2FFB2', '#99FF99', '#7FFF7F', '#66FF66', '#4CFF4C', '#33FF33', '#1AFF1A'],
+
+ relief: ['#000000', '#000413', '#000728', '#002650', '#005E8C', '#0096C8', '#45BCBB', '#8AE2AE', '#BCF8B9', '#DBFBDC', '#467832', '#887438', '#B19D48', '#DBC758', '#FAE769', '#FAEB7E', '#FCED93', '#FCF1A7', '#FCF6C1', '#FDFAE0'],
+
+ split: ['#7F7FFF', '#6666E6', '#4D4DCC', '#3333B3', '#1A1A99', '#00007F', '#000066', '#00004D', '#000033', '#00001A', '#000000', '#1A0000', '#330000', '#4D0000', '#660000', '#7F0000', '#991A1A', '#B33333', '#CC4D4D', '#E66666'],
+
+ topo: ['#C977D9', '#A18AE6', '#8AA2E6', '#8BD1E7', '#8AF3CF', '#85F38E', '#BDF385', '#EDE485', '#F0B086', '#DE9F8B', '#74A3B3', '#99CC70', '#DCD68E', '#EDDFAD', '#F7E8CA', '#FFF9F3', '#FFF9F6', '#FFFBF9', '#FFFCFA', '#FFFEFD'],
+
+ wysiwyg: ['#3F003F', '#3F003F', '#3F00BF', '#003FFF', '#00A0FF', '#3FBFFF', '#3FBFFF', '#40E0FF', '#3FFFBF', '#3FFF3F', '#7FFF3F', '#BFFF3F', '#BFFF3F', '#FFE040', '#FFE040', '#FF6040', '#FF1F40', '#FF60C0', '#FFA0FF', '#FFA0FF']
+}
+
+// return
+return {
+ colorSets: colorSets
+}
+
+});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/heatmap/heatmap-plugin.js
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/charts/heatmap/heatmap-plugin.js
@@ -0,0 +1,739 @@
+// dependencies
+define(['utils/utils'],
+function(Utils) {
+
+// widget
+return Backbone.View.extend(
+{
+ // number of columns and rows
+ colNumber: 0,
+ rowNumber: 0,
+
+ // indices
+ rowIndex: [],
+ colIndex: [],
+
+ // labels
+ rowLabel: [],
+ colLabel: [],
+
+ // cell size
+ cellSize: 0,
+
+ // font size
+ fontSize: 0,
+
+ // color buckets
+ nColors: 0,
+
+ // margins as cells
+ margin : {
+ top : 5,
+ right : 5,
+ bottom : 5,
+ left : 5
+ },
+
+ // default settings
+ optionsDefault: {
+ title : '',
+ pace : 1000,
+ },
+
+ // initialize
+ initialize: function(options) {
+ // link this
+ var self = this;
+
+ // load options
+ this.options = Utils.merge(options, this.optionsDefault)
+
+ // check requirements
+ if (!this.options.data || !this.options.div || !this.options.colors) {
+ console.debug('FAILED - HeatMapPlugin::initialize() - Parameters (container and/or data and/or colors) missing.');
+ return;
+ }
+
+ // link data
+ this.data = this.options.data;
+
+ // set element
+ this.setElement(this.options.div);
+
+ //
+ // data indexing
+ //
+
+ // labels (in alphabetical order)
+ this.rowLabel = [];
+ this.colLabel = [];
+
+ // index (order from original dataset)
+ this.rowIndex = [];
+ this.colIndex = [];
+
+ // unique keys (key indices are unique per label and indicate the labels rank in the alphabetical sorting)
+ this.colRank = {};
+ this.rowRank = {};
+
+ //
+ // identify and parse labels
+ //
+ for (var i in this.data) {
+ var cell = this.data[i];
+
+ // add label to index list
+ var col_label = cell.col_label;
+ if (this.colRank[col_label] === undefined) {
+ this.colRank[col_label] = true;
+ this.colLabel.push(col_label);
+ this.colIndex.push(col_label);
+ }
+ var row_label = cell.row_label;
+ if (this.rowRank[row_label] === undefined) {
+ this.rowRank[row_label] = true;
+ this.rowLabel.push(row_label);
+ this.rowIndex.push(row_label);
+ }
+ }
+
+ //
+ // sort labels and update rank dictionary
+ //
+
+ // set sizes
+ this.rowNumber = this.rowLabel.length
+ this.colNumber = this.colLabel.length
+
+ // sort labels alphabetical
+ this.rowLabel.sort();
+ this.colLabel.sort();
+
+ // generate sorted key list for rows
+ for (var i in this.rowLabel) {
+ var row_label = this.rowLabel[i];
+ var row = parseInt(i);
+ this.rowRank[row_label] = row;
+ }
+
+ // generate sorted key list for columns
+ for (var i in this.colLabel) {
+ var col_label = this.colLabel[i];
+ var col = parseInt(i);
+ this.colRank[col_label] = col;
+ }
+
+ //
+ // parse indexing from rank dictionary to cells
+ //
+
+ // min/max
+ this.max = undefined;
+ this.min = undefined
+
+ // add indices to data
+ for (var i in this.data) {
+ // get cell data
+ var cell = this.data[i];
+
+ // add rank
+ cell.col = this.colRank[cell.col_label];
+ cell.row = this.rowRank[cell.row_label];
+
+ // identify max/min values
+ if (this.min == undefined || this.min > cell.value) {
+ this.min = cell.value;
+ }
+ if (this.max == undefined || this.max < cell.value) {
+ this.max = cell.value;
+ }
+ }
+
+ //
+ // translate original create cluster from order in original data
+ //
+
+ // generate sorted key list for columns
+ for (var i in this.colIndex) {
+ this.colIndex[i] = this.colRank[this.colIndex[i]];
+ }
+ // generate sorted key list for columns
+ for (var i in this.rowIndex) {
+ this.rowIndex[i] = this.rowRank[this.rowIndex[i]];
+ }
+
+ // middle
+ this.mid = (this.max + this.min) / 2;
+
+ //
+ // set colors
+ //
+
+ // identify buckets
+ this.nColors = this.options.colors.length;
+
+ // color scale
+ this.colorScale = d3.scale.quantile()
+ .domain([this.min, this.mid, this.max])
+ .range(this.options.colors);
+
+ //
+ // add ui elements
+ //
+ // create tooltip
+ this.$tooltip = $(this._templateTooltip());
+ this.$el.append(this.$tooltip);
+
+ //
+ // finally draw the heatmap
+ //
+ this._build();
+
+ // catch window resize event
+ $(window).resize(function () {
+ self._build();
+ });
+ },
+
+ _build: function() {
+ // link this
+ var self = this;
+
+ // container (full draw area)
+ this.widthContainer = this.$el.width();
+ this.heightContainer = this.$el.height();
+
+ // get grid dimensions
+ this.width = this.widthContainer;
+ this.height = this.heightContainer;
+
+ // calculate cell size
+ this.cellSize = Math.min(((this.height) / (this.rowNumber + this.margin.top + this.margin.bottom)),
+ (this.width / (this.colNumber + this.margin.left + this.margin.right)));
+
+ // set font size
+ this.fontSize = Math.min(this.cellSize, 16);
+
+ // set width/height for plugin
+ this.width = this.cellSize * this.colNumber;
+ this.height = this.cellSize * this.rowNumber;
+
+ // get dimensions
+ var margin = this.options.margin;
+ var width = this.width;
+ var height = this.height;
+
+ // reset svg
+ if (this.svg !== undefined) {
+ this.$el.find('svg').remove();
+ }
+
+ // add main group and translate
+ this.svg = d3.select(this.$el[0]).append('svg')
+ .append('g')
+ .attr('transform', 'translate(' + (this.widthContainer - width) / 2 + ',' +
+ (this.heightContainer - height) / 2 + ')');
+
+ // reset sorting
+ this.rowSortOrder = false;
+ this.colSortOrder = false;
+
+ // build
+ this.d3RowLabels = this._buildRowLabels();
+ this.d3ColLabels = this._buildColLabels();
+ this.d3HeatMap = this._buildHeatMap();
+ this.d3Legend = this._buildLegend();
+ this.d3Title = this._buildTitle();
+ },
+
+ // build title
+ _buildTitle: function() {
+ // link this
+ var self = this;
+
+ // gather data
+ var height = this.height;
+ var width = this.width;
+ var cellSize = this.cellSize;
+ var fontSize = this.fontSize;
+ var title = this.options.title;
+
+ // add title
+ return this.svg.append('g')
+ .append('text')
+ .attr('x', width / 2)
+ .attr('y', height + 3 * cellSize + fontSize + 3)
+ .attr('text-anchor', 'middle')
+ .text(title);
+ },
+
+ // build legend
+ _buildLegend: function() {
+ // link this
+ var self = this;
+
+ // gather data
+ var cellSize = this.cellSize;
+ var fontSize = this.fontSize;
+ var height = this.height;
+ var legendCellWidth = this.width / this.nColors;
+
+ // create range labels
+ var dataRange = [];
+ for(var i = 0; i < this.nColors; i++) {
+ dataRange.push('');
+ }
+
+ // prepare indices
+ var dataRangeMin = 0;
+ var dataRangeMid = parseInt((dataRange.length - 1) / 2);
+ var dataRangeMax = dataRange.length - 1;
+
+ // add labels
+ dataRange[dataRangeMin] = this.min;
+ dataRange[dataRangeMid] = this.mid;
+ dataRange[dataRangeMax] = this.max;
+
+ // create legend
+ var legend = this.svg.selectAll('.legend')
+ .data(dataRange)
+ .enter().append('g')
+ .attr('class', 'legend');
+
+ // add boxes
+ legend.append('rect')
+ .attr('x', function(d, i) {
+ return legendCellWidth * i;
+ })
+ .attr('y', height + cellSize)
+ .attr('width', legendCellWidth)
+ .attr('height', cellSize)
+ .style('fill', function(d, i) {
+ return self.options.colors[i];
+ });
+
+ // add text
+ legend.append('text')
+ .attr('class', 'mono')
+ .text(function(d) {
+ return d;
+ })
+ .attr('width', legendCellWidth)
+ .attr('x', function(d, i) {
+ return legendCellWidth * i;
+ })
+ .attr('y', height + cellSize - 3)
+ .style('font-size', fontSize + 'px');
+
+ // return
+ return legend;
+ },
+
+ // build column labels
+ _buildColLabels: function() {
+ // link this
+ var self = this;
+
+ // gather data
+ var cellSize = this.cellSize;
+ var fontSize = this.fontSize;
+ var colIndex = this.colIndex;
+ var colLabel = this.colLabel;
+
+ // column labels
+ var colLabels = this.svg.append('g')
+ .selectAll('.colLabelg')
+ .data(colLabel)
+ .enter()
+ .append('text')
+ .text(function (d) {
+ return d;
+ })
+ .attr('x', 0)
+ .attr('y', function (d, i) {
+ return colIndex.indexOf(i) * cellSize;
+ })
+ .style('font-size', fontSize + 'px')
+ .style('text-anchor', 'left')
+ .attr('transform', 'translate(' + cellSize / 2 + ', -17) rotate (-90)')
+ .attr('class', function (d, i) {
+ return 'colLabel mono c' + i;
+ })
+ .on('mouseover', function(d) {
+ d3.select(this).classed('text-hover',true);
+ })
+ .on('mouseout' , function(d) {
+ d3.select(this).classed('text-hover',false);
+ })
+ .on('click', function(d, i) {
+ self.colSortOrder=!self.colSortOrder;
+ self._sortByLabel('c', 'row', self.rowNumber, i, self.colSortOrder);
+ d3.select('#order').property('selectedIndex', 4).node().focus();
+ });
+
+ // return
+ return colLabels;
+ },
+
+ // build row labels
+ _buildRowLabels: function() {
+ // link this
+ var self = this;
+
+ // gather data
+ var cellSize = this.cellSize;
+ var fontSize = this.fontSize;
+ var rowIndex = this.rowIndex;
+ var rowLabel = this.rowLabel;
+
+ // draw labels
+ var rowLabels = this.svg.append('g')
+ .selectAll('.rowLabelg')
+ .data(rowLabel)
+ .enter()
+ .append('text')
+ .text(function (d) {
+ return d;
+ })
+ .attr('x', 0)
+ .attr('y', function (d, i) {
+ return rowIndex.indexOf(i) * cellSize;
+ })
+ .style('font-size', fontSize + 'px')
+ .style('text-anchor', 'end')
+ .attr('transform', 'translate(-10,' + cellSize / 1.5 + ')')
+ .attr('class', function (d, i) {
+ return 'rowLabel mono r' + i;
+ } )
+ .on('mouseover', function(d) {
+ d3.select(this).classed('text-hover',true);
+ })
+ .on('mouseout' , function(d) {
+ d3.select(this).classed('text-hover',false);
+ })
+ .on('click', function(d, i) {
+ self.rowSortOrder=!self.rowSortOrder;
+ self._sortByLabel('r', 'col', self.colNumber, i, self.rowSortOrder);
+ d3.select('#order').property('selectedIndex', 4).node().focus();
+ });
+
+ // return
+ return rowLabels;
+ },
+
+ // build heat map
+ _buildHeatMap: function() {
+ // link this
+ var self = this;
+
+ // gather data
+ var cellSize = this.cellSize;
+ var rowIndex = this.rowIndex;
+ var rowLabel = this.rowLabel;
+ var colIndex = this.colIndex;
+ var colLabel = this.colLabel;
+
+ // heat map
+ var heatmap = this.svg.append('g').attr('class','g3')
+ .selectAll('.cellg')
+ .data(self.data, function(d) {
+ return d.row + ':' + d.col;
+ })
+ .enter()
+ .append('rect')
+ .attr('x', function(d) {
+ return colIndex.indexOf(d.col) * cellSize;
+ })
+ .attr('y', function(d) {
+ return rowIndex.indexOf(d.row) * cellSize;
+ })
+ .attr('class', function(d){
+ return 'cell cell-border cr' + d.row + ' cc' + d.col;
+ })
+ .attr('width', cellSize)
+ .attr('height', cellSize)
+ .style('fill', function(d) {
+ return self.colorScale(d.value);
+ })
+ .on('mouseover', function(d){
+ // highlight text
+ d3.select(this).classed('cell-hover',true);
+ d3.selectAll('.rowLabel').classed('text-highlight',function(r,ri){ return ri==(d.row);});
+ d3.selectAll('.colLabel').classed('text-highlight',function(c,ci){ return ci==(d.col);});
+
+ // update the tooltip position and value
+ d3.select('#heatmap-tooltip')
+ .style('left', (d3.event.pageX+10) + 'px')
+ .style('top', (d3.event.pageY-10) + 'px')
+ .select('#value')
+ .text('Label: ' + rowLabel[d.row] + ' | ' + colLabel[d.col] + ', Value: ' + d.value);
+ // show the tooltip
+ d3.select('#heatmap-tooltip').classed('hidden', false);
+ })
+ .on('mouseout', function(){
+ d3.select(this).classed('cell-hover',false);
+ d3.selectAll('.rowLabel').classed('text-highlight',false);
+ d3.selectAll('.colLabel').classed('text-highlight',false);
+ d3.select('#heatmap-tooltip').classed('hidden', true);
+ });
+
+ // return
+ return heatmap;
+ },
+
+ // change ordering of cells
+ _sortByLabel: function(rORc, rowORcol, n, index, sortOrder) {
+ // get cell size
+ var cellSize = this.cellSize;
+
+ // define transition / prepare element
+ var t = this.svg.transition().duration(this.options.pace);
+
+ // create cells
+ var cells=[];
+ for (var i = 0; i < n; i++) {
+ cells[i] = {
+ value: this.min - 1
+ }
+ cells[i][rowORcol] = i;
+ }
+
+ // collect cells
+ t.selectAll('.c' + rORc + index).filter(function(ce) {
+ cells[ce[rowORcol]].value = ce.value;
+ });
+
+ // sort cells
+ cells.sort(function(a, b) {
+ if (sortOrder) {
+ return b.value - a.value;
+ } else {
+ return a.value - b.value;
+ }
+ });
+
+ // get sorted key list
+ var sorted = [];
+ for (var i in cells) {
+ sorted.push(cells[i][rowORcol]);
+ }
+
+ // rows or columns
+ if(rORc == 'r') {
+ // sort cells
+ t.selectAll('.cell')
+ .attr('x', function(d) {
+ return sorted.indexOf(d.col) * cellSize;
+ });
+
+ // sort labels
+ t.selectAll('.colLabel')
+ .attr('y', function (d, i) {
+ return sorted.indexOf(i) * cellSize;
+ });
+ } else {
+ // sort cells
+ t.selectAll('.cell')
+ .attr('y', function(d) {
+ return sorted.indexOf(d.row) * cellSize;
+ });
+
+ // sort labels
+ t.selectAll('.rowLabel')
+ .attr('y', function (d, i) {
+ return sorted.indexOf(i) * cellSize;
+ });
+ }
+ },
+
+ // sort function
+ _sortByOrder: function (value) {
+ // link this
+ var self = this;
+
+ // gather data
+ var cellSize = this.cellSize;
+ var rowIndex = this.rowIndex;
+ var rowLabel = this.rowLabel;
+ var colIndex = this.colIndex;
+ var colLabel = this.colLabel;
+
+ // set duration / select element
+ var t = this.svg.transition().duration(this.options.pace);
+ if(value=='hclust'){
+ t.selectAll('.cell')
+ .attr('x', function(d) {
+ return colIndex.indexOf(d.col) * cellSize;
+ })
+ .attr('y', function(d) {
+ return rowIndex.indexOf(d.row) * cellSize;
+ });
+
+ t.selectAll('.rowLabel')
+ .attr('y', function(d, i) {
+ return rowIndex.indexOf(i) * cellSize;
+ });
+
+ t.selectAll('.colLabel')
+ .attr('y', function(d, i) {
+ return colIndex.indexOf(i) * cellSize;
+ });
+
+ } else if (value=='byboth') {
+ t.selectAll('.cell')
+ .attr('x', function(d) {
+ return d.col * cellSize;
+ })
+ .attr('y', function(d) {
+ return d.row * cellSize;
+ });
+
+ t.selectAll('.rowLabel')
+ .attr('y', function (d, i) {
+ return i * cellSize;
+ });
+
+ t.selectAll('.colLabel')
+ .attr('y', function (d, i) {
+ return i * cellSize;
+ });
+ } else if (value=='byrow') {
+ t.selectAll('.cell')
+ .attr('y', function(d) {
+ return d.row * cellSize;
+ });
+
+ t.selectAll('.rowLabel')
+ .attr('y', function (d, i) {
+ return i * cellSize;
+ });
+ } else if (value=='bycol'){
+ t.selectAll('.cell')
+ .attr('x', function(d) {
+ return d.col * cellSize;
+ });
+ t.selectAll('.colLabel')
+ .attr('y', function (d, i) {
+ return i * cellSize;
+ });
+ }
+ },
+
+ // selection of cells
+ _addSelectionTool: function() {
+ //
+ // selection
+ //
+ var sa=d3.select('.g3')
+ .on('mousedown', function() {
+ if( !d3.event.altKey) {
+ d3.selectAll('.cell-selected').classed('cell-selected', false);
+ d3.selectAll('.rowLabel').classed('text-selected', false);
+ d3.selectAll('.colLabel').classed('text-selected', false);
+ }
+ var p = d3.mouse(this);
+ sa.append('rect')
+ .attr({
+ rx : 0,
+ ry : 0,
+ class : 'selection',
+ x : p[0],
+ y : p[1],
+ width : 1,
+ height : 1
+ })
+ })
+ .on('mousemove', function() {
+ var s = sa.select('rect.selection');
+
+ if(!s.empty()) {
+ var p = d3.mouse(this),
+ d = {
+ x : parseInt(s.attr('x'), 10),
+ y : parseInt(s.attr('y'), 10),
+ width : parseInt(s.attr('width'), 10),
+ height : parseInt(s.attr('height'), 10)
+ },
+ move = {
+ x : p[0] - d.x,
+ y : p[1] - d.y
+ };
+
+ if(move.x < 1 || (move.x*2<d.width)) {
+ d.x = p[0];
+ d.width -= move.x;
+ } else {
+ d.width = move.x;
+ }
+
+ if(move.y < 1 || (move.y*2<d.height)) {
+ d.y = p[1];
+ d.height -= move.y;
+ } else {
+ d.height = move.y;
+ }
+ s.attr(d);
+
+ // deselect all temporary selected state objects
+ d3.selectAll('.cell-selection.cell-selected').classed('cell-selected', false);
+ d3.selectAll('.text-selection.text-selected').classed('text-selected',false);
+ d3.selectAll('.cell').filter(function(cell_d, i) {
+ if(!d3.select(this).classed('cell-selected') &&
+ // inner circle inside selection frame
+ (this.x.baseVal.value)+cellSize >= d.x && (this.x.baseVal.value)<=d.x+d.width &&
+ (this.y.baseVal.value)+cellSize >= d.y && (this.y.baseVal.value)<=d.y+d.height)
+ {
+ d3.select(this)
+ .classed('cell-selection', true)
+ .classed('cell-selected', true);
+
+ d3.select('.r' + cell_d.row)
+ .classed('text-selection',true)
+ .classed('text-selected',true);
+
+ d3.select('.c' + cell_d.col)
+ .classed('text-selection',true)
+ .classed('text-selected',true);
+ }
+ });
+ }
+ })
+ .on('mouseup', function() {
+ // remove selection frame
+ sa.selectAll('rect.selection').remove();
+
+ // remove temporary selection marker class
+ d3.selectAll('.cell-selection').classed('cell-selection', false);
+ d3.selectAll('.text-selection').classed('text-selection', false);
+ })
+ .on('mouseout', function() {
+ if(d3.event.relatedTarget.tagName=='html') {
+ // remove selection frame
+ sa.selectAll('rect.selection').remove();
+
+ // remove temporary selection marker class
+ d3.selectAll('.cell-selection').classed('cell-selection', false);
+ d3.selectAll('.rowLabel').classed('text-selected',false);
+ d3.selectAll('.colLabel').classed('text-selected',false);
+ }
+ });
+ },
+
+ // template
+ _templateSelect: function() {
+ return '<select id="order">' +
+ '<option value="hclust">Cluster</option>' +
+ '<option value="byboth">Sort by row and column</option>' +
+ '<option value="byrow">Sort by row label</option>' +
+ '<option value="bycol">Sort by column label</option>' +
+ '</select>';
+ },
+
+ // template
+ _templateTooltip: function() {
+ return '<div id="heatmap-tooltip" class="hidden">' +
+ '<p><span id="value"></p>'
+ '</div>';
+ }
+});
+});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/heatmap/logo.png
Binary file config/plugins/visualizations/charts/static/charts/heatmap/logo.png has changed
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/heatmap/wrapper.js
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/charts/heatmap/wrapper.js
@@ -0,0 +1,86 @@
+// dependencies
+define(['utils/utils', 'plugin/charts/heatmap/heatmap-plugin', 'plugin/charts/heatmap/heatmap-parameters'],
+function(Utils, HeatmapPlugin, HeatmapParameters) {
+
+// widget
+return Backbone.View.extend(
+{
+ // initialize
+ initialize: function(app, options) {
+ this.app = app;
+ this.options = options;
+ },
+
+ // render
+ draw : function(process_id, chart, request_dictionary)
+ {
+ // link this
+ var self = this;
+
+ // loop through data groups
+ var index = 0;
+ for (var group_index in request_dictionary.groups) {
+
+ // configure request
+ var tmp_dict = {
+ id : request_dictionary.id,
+ groups : [{
+ key : request_dictionary.groups[group_index].key,
+ columns : {
+ row_label: {
+ index : index++,
+ is_label : true
+ },
+ col_label: {
+ index : index++,
+ is_label : true
+ },
+ value: {
+ index : index++
+ }
+ }
+ }]
+ };
+
+ // target div
+ var group_div = self.options.canvas[group_index];
+
+ // draw group
+ this._draw_group(group_index, group_div, chart, tmp_dict, function(group_index) {
+ if (group_index == request_dictionary.groups.length - 1) {
+ // set chart state
+ chart.state('ok', 'Heat map drawn.');
+
+ // unregister process
+ chart.deferred.done(process_id);
+ }
+ });
+ }
+ },
+
+ // draw group
+ _draw_group: function(group_index, div, chart, request_dictionary, callback) {
+ // link this
+ var self = this;
+
+ // request data
+ this.app.datasets.request(request_dictionary, function() {
+
+ // get group
+ var group = request_dictionary.groups[0];
+
+ // draw plot
+ var heatmap = new HeatmapPlugin({
+ 'title' : group.key,
+ 'colors' : HeatmapParameters.colorSets[chart.settings.get('color_set')],
+ 'data' : group.values,
+ 'div' : div
+ });
+
+ // callback on completion
+ callback (group_index);
+ });
+ }
+});
+
+});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/highcharts_boxplot/config.js
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/charts/highcharts_boxplot/config.js
@@ -0,0 +1,40 @@
+define([], function() {
+
+return {
+ title : 'Box plot',
+ category : 'Data processing (requires \'charts\' tool from Toolshed)',
+ library : 'highcharts.js',
+ tag : 'div',
+ execute : 'boxplot',
+ columns : {
+ y : {
+ title : 'Observations'
+ }
+ },
+ settings : {
+ separator_label : {
+ title : 'X axis',
+ type : 'separator'
+ },
+ x_axis_label : {
+ title : 'Axis label',
+ info : 'Provide a label for the axis.',
+ type : 'text',
+ init : 'X-axis',
+ placeholder : 'Axis label'
+ },
+ separator_tick : {
+ title : 'Y axis',
+ type : 'separator'
+ },
+ y_axis_label : {
+ title : 'Axis label',
+ info : 'Provide a label for the axis.',
+ type : 'text',
+ init : 'Y-axis',
+ placeholder : 'Axis label'
+ }
+ }
+};
+
+});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/highcharts_boxplot/logo.png
Binary file config/plugins/visualizations/charts/static/charts/highcharts_boxplot/logo.png has changed
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/highcharts_boxplot/wrapper.js
--- /dev/null
+++ b/config/plugins/visualizations/charts/static/charts/highcharts_boxplot/wrapper.js
@@ -0,0 +1,122 @@
+// dependencies
+define(['utils/utils'], function(Utils) {
+
+// widget
+return Backbone.View.extend(
+{
+ // highcharts configuration
+ hc_config : {
+ chart: {
+ type: 'boxplot'
+ },
+
+ title: {
+ text: ''
+ },
+
+ legend: {
+ enabled: false
+ },
+
+ credits: {
+ enabled: false
+ },
+
+ plotOptions: {
+ series: {
+ animation: false
+ }
+ },
+
+ xAxis: {
+ categories: [],
+ title: {
+ text: ''
+ }
+ },
+
+ yAxis: {
+ title: {
+ text: ''
+ }
+ },
+
+ series: [{
+ name: 'Details:',
+ data: [],
+ tooltip: {
+ headerFormat: '<em>{point.key}</em><br/>'
+ }
+ }]
+ },
+
+ // initialize
+ initialize: function(app, options) {
+ this.app = app;
+ this.options = options;
+ },
+
+ // render
+ draw : function(process_id, chart, request_dictionary)
+ {
+ // configure request
+ var index = 0;
+ for (var i in request_dictionary.groups) {
+ var group = request_dictionary.groups[i];
+ group.columns = null;
+ group.columns = {
+ x: {
+ index: index++
+ }
+ }
+ }
+
+ // set axis labels
+ this.hc_config.xAxis.title.text = chart.settings.get('x_axis_label');
+ this.hc_config.yAxis.title.text = chart.settings.get('y_axis_label');
+
+ // request data
+ var self = this;
+ this.app.datasets.request(request_dictionary, function() {
+
+ // reset data/categories
+ var data = [];
+ var categories = [];
+
+ // loop through data groups
+ for (var key in request_dictionary.groups) {
+ // get group
+ var group = request_dictionary.groups[key];
+
+ // add category
+ categories.push(group.key);
+
+ // format chart data
+ var point = [];
+ for (var key in group.values) {
+ point.push(group.values[key].x);
+ }
+
+ // add to data
+ data.push (point);
+ }
+
+ // categories
+ self.hc_config.xAxis.categories = categories;
+
+ // update data
+ self.hc_config.series[0].data = data;
+
+ // draw plot
+ self.options.canvas[0].highcharts(self.hc_config);
+
+ // set chart state
+ chart.state('ok', 'Box plot drawn.');
+
+ // unregister process
+ chart.deferred.done(process_id);
+ });
+ }
+});
+
+});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/histogram/config.js
--- a/config/plugins/visualizations/charts/static/charts/histogram/config.js
+++ /dev/null
@@ -1,21 +0,0 @@
-define(['plugin/charts/_nvd3/config'], function(nvd3_config) {
-
-return $.extend(true, {}, nvd3_config, {
- title : 'Histogram',
- execute : true,
- columns : {
- y : {
- title : 'Observations'
- }
- },
- settings : {
- x_axis_label : {
- init : 'Breaks'
- },
- y_axis_label : {
- init : 'Density'
- }
- }
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/histogram/histogram.js
--- a/config/plugins/visualizations/charts/static/charts/histogram/histogram.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// dependencies
-define(['plugin/charts/_nvd3/nvd3'], function(NVD3) {
-
-// widget
-return Backbone.View.extend(
-{
- // initialize
- initialize: function(app, options) {
- this.app = app;
- this.options = options;
- },
-
- // render
- draw : function(process_id, chart, request_dictionary)
- {
- // configure request
- var index = 0;
- for (var i in request_dictionary.groups) {
- var group = request_dictionary.groups[i];
- group.columns = {
- x: index++,
- y: index++
- }
- }
-
- var nvd3 = new NVD3(this.app, this.options);
- nvd3.draw(process_id, nv.models.multiBarChart(), chart, request_dictionary);
- }
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/horizontal/config.js
--- a/config/plugins/visualizations/charts/static/charts/horizontal/config.js
+++ /dev/null
@@ -1,12 +0,0 @@
-define(['plugin/charts/_nvd3/config'], function(nvd3_config) {
-
-return $.extend(true, {}, nvd3_config, {
- title : 'Bar diagram (horizontal)',
- settings : {
- x_axis_type : {
- init : 'hide'
- }
- }
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/horizontal/horizontal.js
--- a/config/plugins/visualizations/charts/static/charts/horizontal/horizontal.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// dependencies
-define(['plugin/charts/_nvd3/nvd3'], function(NVD3) {
-
-// widget
-return Backbone.View.extend(
-{
- // initialize
- initialize: function(app, options) {
- this.app = app;
- this.options = options;
- },
-
- // render
- draw : function(process_id, chart, request_dictionary)
- {
- var nvd3 = new NVD3(this.app, this.options);
- nvd3.draw(process_id, nv.models.multiBarHorizontalChart(), chart, request_dictionary);
- }
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/line/config.js
--- a/config/plugins/visualizations/charts/static/charts/line/config.js
+++ /dev/null
@@ -1,7 +0,0 @@
-define(['plugin/charts/_nvd3/config'], function(nvd3_config) {
-
-return $.extend(true, {}, nvd3_config, {
- title : 'Line chart',
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/line/line.js
--- a/config/plugins/visualizations/charts/static/charts/line/line.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// dependencies
-define(['plugin/charts/_nvd3/nvd3'], function(NVD3) {
-
-// widget
-return Backbone.View.extend(
-{
- // initialize
- initialize: function(app, options) {
- this.app = app;
- this.options = options;
- },
-
- // render
- draw : function(process_id, chart, request_dictionary)
- {
- var nvd3 = new NVD3(this.app, this.options);
- nvd3.draw(process_id, nv.models.lineChart(), chart, request_dictionary);
- }
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/linewithfocus/config.js
--- a/config/plugins/visualizations/charts/static/charts/linewithfocus/config.js
+++ /dev/null
@@ -1,7 +0,0 @@
-define(['plugin/charts/_nvd3/config'], function(nvd3_config) {
-
-return $.extend(true, {}, nvd3_config, {
- title : 'Line with focus',
-});
-
-});
\ No newline at end of file
diff -r 8c4e3b85aa3bdf896a826e50acb2714b6b45279c -r 9ebe5ccabe0259801c67138ddf7f1734b011d694 config/plugins/visualizations/charts/static/charts/linewithfocus/linewithfocus.js
--- a/config/plugins/visualizations/charts/static/charts/linewithfocus/linewithfocus.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// dependencies
-define(['plugin/charts/_nvd3/nvd3'], function(NVD3) {
-
-// widget
-return Backbone.View.extend(
-{
- // initialize
- initialize: function(app, options) {
- this.app = app;
- this.options = options;
- },
-
- // render
- draw : function(process_id, chart, request_dictionary)
- {
- var nvd3 = new NVD3(this.app, this.options);
- nvd3.draw(process_id, nv.models.lineWithFocusChart(), chart, request_dictionary);
- }
-});
-
-});
\ No newline at end of file
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Fix for tool shed handling new GenomeBuilds manager.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9b33b543fb14/
Changeset: 9b33b543fb14
User: dan
Date: 2014-05-19 21:35:58
Summary: Fix for tool shed handling new GenomeBuilds manager.
Affected #: 2 files
diff -r 3faf01e5111ecf454f06b22546b530131b0550be -r 9b33b543fb1448f8f775ac975e2605ac610c8f63 lib/galaxy/webapps/tool_shed/app.py
--- a/lib/galaxy/webapps/tool_shed/app.py
+++ b/lib/galaxy/webapps/tool_shed/app.py
@@ -6,6 +6,7 @@
import galaxy.datatypes.registry
import galaxy.webapps.tool_shed.model
from galaxy.openid.providers import OpenIDProviders
+from galaxy.util.dbkeys import GenomeBuilds
from galaxy.web import security
from galaxy.tags.tag_handler import CommunityTagHandler
from tool_shed.grids.util import RepositoryGridFilterManager
@@ -49,6 +50,7 @@
# Initialize the Tool Shed tool data tables. Never pass a configuration file here
# because the Tool Shed should always have an empty dictionary!
self.tool_data_tables = galaxy.tools.data.ToolDataTableManager( self.config.tool_data_path )
+ self.genome_builds = GenomeBuilds( self )
# The Tool Shed makes no use of a Galaxy toolbox, but this attribute is still required.
self.toolbox = tools.ToolBox( [], self.config.tool_path, self )
# Initialize the Tool Shed security agent.
diff -r 3faf01e5111ecf454f06b22546b530131b0550be -r 9b33b543fb1448f8f775ac975e2605ac610c8f63 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.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.
self.num_tool_test_results_saved = kwargs.get( 'num_tool_test_results_saved', 5 )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: First pass at allowing dbkeys / genome builds to be loaded from Tool Data Tables.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3faf01e5111e/
Changeset: 3faf01e5111e
User: dan
Date: 2014-05-19 21:08:26
Summary: First pass at allowing dbkeys / genome builds to be loaded from Tool Data Tables.
Affected #: 12 files
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -57,13 +57,17 @@
self.tag_handler = GalaxyTagHandler()
# Dataset Collection Plugins
self.dataset_collections_service = dataset_collections.DatasetCollectionsService(self)
+
+ # Tool Data Tables
+ self._configure_tool_data_tables( from_shed_config=False )
+ # Load dbkey / genome build manager
+ self._configure_genome_builds( data_table_name="__dbkeys__", load_old_style=True )
+
# Genomes
self.genomes = Genomes( self )
# Data providers registry.
self.data_provider_registry = DataProviderRegistry()
- self._configure_tool_data_tables( from_shed_config=False )
-
# Initialize job metrics manager, needs to be in place before
# config so per-destination modifications can be made.
self.job_metrics = job_metrics.JobMetrics( self.config.job_metrics_config_file, app=self )
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -16,6 +16,7 @@
from galaxy.util import string_as_bool
from galaxy.util import listify
from galaxy.util import parse_xml
+from galaxy.util.dbkeys import GenomeBuilds
from galaxy import eggs
import pkg_resources
@@ -554,6 +555,9 @@
""" Shared code for configuring Galaxy-like app objects.
"""
+ def _configure_genome_builds( self, data_table_name="__dbkeys__", load_old_style=True ):
+ self.genome_builds = GenomeBuilds( self, data_table_name=data_table_name, load_old_style=load_old_style )
+
def _configure_toolbox( self ):
# Initialize the tools, making sure the list of tool configs includes the reserved migrated_tools_conf.xml file.
tool_configs = self.config.tool_configs
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/datatypes/metadata.py
--- a/lib/galaxy/datatypes/metadata.py
+++ b/lib/galaxy/datatypes/metadata.py
@@ -372,7 +372,7 @@
context = context or {}
other_values = other_values or {}
try:
- values = kwd['trans'].db_builds
+ values = kwd['trans'].app.genome_builds.get_genome_build_names( kwd['trans'] )
except KeyError:
pass
return super(DBKeyParameter, self).get_html_field( value, context, other_values, values, **kwd)
@@ -381,7 +381,7 @@
context = context or {}
other_values = other_values or {}
try:
- values = kwd['trans'].db_builds
+ values = kwd['trans'].app.genome_builds.get_genome_build_names( kwd['trans'] )
except KeyError:
pass
return super(DBKeyParameter, self).get_html( value, context, other_values, values, **kwd)
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/tools/actions/__init__.py
--- a/lib/galaxy/tools/actions/__init__.py
+++ b/lib/galaxy/tools/actions/__init__.py
@@ -193,36 +193,10 @@
# Collect chromInfo dataset and add as parameters to incoming
db_datasets = {}
- db_dataset = trans.db_dataset_for( input_dbkey )
+ ( chrom_info, db_dataset ) = trans.app.genome_builds.get_chrom_info( input_dbkey, trans=trans )
if db_dataset:
- db_datasets[ "chromInfo" ] = db_dataset
- incoming[ "chromInfo" ] = db_dataset.file_name
- else:
- # -- Get chrom_info (len file) from either a custom or built-in build. --
-
- chrom_info = None
- if trans.user and ( 'dbkeys' in trans.user.preferences ) and ( input_dbkey in from_json_string( trans.user.preferences[ 'dbkeys' ] ) ):
- # Custom build.
- custom_build_dict = from_json_string( trans.user.preferences[ 'dbkeys' ] )[ input_dbkey ]
- # HACK: the attempt to get chrom_info below will trigger the
- # fasta-to-len converter if the dataset is not available or,
- # which will in turn create a recursive loop when
- # running the fasta-to-len tool. So, use a hack in the second
- # condition below to avoid getting chrom_info when running the
- # fasta-to-len converter.
- if 'fasta' in custom_build_dict and tool.id != 'CONVERTER_fasta_to_len':
- # Build is defined by fasta; get len file, which is obtained from converting fasta.
- build_fasta_dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'fasta' ] )
- chrom_info = build_fasta_dataset.get_converted_dataset( trans, 'len' ).file_name
- elif 'len' in custom_build_dict:
- # Build is defined by len file, so use it.
- chrom_info = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'len' ] ).file_name
-
- if not chrom_info:
- # Default to built-in build.
- chrom_info = os.path.join( trans.app.config.len_file_path, "%s.len" % input_dbkey )
- incoming[ "chromInfo" ] = os.path.abspath( chrom_info )
- inp_data.update( db_datasets )
+ inp_data.update( { "chromInfo": db_dataset } )
+ incoming[ "chromInfo" ] = chrom_info
# Determine output dataset permission/roles list
existing_datasets = [ inp for inp in inp_data.values() if inp ]
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/tools/actions/upload_common.py
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -157,7 +157,7 @@
folder = matches[0]
else:
new_folder = trans.app.model.LibraryFolder( name=name, description='Automatically created by upload tool' )
- new_folder.genome_build = util.dbnames.default_value
+ new_folder.genome_build = trans.app.genome_builds.default_value
folder.add_folder( new_folder )
trans.sa_session.add( new_folder )
trans.sa_session.flush()
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/tools/data/__init__.py
--- a/lib/galaxy/tools/data/__init__.py
+++ b/lib/galaxy/tools/data/__init__.py
@@ -321,6 +321,19 @@
def get_fields( self ):
return self.data
+ def get_named_fields_list( self ):
+ rval = []
+ named_colums = self.get_column_name_list()
+ for fields in self.get_fields():
+ field_dict = {}
+ for i, field in enumerate( fields ):
+ field_name = named_colums[i]
+ if field_name is None:
+ field_name = i #check that this is supposed to be 0 based.
+ field_dict[ field_name ] = field
+ rval.append( field_dict )
+ return rval
+
def get_version_fields( self ):
return ( self._loaded_content_version, self.data )
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1033,17 +1033,18 @@
"""
def __init__( self, *args, **kwds ):
super( GenomeBuildParameter, self ).__init__( *args, **kwds )
- self.static_options = [ ( value, key, False ) for key, value in util.dbnames ]
+ if self.tool:
+ self.static_options = [ ( value, key, False ) for key, value in self._get_dbkey_names()]
def get_options( self, trans, other_values ):
last_used_build = object()
if trans.history:
last_used_build = trans.history.genome_build
- for dbkey, build_name in trans.db_builds:
+ for dbkey, build_name in self._get_dbkey_names( trans=trans ):
yield build_name, dbkey, ( dbkey == last_used_build )
def get_legal_values( self, trans, other_values ):
- return set( dbkey for dbkey, _ in trans.db_builds )
+ return set( dbkey for dbkey, _ in self._get_dbkey_names( trans=trans ) )
def to_dict( self, trans, view='collection', value_mapper=None ):
# skip SelectToolParameter (the immediate parent) bc we need to get options in a different way here
@@ -1062,6 +1063,12 @@
'value': value
})
return d
+
+ def _get_dbkey_names( self, trans=None ):
+ if not self.tool:
+ # Hack for unit tests, since we have no tool
+ return util.dbnames
+ return self.tool.app.genome_builds.get_genome_build_names( trans=trans )
class ColumnListParameter( SelectToolParameter ):
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/util/dbkeys.py
--- /dev/null
+++ b/lib/galaxy/util/dbkeys.py
@@ -0,0 +1,82 @@
+"""
+Functionality for dealing with dbkeys.
+"""
+#dbkeys read from disk using builds.txt
+from galaxy.util import dbnames, galaxy_directory
+from galaxy.util.json import from_json_string
+from galaxy.util.odict import odict
+import os.path
+
+
+class GenomeBuilds( object ):
+ default_value = "?"
+ default_name = "unspecified (?)"
+
+ def __init__( self, app, data_table_name="__dbkeys__", load_old_style=True ):
+ self._app = app
+ self._data_table_name = data_table_name
+ self._static_chrom_info_path = app.config.len_file_path
+ self._static_dbkeys = odict() #need odict to keep ? at top of list
+ if load_old_style:
+ for key, value in dbnames:
+ self._static_dbkeys[ key ] = value
+
+ def get_genome_build_names( self, trans=None ):
+ #FIXME: how to deal with key duplicates?
+ #Load old builds.txt static keys
+ rval = ( self._static_dbkeys.items() )
+ #load dbkeys from dbkey data table
+ dbkey_table = self._app.tool_data_tables.get( self._data_table_name, None )
+ if dbkey_table is not None:
+ for field_dict in dbkey_table.get_named_fields_list():
+ rval.append( ( field_dict[ 'value' ], field_dict[ 'name' ] ) )
+ #load user custom genome builds
+ if trans is not None:
+ if trans.history:
+ datasets = trans.sa_session.query( self._app.model.HistoryDatasetAssociation ) \
+ .filter_by( deleted=False, history_id=trans.history.id, extension="len" )
+ for dataset in datasets:
+ rval.append( (dataset.dbkey, dataset.name) )
+ user = trans.get_user()
+ if user and 'dbkeys' in user.preferences:
+ user_keys = from_json_string( user.preferences['dbkeys'] )
+ for key, chrom_dict in user_keys.iteritems():
+ rval.append( ( key, "%s (%s) [Custom]" % ( chrom_dict['name'], key ) ) )
+ return rval
+
+ def get_chrom_info( self, dbkey, trans=None ):
+ chrom_info = None
+ db_dataset = None
+ # Collect chromInfo from custom builds
+ if trans:
+ db_dataset = trans.db_dataset_for( dbkey )
+ if db_dataset:
+ #incoming[ "chromInfo" ] = db_dataset.file_name
+ chrom_info = db_dataset.file_name
+ else:
+ # -- Get chrom_info (len file) from either a custom or built-in build. --
+ if trans.user and ( 'dbkeys' in trans.user.preferences ) and ( input_dbkey in from_json_string( trans.user.preferences[ 'dbkeys' ] ) ):
+ # Custom build.
+ custom_build_dict = from_json_string( trans.user.preferences[ 'dbkeys' ] )[ input_dbkey ]
+ # HACK: the attempt to get chrom_info below will trigger the
+ # fasta-to-len converter if the dataset is not available or,
+ # which will in turn create a recursive loop when
+ # running the fasta-to-len tool. So, use a hack in the second
+ # condition below to avoid getting chrom_info when running the
+ # fasta-to-len converter.
+ if 'fasta' in custom_build_dict and tool.id != 'CONVERTER_fasta_to_len':
+ # Build is defined by fasta; get len file, which is obtained from converting fasta.
+ build_fasta_dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'fasta' ] )
+ chrom_info = build_fasta_dataset.get_converted_dataset( trans, 'len' ).file_name
+ elif 'len' in custom_build_dict:
+ # Build is defined by len file, so use it.
+ chrom_info = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'len' ] ).file_name
+ if not chrom_info:
+ dbkey_table = self._app.tool_data_tables.get( self._data_table_name, None )
+ if dbkey_table is not None:
+ chrom_info = dbkey_table.get_entry( 'value', dbkey, 'len_path', default=None )
+ if not chrom_info:
+ # Default to built-in build.
+ chrom_info = os.path.join( self._static_chrom_info_path, "%s.len" % dbkey )
+ chrom_info = os.path.abspath( chrom_info )
+ return ( chrom_info, db_dataset )
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/visualization/genomes.py
--- a/lib/galaxy/visualization/genomes.py
+++ b/lib/galaxy/visualization/genomes.py
@@ -178,9 +178,9 @@
"""
def __init__( self, app ):
- # Create list of genomes from util.dbnames
+ # Create list of genomes from app.genome_builds
self.genomes = {}
- for key, description in util.dbnames:
+ for key, description in app.genome_builds.get_genome_build_names():
self.genomes[ key ] = Genome( key, description )
# Add len files to genomes.
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -1075,7 +1075,7 @@
if self.galaxy_session.user:
history.user = self.galaxy_session.user
# Track genome_build with history
- history.genome_build = util.dbnames.default_value
+ history.genome_build = self.app.genome_builds.default_value
# Set the user's default history permissions
self.app.security_agent.history_set_default_permissions( history )
# Save
@@ -1238,19 +1238,8 @@
Returns the builds defined by galaxy and the builds defined by
the user (chromInfo in history).
"""
- dbnames = list()
- if self.history:
- datasets = self.sa_session.query( self.app.model.HistoryDatasetAssociation ) \
- .filter_by( deleted=False, history_id=self.history.id, extension="len" )
- for dataset in datasets:
- dbnames.append( (dataset.dbkey, dataset.name) )
- user = self.get_user()
- if user and 'dbkeys' in user.preferences:
- user_keys = from_json_string( user.preferences['dbkeys'] )
- for key, chrom_dict in user_keys.iteritems():
- dbnames.append((key, "%s (%s) [Custom]" % (chrom_dict['name'], key) ))
- dbnames.extend( util.dbnames )
- return dbnames
+ #FIXME: This method should be removed
+ return self.app.genome_builds.get_genome_build_names( trans=self )
@property
def ucsc_builds( self ):
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be lib/galaxy/webapps/galaxy/controllers/library_common.py
--- a/lib/galaxy/webapps/galaxy/controllers/library_common.py
+++ b/lib/galaxy/webapps/galaxy/controllers/library_common.py
@@ -292,9 +292,9 @@
new_folder = trans.app.model.LibraryFolder( name=util.restore_text( params.name ),
description=util.restore_text( params.description ) )
# We are associating the last used genome build with folders, so we will always
- # initialize a new folder with the first dbkey in util.dbnames which is currently
+ # initialize a new folder with the first dbkey in genome builds list which is currently
# ? unspecified (?)
- new_folder.genome_build = util.dbnames.default_value
+ new_folder.genome_build = trans.app.genome_builds.default_value
parent_folder.add_folder( new_folder )
trans.sa_session.add( new_folder )
trans.sa_session.flush()
@@ -1433,7 +1433,7 @@
file_formats = trans.app.datatypes_registry.upload_file_formats
# Send list of genome builds to the form so the "dbkey" select list can be populated dynamically
def get_dbkey_options( last_used_build ):
- for dbkey, build_name in util.dbnames:
+ for dbkey, build_name in trans.app.genome_builds.get_genome_build_names( trans=trans ):
yield build_name, dbkey, ( dbkey==last_used_build )
dbkeys = get_dbkey_options( last_used_build )
# Send the current history to the form to enable importing datasets from history to library
diff -r 6e4db406d614c7826b80a825be351df674994409 -r 3faf01e5111ecf454f06b22546b530131b0550be test/unit/tools_support.py
--- a/test/unit/tools_support.py
+++ b/test/unit/tools_support.py
@@ -14,6 +14,7 @@
from galaxy.model import mapping
from galaxy.tools import Tool
from galaxy.util import parse_xml
+from galaxy.util.dbkeys import GenomeBuilds
from galaxy.jobs import NoopQueue
@@ -96,6 +97,7 @@
tool_data_path=os.path.join(test_directory, "tools"),
root=os.path.join(test_directory, "galaxy"),
admin_users="mary(a)example.com",
+ len_file_path=os.path.join( 'tool-data', 'shared', 'ucsc', 'chrom' ),
)
# Setup some attributes for downstream extension by specific tests.
@@ -115,6 +117,7 @@
self.model[ module_member_name ] = module_member
else:
self.model = in_memomry_model
+ self.genome_builds = GenomeBuilds( self )
self.toolbox = None
self.object_store = None
self.security = SecurityHelper(id_secret="testing")
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/50e08b9c5329/
Changeset: 50e08b9c5329
User: jmchilton
Date: 2014-05-19 20:36:49
Summary: Don't show different multi-run option button if only one option.
Affected #: 1 file
diff -r 175bacc005a1437bfeedc8c76fe757467c08a870 -r 50e08b9c53293f52cbfe2c7e3e5dc9326e7c442f static/scripts/galaxy.tools.js
--- a/static/scripts/galaxy.tools.js
+++ b/static/scripts/galaxy.tools.js
@@ -68,6 +68,7 @@
var view = this;
var index = 0;
+ var visibleCount = 0;
_.each( this.switchOptions, function( option, onValue ) {
var numValues = _.size( option.options );
var selectionType = SELECTION_TYPE[ onValue ];
@@ -79,15 +80,21 @@
hidden = true;
}
if( ! hidden ) {
- var button = $('<i class="fa ' + selectionType['icon_class'] + '" style="padding-left: 5px; padding-right: 2px;"></i>').click(function() {
+ visibleCount++;
+ var button = $('<i class="fa ' + selectionType['icon_class'] + ' runOptionIcon" style="padding-left: 5px; padding-right: 2px;"></i>').click(function() {
view.enableSelectBy( iIndex, onValue );
}).attr(
'title',
selectionType['select_by']
);
- view.formRow().find( "label" ).append( button );
+ view.formRow().find( "label" ).append( button );
}
});
+ if( visibleCount < 2 ) {
+ // Don't show buttons to switch options...
+ view.formRow().find("i.runOptionIcon").hide();
+ }
+
if( defaultIndex != null) {
view.enableSelectBy( defaultIndex, defaultOption );
}
https://bitbucket.org/galaxy/galaxy-central/commits/6e4db406d614/
Changeset: 6e4db406d614
User: jmchilton
Date: 2014-05-19 20:38:21
Summary: Pack scripts.
Affected #: 1 file
diff -r 50e08b9c53293f52cbfe2c7e3e5dc9326e7c442f -r 6e4db406d614c7826b80a825be351df674994409 static/scripts/packed/galaxy.tools.js
--- a/static/scripts/packed/galaxy.tools.js
+++ b/static/scripts/packed/galaxy.tools.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","mvc/tools"],function(c,b){var a=function(g,f){$("input[name='"+g+"'][type='checkbox']").attr("checked",!!f)};$("div.checkUncheckAllPlaceholder").each(function(){var f=$(this).attr("checkbox_name");select_link=$("<a class='action-button'></a>").text("Select All").click(function(){a(f,true)});unselect_link=$("<a class='action-button'></a>").text("Unselect All").click(function(){a(f,false)});$(this).append(select_link).append(" ").append(unselect_link)});var e={select_single:{icon_class:"fa-file-o",select_by:"Run tool on single input",allow_remap:true},select_multiple:{icon_class:"fa-files-o",select_by:"Run tool in parallel across multiple datasets",allow_remap:false,min_option_count:2},select_collection:{icon_class:"fa-folder-o",select_by:"Run tool in parallel across dataset collection",allow_remap:false},multiselect_single:{icon_class:"fa-list-alt",select_by:"Run tool over multiple datasets",allow_remap:true},multiselect_collection:{icon_class:"fa-folder-o",select_by:"Run tool over dataset collection",allow_remap:false,},select_single_collection:{icon_class:"fa-file-o",select_by:"Run tool on single collection",allow_remap:true},select_map_over_collections:{icon_class:"fa-folder-o",select_by:"Map tool over compontents of nested collection",allow_remap:false,}};var d=Backbone.View.extend({initialize:function(k){var g=k.default_option;var l=null;var j=k.switch_options;this.switchOptions=j;this.prefix=k.prefix;var i=this.$el;var f=this;var h=0;c.each(this.switchOptions,function(q,s){var m=c.size(q.options);var p=e[s];var o=h++;var r=false;if(g==s){l=o}else{if(m<(p.min_option_count||1)){r=true}}if(!r){var n=$('<i class="fa '+p.icon_class+'" style="padding-left: 5px; padding-right: 2px;"></i>').click(function(){f.enableSelectBy(o,s)}).attr("title",p.select_by);f.formRow().find("label").append(n)}});if(l!=null){f.enableSelectBy(l,g)}},formRow:function(){return this.$el.closest(".form-row")},render:function(){},enableSelectBy:function(k,j){var h=e[j];if(h.allow_remap){$("div#remap-row").css("display","none")}else{$("div#remap-row").css("display","inherit")}this.formRow().find("i").each(function(l,m){if(l==k){$(m).css("color","black")}else{$(m).css("color","Gray")}});var g=this.$("select");var f=this.switchOptions[j];g.attr("name",this.prefix+f.name);g.attr("multiple",f.multiple);var i=this.$(".select2-container").length>0;g.html("");c.each(f.options,function(m){var o=m[0];var n=m[1];var l=m[2];g.append($("<option />",{text:o,val:n,selected:l}))});if(i){g.select2()}}});return{SwitchSelectView:d}});
\ No newline at end of file
+define(["libs/underscore","mvc/tools"],function(c,b){var a=function(g,f){$("input[name='"+g+"'][type='checkbox']").attr("checked",!!f)};$("div.checkUncheckAllPlaceholder").each(function(){var f=$(this).attr("checkbox_name");select_link=$("<a class='action-button'></a>").text("Select All").click(function(){a(f,true)});unselect_link=$("<a class='action-button'></a>").text("Unselect All").click(function(){a(f,false)});$(this).append(select_link).append(" ").append(unselect_link)});var e={select_single:{icon_class:"fa-file-o",select_by:"Run tool on single input",allow_remap:true},select_multiple:{icon_class:"fa-files-o",select_by:"Run tool in parallel across multiple datasets",allow_remap:false,min_option_count:2},select_collection:{icon_class:"fa-folder-o",select_by:"Run tool in parallel across dataset collection",allow_remap:false},multiselect_single:{icon_class:"fa-list-alt",select_by:"Run tool over multiple datasets",allow_remap:true},multiselect_collection:{icon_class:"fa-folder-o",select_by:"Run tool over dataset collection",allow_remap:false,},select_single_collection:{icon_class:"fa-file-o",select_by:"Run tool on single collection",allow_remap:true},select_map_over_collections:{icon_class:"fa-folder-o",select_by:"Map tool over compontents of nested collection",allow_remap:false,}};var d=Backbone.View.extend({initialize:function(l){var g=l.default_option;var m=null;var k=l.switch_options;this.switchOptions=k;this.prefix=l.prefix;var j=this.$el;var f=this;var h=0;var i=0;c.each(this.switchOptions,function(r,t){var n=c.size(r.options);var q=e[t];var p=h++;var s=false;if(g==t){m=p}else{if(n<(q.min_option_count||1)){s=true}}if(!s){i++;var o=$('<i class="fa '+q.icon_class+' runOptionIcon" style="padding-left: 5px; padding-right: 2px;"></i>').click(function(){f.enableSelectBy(p,t)}).attr("title",q.select_by);f.formRow().find("label").append(o)}});if(i<2){f.formRow().find("i.runOptionIcon").hide()}if(m!=null){f.enableSelectBy(m,g)}},formRow:function(){return this.$el.closest(".form-row")},render:function(){},enableSelectBy:function(k,j){var h=e[j];if(h.allow_remap){$("div#remap-row").css("display","none")}else{$("div#remap-row").css("display","inherit")}this.formRow().find("i").each(function(l,m){if(l==k){$(m).css("color","black")}else{$(m).css("color","Gray")}});var g=this.$("select");var f=this.switchOptions[j];g.attr("name",this.prefix+f.name);g.attr("multiple",f.multiple);var i=this.$(".select2-container").length>0;g.html("");c.each(f.options,function(m){var o=m[0];var n=m[1];var l=m[2];g.append($("<option />",{text:o,val:n,selected:l}))});if(i){g.select2()}}});return{SwitchSelectView:d}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c559805d44df/
Changeset: c559805d44df
User: davebgx
Date: 2014-05-19 19:01:46
Summary: Migrate 22 tools from the distribution to the tool shed.
Affected #: 67 files
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 lib/tool_shed/galaxy_install/migrate/versions/0011_tools.py
--- /dev/null
+++ b/lib/tool_shed/galaxy_install/migrate/versions/0011_tools.py
@@ -0,0 +1,62 @@
+"""
+The following tools have been eliminated from the distribution:
+
+1: Profile Annotations for a set of genomic intervals
+2: Polymorphism of the Reads
+3: Coverage of the Reads in wiggle format
+4: Canonical Correlation Analysis
+5: Convert Color Space to Nucleotides
+6: Compute sequence length
+7: Concatenate FASTA alignment by species
+8: Filter sequences by length
+9: FASTA-to-Tabular converter
+10: FASTQSOLEXA-to-FASTA-QUAL extracts sequences and quality scores from FASTQSOLEXA data
+11: Kernel Canonical Correlation Analysis
+12: Kernel Principal Component Analysis
+13: Format mapping data as UCSC custom track
+14: Megablast compare short reads against htgs, nt, and wgs databases
+15: Parse blast XML output
+16: Principal Component Analysis
+17: RMAP for Solexa Short Reads Alignment
+18: RMAPQ for Solexa Short Reads Alignment with Quality Scores
+19: Histogram of high quality score reads
+20: Build base quality distribution
+21: Select high quality segments
+22: Tabular-to-FASTA
+
+The tools are now available in the repositories respectively:
+
+1: annotation_profiler
+2: blat_coverage_report
+3: blat_mapping
+4: canonical_correlation_analysis
+5: convert_solid_color2nuc
+6: fasta_compute_length
+7: fasta_concatenate_by_species
+8: fasta_filter_by_length
+9: fasta_to_tabular
+10: fastqsolexa_to_fasta_qual
+11: kernel_canonical_correlation_analysis
+12: kernel_principal_component_analysis
+13: mapping_to_ucsc
+14: megablast_wrapper
+15: megablast_xml_parser
+16: principal_component_analysis
+17: rmap
+18: rmapq
+19: short_reads_figure_high_quality_length
+20: short_reads_figure_score
+21: short_reads_trim_seq
+22: tabular_to_fasta
+
+from the main Galaxy tool shed at http://toolshed.g2.bx.psu.edu
+and will be installed into your local Galaxy instance at the
+location discussed above by running the following command.
+
+"""
+
+def upgrade( migrate_engine ):
+ print __doc__
+
+def downgrade( migrate_engine ):
+ pass
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 scripts/migrate_tools/0011_tools.sh
--- /dev/null
+++ b/scripts/migrate_tools/0011_tools.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cd `dirname $0`/../..
+python ./scripts/migrate_tools/migrate_tools.py 0011_tools.xml $@
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 scripts/migrate_tools/0011_tools.xml
--- /dev/null
+++ b/scripts/migrate_tools/0011_tools.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<toolshed name="toolshed.g2.bx.psu.edu">
+ <repository changeset_revision="3b33da018e74" owner="devteam" name="annotation_profiler" description="Profile Annotations for a set of genomic intervals">
+ <tool file="annotation_profiler/annotation_profiler.xml" id="Annotation_Profiler_0" version="1.0.0" />
+ </repository>
+ <repository changeset_revision="30f0948c649c" owner="devteam" name="blat_coverage_report" description="Polymorphism of the Reads">
+ <tool id="generate_coverage_report" version="1.0.0" file="metag_tools/blat_coverage_report.xml" />
+ </repository>
+ <repository changeset_revision="807e3e50845a" owner="devteam" name="blat_mapping" description="Coverage of the Reads in wiggle format">
+ <tool id="blat2wig" version="1.0.0" file="metag_tools/blat_mapping.xml" />
+ </repository>
+ <repository changeset_revision="9bc0c48a027f" owner="devteam" name="canonical_correlation_analysis" description="Canonical Correlation Analysis">
+ <tool file="multivariate_stats/cca.xml" id="cca1" version="1.0.0" />
+ </repository>
+ <repository changeset_revision="ab28e7de2db3" owner="devteam" name="convert_solid_color2nuc" description="Convert Color Space to Nucleotides">
+ <tool id="color2nuc" version="1.0.0" file="metag_tools/convert_SOLiD_color2nuc.xm" />
+ </repository>
+ <repository changeset_revision="ece409f6573c" owner="devteam" name="fasta_compute_length" description="Compute sequence length">
+ <tool file="fasta_tools/fasta_compute_length.xml" id="fasta_compute_length" version="__VERSION__" />
+ </repository>
+ <repository changeset_revision="2126e1b833a2" owner="devteam" name="fasta_concatenate_by_species" description="Concatenate FASTA alignment by species">
+ <tool file="fasta_tools/fasta_concatenate_by_species.xml" id="fasta_concatenate0" version="0.0.0" />
+ </repository>
+ <repository changeset_revision="16679a7f554a" owner="devteam" name="fasta_filter_by_length" description="Filter sequences by length">
+ <tool file="fasta_tools/fasta_filter_by_length.xml" id="fasta_filter_by_length" version="1.1" />
+ </repository>
+ <repository changeset_revision="9d189d08f2ad" owner="devteam" name="fasta_to_tabular" description="FASTA-to-Tabular converter">
+ <tool file="fasta_tools/fasta_to_tabular.xml" id="fasta2tab" version="1.1.0" />
+ </repository>
+ <repository changeset_revision="ef23c03d7497" owner="devteam" name="fastqsolexa_to_fasta_qual" description="FASTQSOLEXA-to-FASTA-QUAL extracts sequences and quality scores from FASTQSOLEXA data">
+ <tool id="fastqsolexa_to_fasta_qual" version="1.0.0" file="metag_tools/fastqsolexa_to_fasta_qual.xml" />
+ </repository>
+ <repository changeset_revision="7a092113eb8c" owner="devteam" name="kernel_canonical_correlation_analysis" description="Kernel Canonical Correlation Analysis">
+ <tool file="multivariate_stats/kcca.xml" id="kcca1" version="1.0.0" />
+ </repository>
+ <repository changeset_revision="e9ebd4bfbdfc" owner="devteam" name="kernel_principal_component_analysis" description="Kernel Principal Component Analysis">
+ <tool file="multivariate_stats/kpca.xml" id="kpca1" version="1.0.0" />
+ </repository>
+ <repository changeset_revision="601abbd22cea" owner="devteam" name="mapping_to_ucsc" description="Format mapping data as UCSC custom track">
+ <tool id="mapToUCSC" version="1.0.0" file="metag_tools/mapping_to_ucsc.xml" />
+ </repository>
+ <repository changeset_revision="dc7b4acb3fa6" owner="devteam" name="megablast_wrapper" description="Megablast compare short reads against htgs, nt, and wgs databases">
+ <tool file="metag_tools/megablast_wrapper.xml" id="megablast_wrapper" version="1.2.0" />
+ </repository>
+ <repository changeset_revision="03ca082aeb2e" owner="devteam" name="megablast_xml_parser" description="Parse blast XML output">
+ <tool file="metag_tools/megablast_xml_parser.xml" id="megablast_xml_parser" version="1.0.0" />
+ </repository>
+ <repository changeset_revision="f568051cdf2e" owner="devteam" name="principal_component_analysis" description="Principal Component Analysis">
+ <tool file="multivariate_stats/pca.xml" id="pca1" version="1.0.2" />
+ </repository>
+ <repository changeset_revision="ee49255302d8" owner="devteam" name="rmap" description="RMAP for Solexa Short Reads Alignment">
+ <tool id="rmap_wrapper" version="1.0.0" file="metag_tools/rmap_wrapper.xml" />
+ </repository>
+ <repository changeset_revision="f6e5bb5aa2f5" owner="devteam" name="rmapq" description="RMAPQ for Solexa Short Reads Alignment with Quality Scores">
+ <tool id="rmapq_wrapper" version="1.0.0" file="metag_tools/rmapq_wrapper.xml" />
+ </repository>
+ <repository changeset_revision="556ceed24699" owner="devteam" name="short_reads_figure_high_quality_length" description="Histogram of high quality score reads">
+ <tool id="hist_high_quality_score" version="1.0.0" file="metag_tools/short_reads_figure_high_quality_length.xml" />
+ </repository>
+ <repository changeset_revision="b52b9c7aabd9" owner="devteam" name="short_reads_figure_score" description="Build base quality distribution">
+ <tool file="metag_tools/short_reads_figure_score.xml" id="quality_score_distribution" version="1.0.2" />
+ </repository>
+ <repository changeset_revision="f17a1585733b" owner="devteam" name="short_reads_trim_seq" description="Select high quality segments">
+ <tool file="metag_tools/short_reads_trim_seq.xml" id="trim_reads" version="1.0.0" />
+ </repository>
+ <repository changeset_revision="0b4e36026794" owner="devteam" name="tabular_to_fasta" description="Tabular-to-FASTA">
+ <tool file="fasta_tools/tabular_to_fasta.xml" id="tab2fasta" version="1.1.0" />
+ </repository>
+</toolshed>
\ No newline at end of file
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 scripts/tools/annotation_profiler/README.txt
--- a/scripts/tools/annotation_profiler/README.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-This file explains how to create annotation indexes for the annotation profiler tool. Annotation profiler indexes are an exceedingly simple binary format,
-containing no header information and consisting of an ordered linear list of (start,stop encoded individually as '<I') regions which are covered by a UCSC table partitioned
-by chromosome name. Genomic regions are merged by overlap / direct adjacency (e.g. a table having ranges of: 1-10, 6-12, 12-20 and 25-28 results in two merged ranges of: 1-20 and 25-28).
-
-Files are arranged like:
-/profiled_annotations/DBKEY/TABLE_NAME/
- CHROMOSOME_NAME.covered
- CHROMOSOME_NAME.total_coverage
- CHROMOSOME_NAME.total_regions
-/profiled_annotations/DBKEY/
- DBKEY_tables.xml
- chromosomes.txt
- profiled_info.txt
-
-
-where CHROMOSOME_NAME.covered is the binary file, CHROMOSOME_NAME.total_coverage is a text file containing the integer count of bases covered by the
-table and CHROMOSOME_NAME.total_regions contains the integer count of the number of regions found in CHROMOSOME_NAME.covered
-
-DBKEY_tables.xml should be appended to the annotation profile available table configuration file (tool-data/annotation_profiler_options.xml).
-The DBKEY should also be added as a new line to the annotation profiler valid builds file (annotation_profiler_valid_builds.txt).
-The output (/profiled_annotations/DBKEY) should be made available as GALAXY_ROOT/tool-data/annotation_profiler/DBKEY.
-
-profiled_info.txt contains info on the generated annotations, separated by lines with tab-delimited label,value pairs:
- profiler_version - the version of the build_profile_indexes.py script that was used to generate the profiled data
- dbkey - the dbkey used for the run
- chromosomes - contains the names and lengths of chromosomes that were used to parse single-chromosome tables (tables divided into individual files by chromosome)
- dump_time - the declared dump time of the database, taken from trackDb.txt.gz
- profiled_time - seconds since epoch in utc for when the database dump was profiled
- database_hash - a md5 hex digest of all the profiled table info
-
-
-Typical usage includes:
-
-python build_profile_indexes.py -d hg19 -i /ucsc_data/hg19/database/ > hg19.txt
-
-where the genome build is hg19 and /ucsc_data/hg19/database/ contains the downloaded database dump from UCSC (e.g. obtained by rsync: rsync -avzP rsync://hgdownload.cse.ucsc.edu/goldenPath/hg19/database/ /ucsc_data/hg19/database/).
-
-
-
-By default, chromosome names come from a file named 'chromInfo.txt.gz' found in the input directory, with FTP used as a backup.
-When FTP is used to obtain the names of chromosomes from UCSC for a particular genome build, alternate ftp sites and paths can be specified by using the --ftp_site and --ftp_path attributes.
-Chromosome names can instead be provided on the commandline via the --chromosomes option, which accepts a comma separated list of:ChromName1[=length],ChromName2[=length],...
-
-
-
- usage = "usage: %prog options"
- parser = OptionParser( usage=usage )
- parser.add_option( '-d', '--dbkey', dest='dbkey', default='hg18', help='dbkey to process' )
- parser.add_option( '-i', '--input_dir', dest='input_dir', default=os.path.join( 'golden_path','%s', 'database' ), help='Input Directory' )
- parser.add_option( '-o', '--output_dir', dest='output_dir', default=os.path.join( 'profiled_annotations','%s' ), help='Output Directory' )
- parser.add_option( '-c', '--chromosomes', dest='chromosomes', default='', help='Comma separated list of: ChromName1[=length],ChromName2[=length],...' )
- parser.add_option( '-b', '--bitset_size', dest='bitset_size', default=DEFAULT_BITSET_SIZE, type='int', help='Default BitSet size; overridden by sizes specified in chromInfo.txt.gz or by --chromosomes' )
- parser.add_option( '-f', '--ftp_site', dest='ftp_site', default='hgdownload.cse.ucsc.edu', help='FTP site; used for chromosome info when chromInfo.txt.gz method fails' )
- parser.add_option( '-p', '--ftp_path', dest='ftp_path', default='/goldenPath/%s/chromosomes/', help='FTP Path; used for chromosome info when chromInfo.txt.gz method fails' )
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 scripts/tools/annotation_profiler/build_profile_indexes.py
--- a/scripts/tools/annotation_profiler/build_profile_indexes.py
+++ /dev/null
@@ -1,338 +0,0 @@
-#!/usr/bin/env python
-#Dan Blankenberg
-
-VERSION = '1.0.0' # version of this script
-
-from optparse import OptionParser
-import os, gzip, struct, time
-from ftplib import FTP #do we want a diff method than using FTP to determine Chrom Names, eg use local copy
-
-#import md5 from hashlib; if python2.4 or less, use old md5
-try:
- from hashlib import md5
-except ImportError:
- from md5 import new as md5
-
-#import BitSet from bx-python, try using eggs and package resources, fall back to any local installation
-try:
- from galaxy import eggs
- import pkg_resources
- pkg_resources.require( "bx-python" )
-except: pass #Maybe there is a local installation available
-from bx.bitset import BitSet
-
-#Define constants
-STRUCT_FMT = '<I'
-STRUCT_SIZE = struct.calcsize( STRUCT_FMT )
-DEFAULT_BITSET_SIZE = 300000000
-CHUNK_SIZE = 1024
-
-#Headers used to parse .sql files to determine column indexes for chromosome name, start and end
-alias_spec = {
- 'chromCol' : [ 'chrom' , 'CHROMOSOME' , 'CHROM', 'Chromosome Name', 'tName' ],
- 'startCol' : [ 'start' , 'START', 'chromStart', 'txStart', 'Start Position (bp)', 'tStart', 'genoStart' ],
- 'endCol' : [ 'end' , 'END' , 'STOP', 'chromEnd', 'txEnd', 'End Position (bp)', 'tEnd', 'genoEnd' ],
-}
-
-#Headers used to parse trackDb.txt.gz
-#TODO: these should be parsed directly from trackDb.sql
-trackDb_headers = ["tableName", "shortLabel", "type", "longLabel", "visibility", "priority", "colorR", "colorG", "colorB", "altColorR", "altColorG", "altColorB", "useScore", "private", "restrictCount", "restrictList", "url", "html", "grp", "canPack", "settings"]
-
-def get_columns( filename ):
- input_sql = open( filename ).read()
- input_sql = input_sql.split( 'CREATE TABLE ' )[1].split( ';' )[0]
- input_sql = input_sql.split( ' (', 1 )
- table_name = input_sql[0].strip().strip( '`' )
- input_sql = [ split.strip().split( ' ' )[0].strip().strip( '`' ) for split in input_sql[1].rsplit( ')', 1 )[0].strip().split( '\n' ) ]
- print input_sql
- chrom_col = None
- start_col = None
- end_col = None
- for col_name in alias_spec['chromCol']:
- for i, header_name in enumerate( input_sql ):
- if col_name == header_name:
- chrom_col = i
- break
- if chrom_col is not None:
- break
-
- for col_name in alias_spec['startCol']:
- for i, header_name in enumerate( input_sql ):
- if col_name == header_name:
- start_col = i
- break
- if start_col is not None:
- break
-
- for col_name in alias_spec['endCol']:
- for i, header_name in enumerate( input_sql ):
- if col_name == header_name:
- end_col = i
- break
- if end_col is not None:
- break
-
- return table_name, chrom_col, start_col, end_col
-
-
-def create_grouping_xml( input_dir, output_dir, dbkey ):
- output_filename = os.path.join( output_dir, '%s_tables.xml' % dbkey )
- def load_groups( file_name = 'grp.txt.gz' ):
- groups = {}
- for line in gzip.open( os.path.join( input_dir, file_name ) ):
- fields = line.split( '\t' )
- groups[fields[0]] = { 'desc': fields[1], 'priority': fields[2] }
- return groups
- f = gzip.open( os.path.join( input_dir, 'trackDb.txt.gz' ) )
- out = open( output_filename, 'wb' )
- tables = {}
- cur_buf = ''
- while True:
- line = f.readline()
- if not line: break
- #remove new lines
- line = line.rstrip( '\n\r' )
- line = line.replace( '\\\t', ' ' ) #replace escaped tabs with space
- cur_buf += "%s\n" % line.rstrip( '\\' )
- if line.endswith( '\\' ):
- continue #line is wrapped, next line
- #all fields should be loaded now...
- fields = cur_buf.split( '\t' )
- cur_buf = '' #reset buffer
- assert len( fields ) == len( trackDb_headers ), 'Failed Parsing trackDb.txt.gz; fields: %s' % fields
- table_name = fields[ 0 ]
- tables[ table_name ] = {}
- for field_name, field_value in zip( trackDb_headers, fields ):
- tables[ table_name ][ field_name ] = field_value
- #split settings fields into dict
- fields = fields[-1].split( '\n' )
- tables[ table_name ][ 'settings' ] = {}
- for field in fields:
- setting_fields = field.split( ' ', 1 )
- setting_name = setting_value = setting_fields[ 0 ]
- if len( setting_fields ) > 1:
- setting_value = setting_fields[ 1 ]
- if setting_name or setting_value:
- tables[ table_name ][ 'settings' ][ setting_name ] = setting_value
- #Load Groups
- groups = load_groups()
- in_groups = {}
- for table_name, values in tables.iteritems():
- if os.path.exists( os.path.join( output_dir, table_name ) ):
- group = values['grp']
- if group not in in_groups:
- in_groups[group]={}
- #***NAME CHANGE***, 'subTrack' no longer exists as a setting...use 'parent' instead
- #subTrack = values.get('settings', {} ).get( 'subTrack', table_name )
- subTrack = values.get('settings', {} ).get( 'parent', table_name ).split( ' ' )[0] #need to split, because could be e.g. 'trackgroup on'
- if subTrack not in in_groups[group]:
- in_groups[group][subTrack]=[]
- in_groups[group][subTrack].append( table_name )
-
- assigned_tables = []
- out.write( """<filter type="data_meta" data_ref="input1" meta_key="dbkey" value="%s">\n""" % ( dbkey ) )
- out.write( " <options>\n" )
- for group, subTracks in sorted( in_groups.iteritems() ):
- out.write( """ <option name="%s" value="group-%s">\n""" % ( groups[group]['desc'], group ) )
- for sub_name, sub_tracks in subTracks.iteritems():
- if len( sub_tracks ) > 1:
- out.write( """ <option name="%s" value="subtracks-%s">\n""" % ( sub_name, sub_name ) )
- sub_tracks.sort()
- for track in sub_tracks:
- track_label = track
- if "$" not in tables[track]['shortLabel']:
- track_label = tables[track]['shortLabel']
- out.write( """ <option name="%s" value="%s"/>\n""" % ( track_label, track ) )
- assigned_tables.append( track )
- out.write( " </option>\n" )
- else:
- track = sub_tracks[0]
- track_label = track
- if "$" not in tables[track]['shortLabel']:
- track_label = tables[track]['shortLabel']
- out.write( """ <option name="%s" value="%s"/>\n""" % ( track_label, track ) )
- assigned_tables.append( track )
- out.write( " </option>\n" )
- unassigned_tables = list( sorted( [ table_dir for table_dir in os.listdir( output_dir ) if table_dir not in assigned_tables and os.path.isdir( os.path.join( output_dir, table_dir ) ) ] ) )
- if unassigned_tables:
- out.write( """ <option name="Uncategorized Tables" value="group-trackDbUnassigned">\n""" )
- for table_name in unassigned_tables:
- out.write( """ <option name="%s" value="%s"/>\n""" % ( table_name, table_name ) )
- out.write( " </option>\n" )
- out.write( " </options>\n" )
- out.write( """</filter>\n""" )
- out.close()
-
-def write_database_dump_info( input_dir, output_dir, dbkey, chrom_lengths, default_bitset_size ):
- #generate hash for profiled table directories
- #sort directories off output root (files in output root not hashed, including the profiler_info.txt file)
- #sort files in each directory and hash file contents
- profiled_hash = md5()
- for table_dir in sorted( [ table_dir for table_dir in os.listdir( output_dir ) if os.path.isdir( os.path.join( output_dir, table_dir ) ) ] ):
- for filename in sorted( os.listdir( os.path.join( output_dir, table_dir ) ) ):
- f = open( os.path.join( output_dir, table_dir, filename ), 'rb' )
- while True:
- hash_chunk = f.read( CHUNK_SIZE )
- if not hash_chunk:
- break
- profiled_hash.update( hash_chunk )
- profiled_hash = profiled_hash.hexdigest()
-
- #generate hash for input dir
- #sort directories off input root
- #sort files in each directory and hash file contents
- database_hash = md5()
- for dirpath, dirnames, filenames in sorted( os.walk( input_dir ) ):
- for filename in sorted( filenames ):
- f = open( os.path.join( input_dir, dirpath, filename ), 'rb' )
- while True:
- hash_chunk = f.read( CHUNK_SIZE )
- if not hash_chunk:
- break
- database_hash.update( hash_chunk )
- database_hash = database_hash.hexdigest()
-
- #write out info file
- out = open( os.path.join( output_dir, 'profiler_info.txt' ), 'wb' )
- out.write( 'dbkey\t%s\n' % ( dbkey ) )
- out.write( 'chromosomes\t%s\n' % ( ','.join( [ '%s=%s' % ( chrom_name, chrom_len ) for chrom_name, chrom_len in chrom_lengths.iteritems() ] ) ) )
- out.write( 'bitset_size\t%s\n' % ( default_bitset_size ) )
- for line in open( os.path.join( input_dir, 'trackDb.sql' ) ):
- line = line.strip()
- if line.startswith( '-- Dump completed on ' ):
- line = line[ len( '-- Dump completed on ' ): ]
- out.write( 'dump_time\t%s\n' % ( line ) )
- break
- out.write( 'dump_hash\t%s\n' % ( database_hash ) )
- out.write( 'profiler_time\t%s\n' % ( time.time() ) )
- out.write( 'profiler_hash\t%s\n' % ( profiled_hash ) )
- out.write( 'profiler_version\t%s\n' % ( VERSION ) )
- out.write( 'profiler_struct_format\t%s\n' % ( STRUCT_FMT ) )
- out.write( 'profiler_struct_size\t%s\n' % ( STRUCT_SIZE ) )
- out.close()
-
-def __main__():
- usage = "usage: %prog options"
- parser = OptionParser( usage=usage )
- parser.add_option( '-d', '--dbkey', dest='dbkey', default='hg18', help='dbkey to process' )
- parser.add_option( '-i', '--input_dir', dest='input_dir', default=os.path.join( 'golden_path','%s', 'database' ), help='Input Directory' )
- parser.add_option( '-o', '--output_dir', dest='output_dir', default=os.path.join( 'profiled_annotations','%s' ), help='Output Directory' )
- parser.add_option( '-c', '--chromosomes', dest='chromosomes', default='', help='Comma separated list of: ChromName1[=length],ChromName2[=length],...' )
- parser.add_option( '-b', '--bitset_size', dest='bitset_size', default=DEFAULT_BITSET_SIZE, type='int', help='Default BitSet size; overridden by sizes specified in chromInfo.txt.gz or by --chromosomes' )
- parser.add_option( '-f', '--ftp_site', dest='ftp_site', default='hgdownload.cse.ucsc.edu', help='FTP site; used for chromosome info when chromInfo.txt.gz method fails' )
- parser.add_option( '-p', '--ftp_path', dest='ftp_path', default='/goldenPath/%s/chromosomes/', help='FTP Path; used for chromosome info when chromInfo.txt.gz method fails' )
-
- ( options, args ) = parser.parse_args()
-
- input_dir = options.input_dir
- if '%' in input_dir:
- input_dir = input_dir % options.dbkey
- assert os.path.exists( input_dir ), 'Input directory does not exist'
- output_dir = options.output_dir
- if '%' in output_dir:
- output_dir = output_dir % options.dbkey
- assert not os.path.exists( output_dir ), 'Output directory already exists'
- os.makedirs( output_dir )
- ftp_path = options.ftp_path
- if '%' in ftp_path:
- ftp_path = ftp_path % options.dbkey
-
- #Get chromosome names and lengths
- chrom_lengths = {}
- if options.chromosomes:
- for chrom in options.chromosomes.split( ',' ):
- fields = chrom.split( '=' )
- chrom = fields[0]
- if len( fields ) > 1:
- chrom_len = int( fields[1] )
- else:
- chrom_len = options.bitset_size
- chrom_lengths[ chrom ] = chrom_len
- chroms = chrom_lengths.keys()
- print 'Chrom info taken from command line option.'
- else:
- try:
- for line in gzip.open( os.path.join( input_dir, 'chromInfo.txt.gz' ) ):
- fields = line.strip().split( '\t' )
- chrom_lengths[ fields[0] ] = int( fields[ 1 ] )
- chroms = chrom_lengths.keys()
- print 'Chrom info taken from chromInfo.txt.gz.'
- except Exception, e:
- print 'Error loading chrom info from chromInfo.txt.gz, trying FTP method.'
- chrom_lengths = {} #zero out chrom_lengths
- chroms = []
- ftp = FTP( options.ftp_site )
- ftp.login()
- for name in ftp.nlst( ftp_path ):
- if name.endswith( '.fa.gz' ):
- chroms.append( name.split( '/' )[-1][ :-len( '.fa.gz' ) ] )
- ftp.close()
- for chrom in chroms:
- chrom_lengths[ chrom ] = options.bitset_size
- #sort chroms by length of name, decending; necessary for when table names start with chrom name
- chroms = list( reversed( [ chrom for chrom_len, chrom in sorted( [ ( len( chrom ), chrom ) for chrom in chroms ] ) ] ) )
-
- #parse tables from local files
- #loop through directory contents, if file ends in '.sql', process table
- for filename in os.listdir( input_dir ):
- if filename.endswith ( '.sql' ):
- base_filename = filename[ 0:-len( '.sql' ) ]
- table_out_dir = os.path.join( output_dir, base_filename )
- #some tables are chromosome specific, lets strip off the chrom name
- for chrom in chroms:
- if base_filename.startswith( "%s_" % chrom ):
- #found chromosome
- table_out_dir = os.path.join( output_dir, base_filename[len( "%s_" % chrom ):] )
- break
- #create table dir
- if not os.path.exists( table_out_dir ):
- os.mkdir( table_out_dir ) #table dir may already exist in the case of single chrom tables
- print "Created table dir (%s)." % table_out_dir
- else:
- print "Table dir (%s) already exists." % table_out_dir
- #find column assignments
- table_name, chrom_col, start_col, end_col = get_columns( "%s.sql" % os.path.join( input_dir, base_filename ) )
- if chrom_col is None or start_col is None or end_col is None:
- print "Table %s (%s) does not appear to have a chromosome, a start, or a stop." % ( table_name, "%s.sql" % os.path.join( input_dir, base_filename ) )
- if not os.listdir( table_out_dir ):
- print "Removing empty table (%s) directory (%s)." % ( table_name, table_out_dir )
- os.rmdir( table_out_dir )
- continue
- #build bitsets from table
- bitset_dict = {}
- for line in gzip.open( '%s.txt.gz' % os.path.join( input_dir, base_filename ) ):
- fields = line.strip().split( '\t' )
- chrom = fields[ chrom_col ]
- start = int( fields[ start_col ] )
- end = int( fields[ end_col ] )
- if chrom not in bitset_dict:
- bitset_dict[ chrom ] = BitSet( chrom_lengths.get( chrom, options.bitset_size ) )
- bitset_dict[ chrom ].set_range( start, end - start )
- #write bitsets as profiled annotations
- for chrom_name, chrom_bits in bitset_dict.iteritems():
- out = open( os.path.join( table_out_dir, '%s.covered' % chrom_name ), 'wb' )
- end = 0
- total_regions = 0
- total_coverage = 0
- max_size = chrom_lengths.get( chrom_name, options.bitset_size )
- while True:
- start = chrom_bits.next_set( end )
- if start >= max_size:
- break
- end = chrom_bits.next_clear( start )
- out.write( struct.pack( STRUCT_FMT, start ) )
- out.write( struct.pack( STRUCT_FMT, end ) )
- total_regions += 1
- total_coverage += end - start
- if end >= max_size:
- break
- out.close()
- open( os.path.join( table_out_dir, '%s.total_regions' % chrom_name ), 'wb' ).write( str( total_regions ) )
- open( os.path.join( table_out_dir, '%s.total_coverage' % chrom_name ), 'wb' ).write( str( total_coverage ) )
-
- #create xml
- create_grouping_xml( input_dir, output_dir, options.dbkey )
- #create database dump info file, for database version control
- write_database_dump_info( input_dir, output_dir, options.dbkey, chrom_lengths, options.bitset_size )
-
-if __name__ == "__main__": __main__()
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 static/images/blat_mapping_example.png
Binary file static/images/blat_mapping_example.png has changed
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 static/images/dualcolorcode.png
Binary file static/images/dualcolorcode.png has changed
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 static/images/short_reads_boxplot.png
Binary file static/images/short_reads_boxplot.png has changed
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 test-data/annotation_profiler_1.out
--- a/test-data/annotation_profiler_1.out
+++ /dev/null
@@ -1,9 +0,0 @@
-chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + multiz17way 1700000 1
-chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + mrna 1476531 12
-chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + multiz28way 1700000 1
-chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + refGene 1247808 15
-chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + knownAlt 14617 57
-chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + affyGnf1h 16218 2
-chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + snp126 8224 7262
-chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + acembly 1532618 20
-chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + knownGene 1282789 18
diff -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 -r c559805d44df064f98dfbc94b59edba7be01adb9 test-data/annotation_profiler_2.out
--- a/test-data/annotation_profiler_2.out
+++ /dev/null
@@ -1,10 +0,0 @@
-#tableName tableChromosomeCoverage tableChromosomeCount tableRegionCoverage tableRegionCount allIntervalCount allIntervalSize allCoverage allTableRegionsOverlaped allIntervalsOverlapingTable nrIntervalCount nrIntervalSize nrCoverage nrTableRegionsOverlaped nrIntervalsOverlapingTable
-multiz17way 1232617592 115 107496500 7 25 2178864 2178864 25 25 24 2178828 2178828 7 24
-mrna 610115393 8453 53577685 617 25 2178864 1904380 38 24 24 2178828 1904344 33 23
-multiz28way 1233785185 143 107466479 10 25 2178864 2178864 25 25 24 2178828 2178828 8 24
-refGene 496767116 7324 46112187 488 25 2178864 1677947 30 23 24 2178828 1677911 27 22
-knownAlt 8647368 20213 766619 1630 25 2178864 5612 31 11 24 2178828 5612 31 11
-affyGnf1h 24034558 3995 2446754 307 25 2178864 191851 9 6 24 2178828 191851 9 6
-snp126 5297125 4456213 382226 331523 25 2178864 9205 7074 25 24 2178828 9205 7074 24
-acembly 710938193 13800 63146381 938 25 2178864 1903560 35 24 24 2178828 1903524 30 23
-knownGene 555770538 7921 50317496 558 25 2178864 1822985 30 23 24 2178828 1822949 27 22
This diff is so big that we needed to truncate the remainder.
https://bitbucket.org/galaxy/galaxy-central/commits/175bacc005a1/
Changeset: 175bacc005a1
User: davebgx
Date: 2014-05-19 19:02:11
Summary: Remove migrated tools from the tool conf files.
Affected #: 2 files
diff -r c559805d44df064f98dfbc94b59edba7be01adb9 -r 175bacc005a1437bfeedc8c76fe757467c08a870 tool_conf.xml.main
--- a/tool_conf.xml.main
+++ b/tool_conf.xml.main
@@ -51,13 +51,6 @@
<tool file="filters/wig_to_bigwig.xml" /><tool file="filters/bed_to_bigbed.xml" /></section>
- <section id="fasta_manipulation" name="FASTA manipulation">
- <tool file="fasta_tools/fasta_compute_length.xml" />
- <tool file="fasta_tools/fasta_filter_by_length.xml" />
- <tool file="fasta_tools/fasta_concatenate_by_species.xml" />
- <tool file="fasta_tools/fasta_to_tabular.xml" />
- <tool file="fasta_tools/tabular_to_fasta.xml" />
- </section><section id="filter" name="Filter and Sort"><tool file="stats/filtering.xml" /><tool file="filters/sorter.xml" />
@@ -97,9 +90,6 @@
<tool file="filters/wiggle_to_simple.xml" /><tool file="stats/aggregate_binned_scores_in_intervals.xml" /></section>
- <section id="bxops" name="Operate on Genomic Intervals">
- <tool file="annotation_profiler/annotation_profiler.xml" />
- </section><section id="stats" name="Statistics"><tool file="stats/gsummary.xml" /><tool file="filters/uniq.xml" />
@@ -116,12 +106,6 @@
<tool file="maf/vcf_to_maf_customtrack.xml" /><tool file="mutation/visualize.xml" /></section>
- <section id="multVar" name="Multivariate Analysis">
- <tool file="multivariate_stats/pca.xml" />
- <tool file="multivariate_stats/cca.xml" />
- <tool file="multivariate_stats/kpca.xml" />
- <tool file="multivariate_stats/kcca.xml" />
- </section><section id="hgv" name="Phenotype Association"><tool file="evolution/codingSnps.xml" /><tool file="evolution/add_scores.xml" />
@@ -141,8 +125,6 @@
<section id="cshl_library_information" name="NGS: QC and manipulation"><label id="illumina" text="Illumina data" /><label id="454" text="Roche-454 data" />
- <tool file="metag_tools/short_reads_figure_score.xml" />
- <tool file="metag_tools/short_reads_trim_seq.xml" /><label id="solid" text="AB-SOLiD data" /><tool file="next_gen_conversion/solid2fastq.xml" /><tool file="solid_tools/solid_qual_stats.xml" />
@@ -153,8 +135,6 @@
<section id="ngs_mapping" name="NGS: Mapping"><label id="illumina" text="Illumina" /><label id="roche_454" text="Roche-454" />
- <tool file="metag_tools/megablast_wrapper.xml" />
- <tool file="metag_tools/megablast_xml_parser.xml" /><label id="ab_solid" text="AB-SOLiD" /></section><section id="samtools" name="NGS: SAM Tools">
diff -r c559805d44df064f98dfbc94b59edba7be01adb9 -r 175bacc005a1437bfeedc8c76fe757467c08a870 tool_conf.xml.sample
--- a/tool_conf.xml.sample
+++ b/tool_conf.xml.sample
@@ -68,13 +68,11 @@
<tool file="filters/axt_to_fasta.xml" /><tool file="filters/axt_to_lav.xml" /><tool file="filters/bed2gff.xml" />
- <tool file="fasta_tools/fasta_to_tabular.xml" /><tool file="filters/gff2bed.xml" /><tool file="filters/lav_to_bed.xml" /><tool file="maf/maf_to_bed.xml" /><tool file="maf/maf_to_interval.xml" /><tool file="maf/maf_to_fasta.xml" />
- <tool file="fasta_tools/tabular_to_fasta.xml" /><tool file="filters/wiggle_to_simple.xml" /><tool file="filters/sff_extractor.xml" /><tool file="filters/gtf2bedgraph.xml" />
@@ -105,9 +103,6 @@
<tool file="filters/wiggle_to_simple.xml" /><tool file="stats/aggregate_binned_scores_in_intervals.xml" /></section>
- <section id="bxops" name="Operate on Genomic Intervals">
- <tool file="annotation_profiler/annotation_profiler.xml" />
- </section><section id="stats" name="Statistics"><tool file="stats/gsummary.xml" /><tool file="filters/uniq.xml" />
@@ -130,12 +125,6 @@
<tool file="maf/vcf_to_maf_customtrack.xml" /><tool file="mutation/visualize.xml" /></section>
- <section id="multVar" name="Multivariate Analysis">
- <tool file="multivariate_stats/pca.xml" />
- <tool file="multivariate_stats/cca.xml" />
- <tool file="multivariate_stats/kpca.xml" />
- <tool file="multivariate_stats/kcca.xml" />
- </section><section id="hyphy" name="Evolution"><tool file="evolution/codingSnps.xml" /><tool file="evolution/add_scores.xml" />
@@ -144,15 +133,6 @@
<tool file="meme/meme.xml" /><tool file="meme/fimo.xml" /></section>
- <section id="clustal" name="Multiple Alignments">
- </section>
- <section id="fasta_manipulation" name="FASTA manipulation">
- <tool file="fasta_tools/fasta_compute_length.xml" />
- <tool file="fasta_tools/fasta_filter_by_length.xml" />
- <tool file="fasta_tools/fasta_concatenate_by_species.xml" />
- <tool file="fasta_tools/fasta_to_tabular.xml" />
- <tool file="fasta_tools/tabular_to_fasta.xml" />
- </section><section id="NGS_QC" name="NGS: QC and manipulation"><label id="fastqcsambam" text="FastQC: fastq/sam/bam" />
@@ -160,9 +140,6 @@
<label id="illumina" text="Illumina fastq" /><label id="454" text="Roche-454 data" />
- <tool file="metag_tools/short_reads_figure_score.xml" />
- <tool file="metag_tools/short_reads_trim_seq.xml" />
-
<label id="solid" text="AB-SOLiD data" /><tool file="next_gen_conversion/solid2fastq.xml" /><tool file="solid_tools/solid_qual_stats.xml" />
@@ -185,8 +162,6 @@
--><section id="solexa_tools" name="NGS: Mapping"><tool file="sr_mapping/bfast_wrapper.xml" />
- <tool file="metag_tools/megablast_wrapper.xml" />
- <tool file="metag_tools/megablast_xml_parser.xml" /><tool file="sr_mapping/PerM.xml" /><tool file="sr_mapping/srma_wrapper.xml" /><tool file="sr_mapping/mosaik.xml" />
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: More performant database interaction during collection creation.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1fae433a54ea/
Changeset: 1fae433a54ea
User: jmchilton
Date: 2014-05-19 19:15:48
Summary: More performant database interaction during collection creation.
Affected #: 2 files
diff -r 9452c068ec99c52c66dcb2bbb208787f8d379d22 -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 lib/galaxy/dataset_collections/__init__.py
--- a/lib/galaxy/dataset_collections/__init__.py
+++ b/lib/galaxy/dataset_collections/__init__.py
@@ -180,7 +180,6 @@
return dataset_collection_instance
def __recursively_create_collections( self, trans, element_identifiers ):
- # TODO: Optimize - don't recheck parent, reload created model, just use as is.
for index, element_identifier in enumerate( element_identifiers ):
try:
if not element_identifier[ "src" ] == "new_collection":
@@ -197,9 +196,7 @@
collection_type=collection_type,
element_identifiers=element_identifier[ "element_identifiers" ],
)
- self.__persist( collection )
- element_identifier[ "src" ] = "dc"
- element_identifier[ "id" ] = trans.security.encode_id( collection.id )
+ element_identifier[ "__object__" ] = collection
return element_identifiers
@@ -215,7 +212,12 @@
# # consistent with other API methods though.
# element_identifier = dict( src='hda', id=str( element_identifier ) )
- # dateset_identifier is dict {src=hda|ldda, id=<encoded_id>}
+ # Previously created collection already found in request, just pass
+ # through as is.
+ if "__object__" in element_identifier:
+ return element_identifier[ "__object__" ]
+
+ # dateset_identifier is dict {src=hda|ldda|hdca|new_collection, id=<encoded_id>}
try:
src_type = element_identifier.get( 'src', 'hda' )
except AttributeError:
@@ -233,8 +235,6 @@
# TODO: Option to copy? Force copy? Copy or allow if not owned?
element = self.__get_history_collection_instance( trans, encoded_id ).collection
# TODO: ldca.
- elif src_type == "dc":
- element = self.get_dataset_collection( trans, encoded_id )
else:
raise RequestParameterInvalidException( "Unknown src_type parameter supplied '%s'." % src_type )
return element
diff -r 9452c068ec99c52c66dcb2bbb208787f8d379d22 -r 1fae433a54eaaab6392da9e9a8eec94a3b568c14 lib/galaxy/dataset_collections/util.py
--- a/lib/galaxy/dataset_collections/util.py
+++ b/lib/galaxy/dataset_collections/util.py
@@ -6,6 +6,7 @@
ERROR_MESSAGE_NO_NESTED_IDENTIFIERS = "Dataset source new_collection requires nested element_identifiers for new collection."
ERROR_MESSAGE_NO_NAME = "Cannot load invalid dataset identifier - missing name - %s"
ERROR_MESSAGE_NO_COLLECTION_TYPE = "No collection_type define for nested collection %s."
+ERROR_MESSAGE_INVALID_PARAMETER_FOUND = "Found invalid parameter %s in element identifier description %s."
def api_payload_to_create_params( payload ):
@@ -32,6 +33,9 @@
and verify the structure is valid.
"""
for element_identifier in element_identifiers:
+ if "__object__" in element_identifier:
+ message = ERROR_MESSAGE_INVALID_PARAMETER_FOUND % ( "__model_object__", element_identifier )
+ raise exceptions.RequestParameterInvalidException( message )
if "name" not in element_identifier:
message = ERROR_MESSAGE_NO_NAME % element_identifier
raise exceptions.RequestParameterInvalidException( message )
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: Rework, improve validation of dataset creation requests.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9452c068ec99/
Changeset: 9452c068ec99
User: jmchilton
Date: 2014-05-19 18:51:07
Summary: Rework, improve validation of dataset creation requests.
Being more thorough fixes some potential security problems and will allow some performance optimizations I'm planning.
Affected #: 2 files
diff -r c4404368f34df8089812f14dff298092e3ba7a81 -r 9452c068ec99c52c66dcb2bbb208787f8d379d22 lib/galaxy/dataset_collections/__init__.py
--- a/lib/galaxy/dataset_collections/__init__.py
+++ b/lib/galaxy/dataset_collections/__init__.py
@@ -1,6 +1,8 @@
from .registry import DatasetCollectionTypesRegistry
from .matching import MatchingCollections
from .type_description import CollectionTypeDescriptionFactory
+from .util import validate_input_element_identifiers
+
from galaxy import model
from galaxy.exceptions import MessageException
@@ -53,6 +55,8 @@
):
"""
"""
+ if element_identifiers:
+ validate_input_element_identifiers( element_identifiers )
dataset_collection = self.__create_dataset_collection(
trans=trans,
collection_type=collection_type,
@@ -99,6 +103,8 @@
if not collection_type:
raise RequestParameterInvalidException( ERROR_NO_COLLECTION_TYPE )
collection_type_description = self.collection_type_descriptions.for_collection_type( collection_type )
+ # If we have elements, this is an internal request, don't need to load
+ # objects from identifiers.
if elements is None:
if collection_type_description.has_subcollections( ):
# Nested collection - recursively create collections and update identifiers.
@@ -186,8 +192,6 @@
# element identifier is a dict with src new_collection...
collection_type = element_identifier.get( "collection_type", None )
- if not collection_type:
- raise RequestParameterInvalidException( "No collection_type define for nested collection." )
collection = self.__create_dataset_collection(
trans=trans,
collection_type=collection_type,
@@ -202,10 +206,6 @@
def __load_elements( self, trans, element_identifiers ):
elements = odict.odict()
for element_identifier in element_identifiers:
- if "name" not in element_identifier:
- raise RequestParameterInvalidException(
- "Cannot load invalid dataset identifier - missing name - %s" % element_identifier
- )
elements[ element_identifier[ "name" ] ] = self.__load_element( trans, element_identifier )
return elements
@@ -234,8 +234,6 @@
element = self.__get_history_collection_instance( trans, encoded_id ).collection
# TODO: ldca.
elif src_type == "dc":
- # TODO: Force only used internally during nested creation so no
- # need to recheck security.
element = self.get_dataset_collection( trans, encoded_id )
else:
raise RequestParameterInvalidException( "Unknown src_type parameter supplied '%s'." % src_type )
diff -r c4404368f34df8089812f14dff298092e3ba7a81 -r 9452c068ec99c52c66dcb2bbb208787f8d379d22 lib/galaxy/dataset_collections/util.py
--- a/lib/galaxy/dataset_collections/util.py
+++ b/lib/galaxy/dataset_collections/util.py
@@ -2,6 +2,11 @@
from galaxy import web
from galaxy import model
+ERROR_MESSAGE_UNKNOWN_SRC = "Unknown dataset source (src) %s."
+ERROR_MESSAGE_NO_NESTED_IDENTIFIERS = "Dataset source new_collection requires nested element_identifiers for new collection."
+ERROR_MESSAGE_NO_NAME = "Cannot load invalid dataset identifier - missing name - %s"
+ERROR_MESSAGE_NO_COLLECTION_TYPE = "No collection_type define for nested collection %s."
+
def api_payload_to_create_params( payload ):
"""
@@ -22,6 +27,28 @@
return params
+def validate_input_element_identifiers( element_identifiers ):
+ """ Scan through the list of element identifiers supplied by the API consumer
+ and verify the structure is valid.
+ """
+ for element_identifier in element_identifiers:
+ if "name" not in element_identifier:
+ message = ERROR_MESSAGE_NO_NAME % element_identifier
+ raise exceptions.RequestParameterInvalidException( message )
+ src = element_identifier.get( "src", "hda" )
+ if src not in [ "hda", "hdca", "ldda", "new_collection" ]:
+ message = ERROR_MESSAGE_UNKNOWN_SRC % src
+ raise exceptions.RequestParameterInvalidException( message )
+ if src == "new_collection":
+ if "element_identifiers" not in element_identifier:
+ message = ERROR_MESSAGE_NO_NESTED_IDENTIFIERS
+ raise exceptions.RequestParameterInvalidException( ERROR_MESSAGE_NO_NESTED_IDENTIFIERS )
+ if "collection_type" not in element_identifier:
+ message = ERROR_MESSAGE_NO_COLLECTION_TYPE % element_identifier
+ raise exceptions.RequestParameterInvalidException( message )
+ validate_input_element_identifiers( element_identifier[ "element_identifiers" ] )
+
+
def dictify_dataset_collection_instance( dataset_colleciton_instance, parent, security, view="element" ):
dict_value = dataset_colleciton_instance.to_dict( view=view )
encoded_id = security.encode_id( dataset_colleciton_instance.id )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Followup from commentary on PR394, cleaned up incorrect log.exception usage in base controller.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c4404368f34d/
Changeset: c4404368f34d
User: dannon
Date: 2014-05-19 18:47:10
Summary: Followup from commentary on PR394, cleaned up incorrect log.exception usage in base controller.
Affected #: 1 file
diff -r 9afc3e4a3561166beb69d344178338fa954ad5ee -r c4404368f34df8089812f14dff298092e3ba7a81 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -125,8 +125,8 @@
assert item_class is not None
item = trans.sa_session.query( item_class ).get( decoded_id )
assert item is not None
- except Exception, exc:
- log.exception( "Invalid %s id ( %s ) specified: %s" % ( class_name, id, str( exc ) ) )
+ except Exception:
+ log.exception( "Invalid %s id ( %s ) specified." % ( class_name, id ) )
raise MessageException( "Invalid %s id ( %s ) specified" % ( class_name, id ), type="error" )
if check_ownership or check_accessible:
@@ -204,7 +204,7 @@
except MessageException, e:
raise HTTPBadRequest( detail=e.err_msg )
except Exception, e:
- log.exception( "Exception in get_object check for %s %s: %s" % ( class_name, str( id ), str( e ) ) )
+ log.exception( "Exception in get_object check for %s %s." % ( class_name, str( id ) ) )
raise HTTPInternalServerError( comment=str( e ) )
def validate_in_users_and_groups( self, trans, payload ):
@@ -796,8 +796,8 @@
if expose_dataset_path:
try:
hda_dict[ 'file_name' ] = hda.file_name
- except objectstore.ObjectNotFound, onf:
- log.exception( 'objectstore.ObjectNotFound, HDA %s: %s', hda.id, onf )
+ except objectstore.ObjectNotFound:
+ log.exception( 'objectstore.ObjectNotFound, HDA %s.', hda.id )
hda_dict[ 'download_url' ] = url_for( 'history_contents_display',
history_id = trans.security.encode_id( hda.history.id ),
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9afc3e4a3561/
Changeset: 9afc3e4a3561
User: dannon
Date: 2014-05-19 18:39:59
Summary: Merge PR394 from stable.
Affected #: 2 files
diff -r 40c02d5cfc7da40d6b844a8120a019d611462e02 -r 9afc3e4a3561166beb69d344178338fa954ad5ee lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -188,7 +188,7 @@
except MessageException:
raise # handled in the caller
except:
- log.exception( "Execption in get_object check for %s %s:" % ( class_name, str( id ) ) )
+ log.exception( "Exception in get_object check for %s %s:" % ( class_name, str( id ) ) )
raise Exception( 'Server error retrieving %s id ( %s ).' % ( class_name, str( id ) ) )
@@ -204,7 +204,7 @@
except MessageException, e:
raise HTTPBadRequest( detail=e.err_msg )
except Exception, e:
- log.exception( "Execption in get_object check for %s %s: %s" % ( class_name, str( id ), str( e ) ) )
+ log.exception( "Exception in get_object check for %s %s: %s" % ( class_name, str( id ), str( e ) ) )
raise HTTPInternalServerError( comment=str( e ) )
def validate_in_users_and_groups( self, trans, payload ):
@@ -2771,7 +2771,7 @@
return self.get_object( trans, id, 'Quota', check_ownership=False, check_accessible=False, deleted=deleted )
-class UsesTagsMixin( object ):
+class UsesTagsMixin( SharableItemSecurityMixin ):
def get_tag_handler( self, trans ):
return trans.app.tag_handler
diff -r 40c02d5cfc7da40d6b844a8120a019d611462e02 -r 9afc3e4a3561166beb69d344178338fa954ad5ee lib/galaxy/webapps/galaxy/api/item_tags.py
--- a/lib/galaxy/webapps/galaxy/api/item_tags.py
+++ b/lib/galaxy/webapps/galaxy/api/item_tags.py
@@ -4,7 +4,7 @@
import logging
from galaxy import web
from galaxy.web.base.controller import BaseAPIController, UsesTagsMixin
-from paste.httpexceptions import HTTPNotImplemented, HTTPBadRequest
+from paste.httpexceptions import HTTPBadRequest
log = logging.getLogger( __name__ )
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: nsoranzo: Fix for "'HistoryTagsController' object has no attribute 'security_check'".
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/68a8b0397947/
Changeset: 68a8b0397947
Branch: stable
User: nsoranzo
Date: 2014-05-19 18:03:21
Summary: Fix for "'HistoryTagsController' object has no attribute 'security_check'".
Trying to access /api/histories/$history_id/tags gives this error:
Execption in get_object check for History 1723db999e478a37: 'HistoryTagsController' object has no attribute 'security_check'
Traceback (most recent call last):
File "/opt/galaxy/lib/galaxy/web/base/controller.py", line 233, in get_object
check_ownership=check_ownership, check_accessible=check_accessible, deleted=deleted )
File "/opt/galaxy/lib/galaxy/web/base/controller.py", line 131, in get_object
self.security_check( trans, item, check_ownership, check_accessible )
AttributeError: 'HistoryTagsController' object has no attribute 'security_check'
The same happens for workflow tags.
Affected #: 2 files
diff -r cc0fe62e54dc59607c26cd9152ef1ea7c85af625 -r 68a8b0397947c732b28207d465d3f3c4e2a7a8a0 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -221,7 +221,7 @@
except MessageException:
raise # handled in the caller
except:
- log.exception( "Execption in get_object check for %s %s:" % ( class_name, str( id ) ) )
+ log.exception( "Exception in get_object check for %s %s:" % ( class_name, str( id ) ) )
raise Exception( 'Server error retrieving %s id ( %s ).' % ( class_name, str( id ) ) )
@@ -237,7 +237,7 @@
except MessageException, e:
raise HTTPBadRequest( detail=e.err_msg )
except Exception, e:
- log.exception( "Execption in get_object check for %s %s: %s" % ( class_name, str( id ), str( e ) ) )
+ log.exception( "Exception in get_object check for %s %s: %s" % ( class_name, str( id ), str( e ) ) )
raise HTTPInternalServerError( comment=str( e ) )
def validate_in_users_and_groups( self, trans, payload ):
@@ -2779,7 +2779,7 @@
return self.get_object( trans, id, 'Quota', check_ownership=False, check_accessible=False, deleted=deleted )
-class UsesTagsMixin( object ):
+class UsesTagsMixin( SharableItemSecurityMixin ):
def get_tag_handler( self, trans ):
return trans.app.tag_handler
diff -r cc0fe62e54dc59607c26cd9152ef1ea7c85af625 -r 68a8b0397947c732b28207d465d3f3c4e2a7a8a0 lib/galaxy/webapps/galaxy/api/item_tags.py
--- a/lib/galaxy/webapps/galaxy/api/item_tags.py
+++ b/lib/galaxy/webapps/galaxy/api/item_tags.py
@@ -4,7 +4,7 @@
import logging
from galaxy import web
from galaxy.web.base.controller import BaseAPIController, UsesTagsMixin
-from paste.httpexceptions import HTTPNotImplemented, HTTPBadRequest
+from paste.httpexceptions import HTTPBadRequest
log = logging.getLogger( __name__ )
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: More reworking of job logging.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/40c02d5cfc7d/
Changeset: 40c02d5cfc7d
User: jmchilton
Date: 2014-05-19 18:02:59
Summary: More reworking of job logging.
Drop now duplicated log message in drmaa, condor, cli, etc.... Have local job runner report which job script it is running - but log it as a job script. For each job runner log the full command-line which includes dependency resolution and not the base version produced directly by the tool and use the old format from the external runners.
Affected #: 7 files
diff -r f73317a85e5cc38492e0338538ada18484701030 -r 40c02d5cfc7da40d6b844a8120a019d611462e02 lib/galaxy/jobs/command_factory.py
--- a/lib/galaxy/jobs/command_factory.py
+++ b/lib/galaxy/jobs/command_factory.py
@@ -19,8 +19,8 @@
- commands to set metadata (if include_metadata is True)
"""
base_command_line = job_wrapper.get_command_line()
- job_id = job_wrapper.job_id
- log.debug( 'Tool evaluation for job (%s) produced command-line: %s' % ( job_id, base_command_line ) )
+ # job_id = job_wrapper.job_id
+ # log.debug( 'Tool evaluation for job (%s) produced command-line: %s' % ( job_id, base_command_line ) )
commands_builder = CommandsBuilder(base_command_line)
# All job runners currently handle this case which should never occur
diff -r f73317a85e5cc38492e0338538ada18484701030 -r 40c02d5cfc7da40d6b844a8120a019d611462e02 lib/galaxy/jobs/runners/__init__.py
--- a/lib/galaxy/jobs/runners/__init__.py
+++ b/lib/galaxy/jobs/runners/__init__.py
@@ -268,8 +268,8 @@
)
## Additional logging to enable if debugging from_work_dir handling, metadata
## commands, etc... (or just peak in the job script.)
- # job_id = job_wrapper.job_id
- # log.debug( 'Extended command-line for job (%s) is: %s' % ( job_id, command_line ) )
+ job_id = job_wrapper.job_id
+ log.debug( '(%s) command is: %s' % ( job_id, command_line ) )
options.update(**kwds)
return job_script(**options)
diff -r f73317a85e5cc38492e0338538ada18484701030 -r 40c02d5cfc7da40d6b844a8120a019d611462e02 lib/galaxy/jobs/runners/cli.py
--- a/lib/galaxy/jobs/runners/cli.py
+++ b/lib/galaxy/jobs/runners/cli.py
@@ -91,7 +91,6 @@
return
log.debug( "(%s) submitting file: %s" % ( galaxy_id_tag, ajs.job_file ) )
- log.debug( "(%s) command is: %s" % ( galaxy_id_tag, command_line ) )
cmd_out = shell.execute(job_interface.submit(ajs.job_file))
if cmd_out.returncode != 0:
diff -r f73317a85e5cc38492e0338538ada18484701030 -r 40c02d5cfc7da40d6b844a8120a019d611462e02 lib/galaxy/jobs/runners/condor.py
--- a/lib/galaxy/jobs/runners/condor.py
+++ b/lib/galaxy/jobs/runners/condor.py
@@ -120,7 +120,6 @@
return
log.debug( "(%s) submitting file %s" % ( galaxy_id_tag, executable ) )
- log.debug( "(%s) command is: %s" % ( galaxy_id_tag, command_line ) )
external_job_id, message = condor_submit(submit_file)
if external_job_id is None:
diff -r f73317a85e5cc38492e0338538ada18484701030 -r 40c02d5cfc7da40d6b844a8120a019d611462e02 lib/galaxy/jobs/runners/drmaa.py
--- a/lib/galaxy/jobs/runners/drmaa.py
+++ b/lib/galaxy/jobs/runners/drmaa.py
@@ -114,9 +114,6 @@
if not self.prepare_job( job_wrapper, include_metadata=True ):
return
- # command line has been added to the wrapper by prepare_job()
- command_line = job_wrapper.runner_command_line
-
# get configured job destination
job_destination = job_wrapper.job_destination
@@ -164,7 +161,6 @@
return
log.debug( "(%s) submitting file %s", galaxy_id_tag, ajs.job_file )
- log.debug( "(%s) command is: %s", galaxy_id_tag, command_line )
if native_spec:
log.debug( "(%s) native specification is: %s", galaxy_id_tag, native_spec )
diff -r f73317a85e5cc38492e0338538ada18484701030 -r 40c02d5cfc7da40d6b844a8120a019d611462e02 lib/galaxy/jobs/runners/local.py
--- a/lib/galaxy/jobs/runners/local.py
+++ b/lib/galaxy/jobs/runners/local.py
@@ -88,6 +88,7 @@
try:
stdout_file = tempfile.NamedTemporaryFile( suffix='_stdout', dir=job_wrapper.working_directory )
stderr_file = tempfile.NamedTemporaryFile( suffix='_stderr', dir=job_wrapper.working_directory )
+ log.debug( '(%s) executing job script: %s' % ( job_id, command_line ) )
proc = subprocess.Popen( args=command_line,
shell=True,
cwd=job_wrapper.working_directory,
diff -r f73317a85e5cc38492e0338538ada18484701030 -r 40c02d5cfc7da40d6b844a8120a019d611462e02 lib/galaxy/jobs/runners/pbs.py
--- a/lib/galaxy/jobs/runners/pbs.py
+++ b/lib/galaxy/jobs/runners/pbs.py
@@ -317,7 +317,6 @@
# (if a TaskWrapper was passed in):
galaxy_job_id = job_wrapper.get_id_tag()
log.debug("(%s) submitting file %s" % ( galaxy_job_id, job_file ) )
- log.debug("(%s) command is: %s" % ( galaxy_job_id, command_line ) )
tries = 0
while tries < 5:
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
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/f73317a85e5c/
Changeset: f73317a85e5c
User: jmchilton
Date: 2014-05-19 17:16:12
Summary: Improved job logging.
Remove now less useful local runner command-line log statement (still contend it will be valuable for debugging purposes to be able to tweak and rerun the exact script - but point taken :)) . Remove stray statement added in ff4b5fe. Add new logging statement that logs just the base command-line produced by tools for all job runners. Add little note to runners/__init__.py about how to produce an extended command-line logging (with metadata handling, dependencies, and from_work_dir handling).
Affected #: 4 files
diff -r 42ced7ee518c0035dba9514b255ca1dbb8dd4c1a -r f73317a85e5cc38492e0338538ada18484701030 lib/galaxy/datatypes/metadata.py
--- a/lib/galaxy/datatypes/metadata.py
+++ b/lib/galaxy/datatypes/metadata.py
@@ -658,7 +658,6 @@
__get_filename_override(),
metadata_path_on_compute(metadata_files.filename_override_metadata),
)
- log.info(line)
return line
if not isinstance( datasets, list ):
datasets = [ datasets ]
diff -r 42ced7ee518c0035dba9514b255ca1dbb8dd4c1a -r f73317a85e5cc38492e0338538ada18484701030 lib/galaxy/jobs/command_factory.py
--- a/lib/galaxy/jobs/command_factory.py
+++ b/lib/galaxy/jobs/command_factory.py
@@ -4,6 +4,9 @@
CAPTURE_RETURN_CODE = "return_code=$?"
YIELD_CAPTURED_CODE = 'sh -c "exit $return_code"'
+from logging import getLogger
+log = getLogger( __name__ )
+
def build_command( runner, job_wrapper, include_metadata=False, include_work_dir_outputs=True, remote_command_params={} ):
"""
@@ -15,8 +18,10 @@
- command line taken from job wrapper
- commands to set metadata (if include_metadata is True)
"""
-
- commands_builder = CommandsBuilder(job_wrapper.get_command_line())
+ base_command_line = job_wrapper.get_command_line()
+ job_id = job_wrapper.job_id
+ log.debug( 'Tool evaluation for job (%s) produced command-line: %s' % ( job_id, base_command_line ) )
+ commands_builder = CommandsBuilder(base_command_line)
# All job runners currently handle this case which should never occur
if not commands_builder.commands:
diff -r 42ced7ee518c0035dba9514b255ca1dbb8dd4c1a -r f73317a85e5cc38492e0338538ada18484701030 lib/galaxy/jobs/runners/__init__.py
--- a/lib/galaxy/jobs/runners/__init__.py
+++ b/lib/galaxy/jobs/runners/__init__.py
@@ -151,7 +151,11 @@
# Prepare the job
try:
job_wrapper.prepare()
- job_wrapper.runner_command_line = self.build_command_line( job_wrapper, include_metadata=include_metadata, include_work_dir_outputs=include_work_dir_outputs )
+ job_wrapper.runner_command_line = self.build_command_line(
+ job_wrapper,
+ include_metadata=include_metadata,
+ include_work_dir_outputs=include_work_dir_outputs
+ )
except:
log.exception("(%s) Failure preparing job" % job_id)
job_wrapper.fail( "failure preparing job", exception=True )
@@ -254,13 +258,18 @@
envs = destination.get( "env", [] )
for env in envs:
env_setup_commands.append( env_to_statement( env ) )
+ command_line = job_wrapper.runner_command_line
options = dict(
job_instrumenter=job_instrumenter,
galaxy_lib=job_wrapper.galaxy_lib_dir,
env_setup_commands=env_setup_commands,
working_directory=os.path.abspath( job_wrapper.working_directory ),
- command=job_wrapper.runner_command_line,
+ command=command_line,
)
+ ## Additional logging to enable if debugging from_work_dir handling, metadata
+ ## commands, etc... (or just peak in the job script.)
+ # job_id = job_wrapper.job_id
+ # log.debug( 'Extended command-line for job (%s) is: %s' % ( job_id, command_line ) )
options.update(**kwds)
return job_script(**options)
diff -r 42ced7ee518c0035dba9514b255ca1dbb8dd4c1a -r f73317a85e5cc38492e0338538ada18484701030 lib/galaxy/jobs/runners/local.py
--- a/lib/galaxy/jobs/runners/local.py
+++ b/lib/galaxy/jobs/runners/local.py
@@ -86,7 +86,6 @@
job_id = job_wrapper.get_id_tag()
try:
- log.debug( '(%s) executing: %s' % ( job_id, command_line ) )
stdout_file = tempfile.NamedTemporaryFile( suffix='_stdout', dir=job_wrapper.working_directory )
stderr_file = tempfile.NamedTemporaryFile( suffix='_stderr', dir=job_wrapper.working_directory )
proc = subprocess.Popen( args=command_line,
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Fixes for genomespace exporter recieving UnvalidatedValue objects.
by commits-noreply@bitbucket.org 19 May '14
by commits-noreply@bitbucket.org 19 May '14
19 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/42ced7ee518c/
Changeset: 42ced7ee518c
User: dan
Date: 2014-05-19 16:17:36
Summary: Fixes for genomespace exporter recieving UnvalidatedValue objects.
Affected #: 1 file
diff -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 -r 42ced7ee518c0035dba9514b255ca1dbb8dd4c1a tools/genomespace/genomespace_exporter.py
--- a/tools/genomespace/genomespace_exporter.py
+++ b/tools/genomespace/genomespace_exporter.py
@@ -120,7 +120,13 @@
def galaxy_code_get_genomespace_folders( genomespace_site='prod', trans=None, value=None, base_url=None, **kwd ):
if value:
- value = value[0]#single select, only 1 value
+ if isinstance( value, list ):
+ value = value[0] #single select, only 1 value
+ elif not isinstance( value, basestring ):
+ #unvalidated value
+ value = value.value
+ if isinstance( value, list ):
+ value = value[0] #single select, only 1 value
def recurse_directory_dict( url_opener, cur_options, url ):
cur_directory = urllib2.Request( url, headers = { 'Content-Type': 'application/json', 'Accept': 'application/json, text/plain' } )
cur_directory.get_method = lambda: 'GET'
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 (pull request #384)
by commits-noreply@bitbucket.org 18 May '14
by commits-noreply@bitbucket.org 18 May '14
18 May '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5bf39d99f789/
Changeset: 5bf39d99f789
User: jmchilton
Date: 2014-05-19 04:12:36
Summary: Merged in jmchilton/galaxy-central-fork-1 (pull request #384)
Local Job Runner Enhancements
Affected #: 5 files
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -1163,6 +1163,11 @@
return 'Job ran longer than the maximum allowed execution time (%s), please try different inputs or parameters' % self.app.job_config.limits.walltime
return None
+ def has_limits( self ):
+ has_output_limit = self.app.job_config.limits.output_size > 0
+ has_walltime_limit = self.app.job_config.limits.walltime_delta is not None
+ return has_output_limit or has_walltime_limit
+
def get_command_line( self ):
return self.command_line
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 lib/galaxy/jobs/runners/__init__.py
--- a/lib/galaxy/jobs/runners/__init__.py
+++ b/lib/galaxy/jobs/runners/__init__.py
@@ -196,7 +196,7 @@
output_pairs = []
# Walk job's output associations to find and use from_work_dir attributes.
job = job_wrapper.get_job()
- job_tool = self.app.toolbox.tools_by_id.get( job.tool_id, None )
+ job_tool = job_wrapper.tool
for dataset_assoc in job.output_datasets + job.output_library_datasets:
for dataset in dataset_assoc.dataset.dataset.history_associations + dataset_assoc.dataset.dataset.library_associations:
if isinstance( dataset, self.app.model.HistoryDatasetAssociation ):
@@ -269,7 +269,36 @@
self.work_queue.put( ( self.finish_job, ajs ) )
-class AsynchronousJobState( object ):
+class JobState( object ):
+ """
+ Encapsulate state of jobs.
+ """
+
+ def set_defaults( self, files_dir ):
+ if self.job_wrapper is not None:
+ id_tag = self.job_wrapper.get_id_tag()
+ if files_dir is not None:
+ self.job_file = JobState.default_job_file( files_dir, id_tag )
+ self.output_file = os.path.join( files_dir, 'galaxy_%s.o' % id_tag )
+ self.error_file = os.path.join( files_dir, 'galaxy_%s.e' % id_tag )
+ self.exit_code_file = os.path.join( files_dir, 'galaxy_%s.ec' % id_tag )
+ job_name = 'g%s' % id_tag
+ if self.job_wrapper.tool.old_id:
+ job_name += '_%s' % self.job_wrapper.tool.old_id
+ if self.job_wrapper.user:
+ job_name += '_%s' % self.job_wrapper.user
+ self.job_name = ''.join( map( lambda x: x if x in ( string.letters + string.digits + '_' ) else '_', job_name ) )
+
+ @staticmethod
+ def default_job_file( files_dir, id_tag ):
+ return os.path.join( files_dir, 'galaxy_%s.sh' % id_tag )
+
+ @staticmethod
+ def default_exit_code_file( files_dir, id_tag ):
+ return os.path.join( files_dir, 'galaxy_%s.ec' % id_tag )
+
+
+class AsynchronousJobState( JobState ):
"""
Encapsulate the state of an asynchronous job, this should be subclassed as
needed for various job runners to capture additional information needed
@@ -296,21 +325,6 @@
self.cleanup_file_attributes = [ 'job_file', 'output_file', 'error_file', 'exit_code_file' ]
- def set_defaults( self, files_dir ):
- if self.job_wrapper is not None:
- id_tag = self.job_wrapper.get_id_tag()
- if files_dir is not None:
- self.job_file = os.path.join( files_dir, 'galaxy_%s.sh' % id_tag )
- self.output_file = os.path.join( files_dir, 'galaxy_%s.o' % id_tag )
- self.error_file = os.path.join( files_dir, 'galaxy_%s.e' % id_tag )
- self.exit_code_file = os.path.join( files_dir, 'galaxy_%s.ec' % id_tag )
- job_name = 'g%s' % id_tag
- if self.job_wrapper.tool.old_id:
- job_name += '_%s' % self.job_wrapper.tool.old_id
- if self.job_wrapper.user:
- job_name += '_%s' % self.job_wrapper.user
- self.job_name = ''.join( map( lambda x: x if x in ( string.letters + string.digits + '_' ) else '_', job_name ) )
-
def cleanup( self ):
for file in [ getattr( self, a ) for a in self.cleanup_file_attributes if hasattr( self, a ) ]:
try:
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 lib/galaxy/jobs/runners/local.py
--- a/lib/galaxy/jobs/runners/local.py
+++ b/lib/galaxy/jobs/runners/local.py
@@ -11,13 +11,20 @@
from time import sleep
from galaxy import model
-from galaxy.jobs.runners import BaseJobRunner
+from ..runners import BaseJobRunner
+from ..runners import JobState
from galaxy.util import DATABASE_MAX_STRING_SIZE, shrink_stream_by_size
+from galaxy.util import asbool
log = logging.getLogger( __name__ )
__all__ = [ 'LocalJobRunner' ]
+DEFAULT_POOL_SLEEP_TIME = 1
+# TODO: Set to false and just get rid of this option. It would simplify this
+# class nicely. -John
+DEFAULT_EMBED_METADATA_IN_JOB = False
+
class LocalJobRunner( BaseJobRunner ):
"""
@@ -31,12 +38,6 @@
#create a local copy of os.environ to use as env for subprocess.Popen
self._environ = os.environ.copy()
- # put lib into the PYTHONPATH for subprocesses
- if 'PYTHONPATH' in self._environ:
- self._environ['PYTHONPATH'] = '%s:%s' % ( self._environ['PYTHONPATH'], os.path.abspath( 'lib' ) )
- else:
- self._environ['PYTHONPATH'] = os.path.abspath( 'lib' )
-
#Set TEMP if a valid temp value is not already set
if not ( 'TMPDIR' in self._environ or 'TEMP' in self._environ or 'TMP' in self._environ ):
self._environ[ 'TEMP' ] = os.path.abspath(tempfile.gettempdir())
@@ -52,24 +53,36 @@
## slots would be cleaner name, but don't want deployers to see examples and think it
## is going to work with other job runners.
slots = job_wrapper.job_destination.params.get( "local_slots", None )
- command_line = command_line.lstrip( " ;" )
if slots:
- command_line = 'GALAXY_SLOTS="%d"; export GALAXY_SLOTS; GALAXY_SLOTS_CONFIGURED="1"; export GALAXY_SLOTS_CONFIGURED; %s' % ( int( slots ), command_line )
+ slots_statement = 'GALAXY_SLOTS="%d"; export GALAXY_SLOTS; GALAXY_SLOTS_CONFIGURED="1"; export GALAXY_SLOTS_CONFIGURED;' % ( int( slots ) )
else:
- command_line = 'GALAXY_SLOTS="1"; export GALAXY_SLOTS; %s' % command_line
- return command_line
+ slots_statement = 'GALAXY_SLOTS="1"; export GALAXY_SLOTS;'
+
+ job_id = job_wrapper.get_id_tag()
+ job_file = JobState.default_job_file( job_wrapper.working_directory, job_id )
+ exit_code_path = JobState.default_exit_code_file( job_wrapper.working_directory, job_id )
+ job_script_props = {
+ 'slots_statement': slots_statement,
+ 'command': command_line,
+ 'exit_code_path': exit_code_path,
+ 'working_directory': job_wrapper.working_directory,
+ }
+ job_file_contents = self.get_job_file( job_wrapper, **job_script_props )
+ open( job_file, 'w' ).write( job_file_contents )
+ os.chmod( job_file, 0755 )
+ return job_file, exit_code_path
def queue_job( self, job_wrapper ):
# prepare the job
- if not self.prepare_job( job_wrapper ):
+ include_metadata = asbool( job_wrapper.job_destination.params.get( "embed_metadata_in_job", DEFAULT_EMBED_METADATA_IN_JOB ) )
+ if not self.prepare_job( job_wrapper, include_metadata=include_metadata ):
return
stderr = stdout = ''
exit_code = 0
# command line has been added to the wrapper by prepare_job()
- command_line = self.__command_line( job_wrapper )
-
+ command_line, exit_code_path = self.__command_line( job_wrapper )
job_id = job_wrapper.get_id_tag()
try:
@@ -85,22 +98,18 @@
preexec_fn=os.setpgrp )
job_wrapper.set_job_destination(job_wrapper.job_destination, proc.pid)
job_wrapper.change_state( model.Job.states.RUNNING )
- job_start = datetime.datetime.now()
- i = 0
- # Iterate until the process exits, periodically checking its limits
- while proc.poll() is None:
- i += 1
- if (i % 20) == 0:
- msg = job_wrapper.check_limits(runtime=datetime.datetime.now() - job_start)
- if msg is not None:
- job_wrapper.fail(msg)
- log.debug('(%s) Terminating process group' % job_id)
- self._terminate(proc)
- return
- else:
- sleep(1)
+
+ terminated = self.__poll_if_needed( proc, job_wrapper, job_id )
+ if terminated:
+ return
+
# Reap the process and get the exit code.
exit_code = proc.wait()
+ try:
+ exit_code = int( open( exit_code_path, 'r' ).read() )
+ except Exception:
+ log.warn( "Failed to read exit code from path %s" % exit_code_path )
+ pass
stdout_file.seek( 0 )
stderr_file.seek( 0 )
stdout = shrink_stream_by_size( stdout_file, DATABASE_MAX_STRING_SIZE, join_by="\n..\n", left_larger=True, beginning_on_size_error=True )
@@ -112,7 +121,9 @@
log.exception("failure running job %d" % job_wrapper.job_id)
job_wrapper.fail( "failure running job", exception=True )
return
- self._handle_metadata_externally( job_wrapper, resolve_requirements=True )
+ external_metadata = not asbool( job_wrapper.job_destination.params.get( "embed_metadata_in_job", DEFAULT_EMBED_METADATA_IN_JOB ) )
+ if external_metadata:
+ self._handle_metadata_externally( job_wrapper, resolve_requirements=True )
# Finish the job!
try:
job_wrapper.finish( stdout, stderr, exit_code )
@@ -168,3 +179,23 @@
if proc.poll() is None:
os.killpg( proc.pid, 9 )
return proc.wait() # reap
+
+ def __poll_if_needed( self, proc, job_wrapper, job_id ):
+ # Only poll if needed (i.e. job limits are set)
+ if not job_wrapper.has_limits():
+ return
+
+ job_start = datetime.datetime.now()
+ i = 0
+ # Iterate until the process exits, periodically checking its limits
+ while proc.poll() is None:
+ i += 1
+ if (i % 20) == 0:
+ msg = job_wrapper.check_limits(runtime=datetime.datetime.now() - job_start)
+ if msg is not None:
+ job_wrapper.fail(msg)
+ log.debug('(%s) Terminating process group' % job_id)
+ self._terminate(proc)
+ return True
+ else:
+ sleep( DEFAULT_POOL_SLEEP_TIME )
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 test/unit/jobs/test_runner_local.py
--- /dev/null
+++ b/test/unit/jobs/test_runner_local.py
@@ -0,0 +1,166 @@
+import os
+import threading
+import time
+from unittest import TestCase
+
+from galaxy.util import bunch
+from galaxy.jobs.runners import local
+from galaxy.jobs import metrics
+from galaxy import model
+
+from tools_support import (
+ UsesApp,
+ UsesTools
+)
+
+
+class TestLocalJobRunner( TestCase, UsesApp, UsesTools ):
+
+ def setUp( self ):
+ self.setup_app()
+ self._init_tool()
+ self.app.job_metrics = metrics.JobMetrics()
+ self.job_wrapper = MockJobWrapper( self.app, self.test_directory, self.tool )
+
+ def tearDown( self ):
+ self.tear_down_app()
+
+ def test_run( self ):
+ self.job_wrapper.command_line = "echo HelloWorld"
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.stdout.strip() == "HelloWorld"
+
+ def test_galaxy_lib_on_path( self ):
+ self.job_wrapper.command_line = '''python -c "import galaxy.util"'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.exit_code == 0
+
+ def test_default_slots( self ):
+ self.job_wrapper.command_line = '''echo $GALAXY_SLOTS'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.stdout.strip() == "1"
+
+ def test_slots_override( self ):
+ # Set local_slots in job destination to specify slots for
+ # local job runner.
+ self.job_wrapper.job_destination.params[ "local_slots" ] = 3
+ self.job_wrapper.command_line = '''echo $GALAXY_SLOTS'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.stdout.strip() == "3"
+
+ def test_exit_code( self ):
+ self.job_wrapper.command_line = '''sh -c "exit 4"'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.exit_code == 4
+
+ def test_metadata_gets_set( self ):
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert os.path.exists( self.job_wrapper.mock_metadata_path )
+
+ def test_metadata_gets_set_if_embedded( self ):
+ self.job_wrapper.job_destination.params[ "embed_metadata_in_job" ] = "True"
+
+ # Kill off cruft for _handle_metadata_externally and make sure job stil works...
+ self.job_wrapper.external_output_metadata = None
+ self.app.datatypes_registry.set_external_metadata_tool = None
+
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert os.path.exists( self.job_wrapper.mock_metadata_path )
+
+ def test_stopping_job( self ):
+ self.job_wrapper.command_line = '''python -c "import time; time.sleep(15)"'''
+ runner = local.LocalJobRunner( self.app, 1 )
+
+ def queue():
+ runner.queue_job( self.job_wrapper )
+
+ t = threading.Thread(target=queue)
+ t.start()
+ while True:
+ if self.job_wrapper.external_id:
+ break
+ time.sleep( .01 )
+ external_id = self.job_wrapper.external_id
+ mock_job = bunch.Bunch(
+ get_external_output_metadata=lambda: None,
+ get_job_runner_external_id=lambda: str(external_id),
+ get_id=lambda: 1
+ )
+ runner.stop_job( mock_job )
+ t.join(1)
+
+
+class MockJobWrapper( object ):
+
+ def __init__( self, app, test_directory, tool ):
+ working_directory = os.path.join( test_directory, "workdir" )
+ os.makedirs( working_directory )
+ self.app = app
+ self.tool = tool
+ self.state = model.Job.states.QUEUED
+ self.command_line = "echo HelloWorld"
+ self.prepare_called = False
+ self.write_version_cmd = None
+ self.dependency_shell_commands = None
+ self.working_directory = working_directory
+ self.requires_setting_metadata = True
+ self.job_destination = bunch.Bunch( id="default", params={} )
+ self.galaxy_lib_dir = os.path.abspath( "lib" )
+ self.job_id = 1
+ self.external_id = None
+ self.output_paths = [ '/tmp/output1.dat' ]
+ self.mock_metadata_path = os.path.abspath( os.path.join( test_directory, "METADATA_SET" ) )
+ self.metadata_command = "touch %s" % self.mock_metadata_path
+
+ # Cruft for setting metadata externally, axe at some point.
+ self.external_output_metadata = bunch.Bunch(
+ set_job_runner_external_pid=lambda pid, session: None
+ )
+ self.app.datatypes_registry.set_external_metadata_tool = bunch.Bunch(
+ build_dependency_shell_commands=lambda: []
+ )
+
+ def prepare( self ):
+ self.prepare_called = True
+
+ def set_job_destination( self, job_destination, external_id ):
+ self.external_id = external_id
+
+ def get_command_line( self ):
+ return self.command_line
+
+ def get_id_tag( self ):
+ return "1"
+
+ def get_state( self ):
+ return self.state
+
+ def change_state( self, state ):
+ self.state = state
+
+ def get_output_fnames( self ):
+ return []
+
+ def get_job( self ):
+ return model.Job()
+
+ def setup_external_metadata( self, **kwds ):
+ return self.metadata_command
+
+ def get_env_setup_clause( self ):
+ return ""
+
+ def has_limits( self ):
+ return False
+
+ def finish( self, stdout, stderr, exit_code ):
+ self.stdout = stdout
+ self.stderr = stderr
+ self.exit_code = exit_code
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 test/unit/tools_support.py
--- a/test/unit/tools_support.py
+++ b/test/unit/tools_support.py
@@ -58,7 +58,7 @@
class UsesTools( object ):
- def _init_tool( self, tool_contents ):
+ def _init_tool( self, tool_contents=SIMPLE_TOOL_CONTENTS ):
self.tool_file = os.path.join( self.test_directory, "tool.xml" )
self.app.config.drmaa_external_runjob_script = ""
self.app.config.tool_secret = "testsecret"
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
7 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bed23d528080/
Changeset: bed23d528080
User: jmchilton
Date: 2014-05-05 19:35:09
Summary: Simplify command for grabbing tool in get_work_dir_outputs.
Subtlely reduces code duplication and makes runners slightly easier to unit test (fewer dependencies).
Affected #: 1 file
diff -r b94b4da49bfdf4f204d0ad2dce878a37e6e4f3d3 -r bed23d5280808dbc2d6b56ddcfe572e9bedda97a lib/galaxy/jobs/runners/__init__.py
--- a/lib/galaxy/jobs/runners/__init__.py
+++ b/lib/galaxy/jobs/runners/__init__.py
@@ -196,7 +196,7 @@
output_pairs = []
# Walk job's output associations to find and use from_work_dir attributes.
job = job_wrapper.get_job()
- job_tool = self.app.toolbox.tools_by_id.get( job.tool_id, None )
+ job_tool = job_wrapper.tool
for dataset_assoc in job.output_datasets + job.output_library_datasets:
for dataset in dataset_assoc.dataset.dataset.history_associations + dataset_assoc.dataset.dataset.library_associations:
if isinstance( dataset, self.app.model.HistoryDatasetAssociation ):
https://bitbucket.org/galaxy/galaxy-central/commits/51c248b80e72/
Changeset: 51c248b80e72
User: jmchilton
Date: 2014-05-05 19:35:09
Summary: Unit tests for local job runner.
Test running, capturing standard output and exit code, killing job, setting metadata, adding Galaxy to jobs PYTHONPATH, GALAXY_SLOTS logic (default and overidding).
Affected #: 2 files
diff -r bed23d5280808dbc2d6b56ddcfe572e9bedda97a -r 51c248b80e729ec6a3ef39e851ebdf79ef888476 test/unit/jobs/test_runner_local.py
--- /dev/null
+++ b/test/unit/jobs/test_runner_local.py
@@ -0,0 +1,155 @@
+import os
+import threading
+import time
+from unittest import TestCase
+
+from galaxy.util import bunch
+from galaxy.jobs.runners import local
+from galaxy.jobs import metrics
+from galaxy import model
+
+from tools_support import (
+ UsesApp,
+ UsesTools
+)
+
+
+class TestLocalJobRunner( TestCase, UsesApp, UsesTools ):
+
+ def setUp( self ):
+ self.setup_app()
+ self._init_tool()
+ self.app.job_metrics = metrics.JobMetrics()
+ self.job_wrapper = MockJobWrapper( self.app, self.test_directory, self.tool )
+
+ def tearDown( self ):
+ self.tear_down_app()
+
+ def test_run( self ):
+ self.job_wrapper.command_line = "echo HelloWorld"
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.stdout.strip() == "HelloWorld"
+
+ def test_galaxy_lib_on_path( self ):
+ self.job_wrapper.command_line = '''python -c "import galaxy.util"'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.exit_code == 0
+
+ def test_default_slots( self ):
+ self.job_wrapper.command_line = '''echo $GALAXY_SLOTS'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.stdout.strip() == "1"
+
+ def test_slots_override( self ):
+ # Set local_slots in job destination to specify slots for
+ # local job runner.
+ self.job_wrapper.job_destination.params[ "local_slots" ] = 3
+ self.job_wrapper.command_line = '''echo $GALAXY_SLOTS'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.stdout.strip() == "3"
+
+ def test_exit_code( self ):
+ self.job_wrapper.command_line = '''sh -c "exit 4"'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.exit_code == 4
+
+ def test_metadata_gets_set( self ):
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert os.path.exists( self.job_wrapper.mock_metadata_path )
+
+ def test_stopping_job( self ):
+ self.job_wrapper.command_line = '''python -c "import time; time.sleep(15)"'''
+ runner = local.LocalJobRunner( self.app, 1 )
+
+ def queue():
+ runner.queue_job( self.job_wrapper )
+
+ t = threading.Thread(target=queue)
+ t.start()
+ while True:
+ if self.job_wrapper.external_id:
+ break
+ time.sleep( .01 )
+ external_id = self.job_wrapper.external_id
+ mock_job = bunch.Bunch(
+ get_external_output_metadata=lambda: None,
+ get_job_runner_external_id=lambda: str(external_id),
+ get_id=lambda: 1
+ )
+ runner.stop_job( mock_job )
+ t.join(1)
+
+
+class MockJobWrapper( object ):
+
+ def __init__( self, app, test_directory, tool ):
+ working_directory = os.path.join( test_directory, "workdir" )
+ os.makedirs( working_directory )
+ self.app = app
+ self.tool = tool
+ self.state = model.Job.states.QUEUED
+ self.command_line = "echo HelloWorld"
+ self.prepare_called = False
+ self.write_version_cmd = None
+ self.dependency_shell_commands = None
+ self.working_directory = working_directory
+ self.requires_setting_metadata = True
+ self.job_destination = bunch.Bunch( id="default", params={} )
+ self.galaxy_lib_dir = os.path.abspath( "lib" )
+ self.job_id = 1
+ self.external_id = None
+ self.output_paths = [ '/tmp/output1.dat' ]
+ self.mock_metadata_path = os.path.abspath( os.path.join( test_directory, "METADATA_SET" ) )
+ self.metadata_command = "touch %s" % self.mock_metadata_path
+
+ # Cruft for setting metadata externally, axe at some point.
+ self.external_output_metadata = bunch.Bunch(
+ set_job_runner_external_pid=lambda pid, session: None
+ )
+ self.app.datatypes_registry.set_external_metadata_tool = bunch.Bunch(
+ build_dependency_shell_commands=lambda: []
+ )
+
+ def prepare( self ):
+ self.prepare_called = True
+
+ def set_job_destination( self, job_destination, external_id ):
+ self.external_id = external_id
+
+ def get_command_line( self ):
+ return self.command_line
+
+ def get_id_tag( self ):
+ return "1"
+
+ def get_state( self ):
+ return self.state
+
+ def change_state( self, state ):
+ self.state = state
+
+ def get_output_fnames( self ):
+ return []
+
+ def get_job( self ):
+ return model.Job()
+
+ def setup_external_metadata( self, **kwds ):
+ return self.metadata_command
+
+ def get_env_setup_clause( self ):
+ return ""
+
+ def has_limits( self ):
+ return False
+
+ def finish( self, stdout, stderr, exit_code ):
+ self.stdout = stdout
+ self.stderr = stderr
+ self.exit_code = exit_code
diff -r bed23d5280808dbc2d6b56ddcfe572e9bedda97a -r 51c248b80e729ec6a3ef39e851ebdf79ef888476 test/unit/tools_support.py
--- a/test/unit/tools_support.py
+++ b/test/unit/tools_support.py
@@ -58,7 +58,7 @@
class UsesTools( object ):
- def _init_tool( self, tool_contents ):
+ def _init_tool( self, tool_contents=SIMPLE_TOOL_CONTENTS ):
self.tool_file = os.path.join( self.test_directory, "tool.xml" )
self.app.config.drmaa_external_runjob_script = ""
self.app.config.tool_secret = "testsecret"
https://bitbucket.org/galaxy/galaxy-central/commits/ff666103459d/
Changeset: ff666103459d
User: jmchilton
Date: 2014-05-05 19:35:09
Summary: Refactor small __poll helper method out of local job runner's queue.
Affected #: 1 file
diff -r 51c248b80e729ec6a3ef39e851ebdf79ef888476 -r ff666103459de3c87595a1d25783d7a3283b4951 lib/galaxy/jobs/runners/local.py
--- a/lib/galaxy/jobs/runners/local.py
+++ b/lib/galaxy/jobs/runners/local.py
@@ -18,6 +18,8 @@
__all__ = [ 'LocalJobRunner' ]
+DEFAULT_POOL_SLEEP_TIME = 1
+
class LocalJobRunner( BaseJobRunner ):
"""
@@ -85,20 +87,11 @@
preexec_fn=os.setpgrp )
job_wrapper.set_job_destination(job_wrapper.job_destination, proc.pid)
job_wrapper.change_state( model.Job.states.RUNNING )
- job_start = datetime.datetime.now()
- i = 0
- # Iterate until the process exits, periodically checking its limits
- while proc.poll() is None:
- i += 1
- if (i % 20) == 0:
- msg = job_wrapper.check_limits(runtime=datetime.datetime.now() - job_start)
- if msg is not None:
- job_wrapper.fail(msg)
- log.debug('(%s) Terminating process group' % job_id)
- self._terminate(proc)
- return
- else:
- sleep(1)
+
+ terminated = self.__poll( proc, job_wrapper, job_id )
+ if terminated:
+ return
+
# Reap the process and get the exit code.
exit_code = proc.wait()
stdout_file.seek( 0 )
@@ -168,3 +161,19 @@
if proc.poll() is None:
os.killpg( proc.pid, 9 )
return proc.wait() # reap
+
+ def __poll( self, proc, job_wrapper, job_id ):
+ job_start = datetime.datetime.now()
+ i = 0
+ # Iterate until the process exits, periodically checking its limits
+ while proc.poll() is None:
+ i += 1
+ if (i % 20) == 0:
+ msg = job_wrapper.check_limits(runtime=datetime.datetime.now() - job_start)
+ if msg is not None:
+ job_wrapper.fail(msg)
+ log.debug('(%s) Terminating process group' % job_id)
+ self._terminate(proc)
+ return True
+ else:
+ sleep( DEFAULT_POOL_SLEEP_TIME )
https://bitbucket.org/galaxy/galaxy-central/commits/50de2360e451/
Changeset: 50de2360e451
User: jmchilton
Date: 2014-05-05 19:35:09
Summary: Local job runner - only poll if limits set (so can be set).
Small optimization aimed at speeding up tests - unit and functional.
Affected #: 2 files
diff -r ff666103459de3c87595a1d25783d7a3283b4951 -r 50de2360e4511b91f22ed437c1d1d62826136342 lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -1161,6 +1161,11 @@
return 'Job ran longer than the maximum allowed execution time (%s), please try different inputs or parameters' % self.app.job_config.limits.walltime
return None
+ def has_limits( self ):
+ has_output_limit = self.app.job_config.limits.output_size > 0
+ has_walltime_limit = self.app.job_config.limits.walltime_delta is not None
+ return has_output_limit or has_walltime_limit
+
def get_command_line( self ):
return self.command_line
diff -r ff666103459de3c87595a1d25783d7a3283b4951 -r 50de2360e4511b91f22ed437c1d1d62826136342 lib/galaxy/jobs/runners/local.py
--- a/lib/galaxy/jobs/runners/local.py
+++ b/lib/galaxy/jobs/runners/local.py
@@ -88,7 +88,7 @@
job_wrapper.set_job_destination(job_wrapper.job_destination, proc.pid)
job_wrapper.change_state( model.Job.states.RUNNING )
- terminated = self.__poll( proc, job_wrapper, job_id )
+ terminated = self.__poll_if_needed( proc, job_wrapper, job_id )
if terminated:
return
@@ -162,7 +162,11 @@
os.killpg( proc.pid, 9 )
return proc.wait() # reap
- def __poll( self, proc, job_wrapper, job_id ):
+ def __poll_if_needed( self, proc, job_wrapper, job_id ):
+ # Only poll if needed (i.e. job limits are set)
+ if not job_wrapper.has_limits():
+ return
+
job_start = datetime.datetime.now()
i = 0
# Iterate until the process exits, periodically checking its limits
https://bitbucket.org/galaxy/galaxy-central/commits/03d912919356/
Changeset: 03d912919356
User: jmchilton
Date: 2014-05-05 19:35:09
Summary: Allow embedding setting of metadata as part of local jobs.
(Like it works for all other runners except the LWR). This is essentially scaffolding toward elimination of extra metadata step in local runner.
Got Dan's blessing to kill this off a while ago but I still don't quite understand why it is separated out - so doing this in two parts. This changeset changes nothing by default but adds an option to local runner destinations (embed_metadata_in_job) to allow them operate in the new fashion (embed the metadata setting step in the job itself). At some later point this option should just be removed and all local jobs should operate this way. Use this new option to speed up the local job runner or to test out how this runner will work in the future.
Affected #: 2 files
diff -r 50de2360e4511b91f22ed437c1d1d62826136342 -r 03d912919356db7ff34d289985c8ee3ac2a67dd1 lib/galaxy/jobs/runners/local.py
--- a/lib/galaxy/jobs/runners/local.py
+++ b/lib/galaxy/jobs/runners/local.py
@@ -13,12 +13,16 @@
from galaxy import model
from galaxy.jobs.runners import BaseJobRunner
from galaxy.util import DATABASE_MAX_STRING_SIZE, shrink_stream_by_size
+from galaxy.util import asbool
log = logging.getLogger( __name__ )
__all__ = [ 'LocalJobRunner' ]
DEFAULT_POOL_SLEEP_TIME = 1
+# TODO: Set to false and just get rid of this option. It would simplify this
+# class nicely. -John
+DEFAULT_EMBED_METADATA_IN_JOB = False
class LocalJobRunner( BaseJobRunner ):
@@ -63,7 +67,8 @@
def queue_job( self, job_wrapper ):
# prepare the job
- if not self.prepare_job( job_wrapper ):
+ include_metadata = asbool( job_wrapper.job_destination.params.get( "embed_metadata_in_job", DEFAULT_EMBED_METADATA_IN_JOB ) )
+ if not self.prepare_job( job_wrapper, include_metadata=include_metadata ):
return
stderr = stdout = ''
@@ -105,7 +110,9 @@
log.exception("failure running job %d" % job_wrapper.job_id)
job_wrapper.fail( "failure running job", exception=True )
return
- self._handle_metadata_externally( job_wrapper, resolve_requirements=True )
+ external_metadata = not asbool( job_wrapper.job_destination.params.get( "embed_metadata_in_job", DEFAULT_EMBED_METADATA_IN_JOB ) )
+ if external_metadata:
+ self._handle_metadata_externally( job_wrapper, resolve_requirements=True )
# Finish the job!
try:
job_wrapper.finish( stdout, stderr, exit_code )
diff -r 50de2360e4511b91f22ed437c1d1d62826136342 -r 03d912919356db7ff34d289985c8ee3ac2a67dd1 test/unit/jobs/test_runner_local.py
--- a/test/unit/jobs/test_runner_local.py
+++ b/test/unit/jobs/test_runner_local.py
@@ -63,6 +63,17 @@
runner.queue_job( self.job_wrapper )
assert os.path.exists( self.job_wrapper.mock_metadata_path )
+ def test_metadata_gets_set_if_embedded( self ):
+ self.job_wrapper.job_destination.params[ "embed_metadata_in_job" ] = "True"
+
+ # Kill off cruft for _handle_metadata_externally and make sure job stil works...
+ self.job_wrapper.external_output_metadata = None
+ self.app.datatypes_registry.set_external_metadata_tool = None
+
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert os.path.exists( self.job_wrapper.mock_metadata_path )
+
def test_stopping_job( self ):
self.job_wrapper.command_line = '''python -c "import time; time.sleep(15)"'''
runner = local.LocalJobRunner( self.app, 1 )
https://bitbucket.org/galaxy/galaxy-central/commits/e1db77201a5d/
Changeset: e1db77201a5d
User: jmchilton
Date: 2014-05-05 19:35:09
Summary: Rework local job runner to create job script.
Affected #: 2 files
diff -r 03d912919356db7ff34d289985c8ee3ac2a67dd1 -r e1db77201a5d9e93cf7729c2695c34e98abf5252 lib/galaxy/jobs/runners/__init__.py
--- a/lib/galaxy/jobs/runners/__init__.py
+++ b/lib/galaxy/jobs/runners/__init__.py
@@ -270,7 +270,36 @@
self.work_queue.put( ( self.finish_job, ajs ) )
-class AsynchronousJobState( object ):
+class JobState( object ):
+ """
+ Encapsulate state of jobs.
+ """
+
+ def set_defaults( self, files_dir ):
+ if self.job_wrapper is not None:
+ id_tag = self.job_wrapper.get_id_tag()
+ if files_dir is not None:
+ self.job_file = JobState.default_job_file( files_dir, id_tag )
+ self.output_file = os.path.join( files_dir, 'galaxy_%s.o' % id_tag )
+ self.error_file = os.path.join( files_dir, 'galaxy_%s.e' % id_tag )
+ self.exit_code_file = os.path.join( files_dir, 'galaxy_%s.ec' % id_tag )
+ job_name = 'g%s' % id_tag
+ if self.job_wrapper.tool.old_id:
+ job_name += '_%s' % self.job_wrapper.tool.old_id
+ if self.job_wrapper.user:
+ job_name += '_%s' % self.job_wrapper.user
+ self.job_name = ''.join( map( lambda x: x if x in ( string.letters + string.digits + '_' ) else '_', job_name ) )
+
+ @staticmethod
+ def default_job_file( files_dir, id_tag ):
+ return os.path.join( files_dir, 'galaxy_%s.sh' % id_tag )
+
+ @staticmethod
+ def default_exit_code_file( files_dir, id_tag ):
+ return os.path.join( files_dir, 'galaxy_%s.ec' % id_tag )
+
+
+class AsynchronousJobState( JobState ):
"""
Encapsulate the state of an asynchronous job, this should be subclassed as
needed for various job runners to capture additional information needed
@@ -297,21 +326,6 @@
self.cleanup_file_attributes = [ 'job_file', 'output_file', 'error_file', 'exit_code_file' ]
- def set_defaults( self, files_dir ):
- if self.job_wrapper is not None:
- id_tag = self.job_wrapper.get_id_tag()
- if files_dir is not None:
- self.job_file = os.path.join( files_dir, 'galaxy_%s.sh' % id_tag )
- self.output_file = os.path.join( files_dir, 'galaxy_%s.o' % id_tag )
- self.error_file = os.path.join( files_dir, 'galaxy_%s.e' % id_tag )
- self.exit_code_file = os.path.join( files_dir, 'galaxy_%s.ec' % id_tag )
- job_name = 'g%s' % id_tag
- if self.job_wrapper.tool.old_id:
- job_name += '_%s' % self.job_wrapper.tool.old_id
- if self.job_wrapper.user:
- job_name += '_%s' % self.job_wrapper.user
- self.job_name = ''.join( map( lambda x: x if x in ( string.letters + string.digits + '_' ) else '_', job_name ) )
-
def cleanup( self ):
for file in [ getattr( self, a ) for a in self.cleanup_file_attributes if hasattr( self, a ) ]:
try:
diff -r 03d912919356db7ff34d289985c8ee3ac2a67dd1 -r e1db77201a5d9e93cf7729c2695c34e98abf5252 lib/galaxy/jobs/runners/local.py
--- a/lib/galaxy/jobs/runners/local.py
+++ b/lib/galaxy/jobs/runners/local.py
@@ -11,7 +11,8 @@
from time import sleep
from galaxy import model
-from galaxy.jobs.runners import BaseJobRunner
+from ..runners import BaseJobRunner
+from ..runners import JobState
from galaxy.util import DATABASE_MAX_STRING_SIZE, shrink_stream_by_size
from galaxy.util import asbool
@@ -37,12 +38,6 @@
#create a local copy of os.environ to use as env for subprocess.Popen
self._environ = os.environ.copy()
- # put lib into the PYTHONPATH for subprocesses
- if 'PYTHONPATH' in self._environ:
- self._environ['PYTHONPATH'] = '%s:%s' % ( self._environ['PYTHONPATH'], os.path.abspath( 'lib' ) )
- else:
- self._environ['PYTHONPATH'] = os.path.abspath( 'lib' )
-
#Set TEMP if a valid temp value is not already set
if not ( 'TMPDIR' in self._environ or 'TEMP' in self._environ or 'TMP' in self._environ ):
self._environ[ 'TEMP' ] = tempfile.gettempdir()
@@ -58,12 +53,24 @@
## slots would be cleaner name, but don't want deployers to see examples and think it
## is going to work with other job runners.
slots = job_wrapper.job_destination.params.get( "local_slots", None )
- command_line = command_line.lstrip( " ;" )
if slots:
- command_line = 'GALAXY_SLOTS="%d"; export GALAXY_SLOTS; GALAXY_SLOTS_CONFIGURED="1"; export GALAXY_SLOTS_CONFIGURED; %s' % ( int( slots ), command_line )
+ slots_statement = 'GALAXY_SLOTS="%d"; export GALAXY_SLOTS; GALAXY_SLOTS_CONFIGURED="1"; export GALAXY_SLOTS_CONFIGURED;' % ( int( slots ) )
else:
- command_line = 'GALAXY_SLOTS="1"; export GALAXY_SLOTS; %s' % command_line
- return command_line
+ slots_statement = 'GALAXY_SLOTS="1"; export GALAXY_SLOTS;'
+
+ job_id = job_wrapper.get_id_tag()
+ job_file = JobState.default_job_file( job_wrapper.working_directory, job_id )
+ exit_code_path = JobState.default_exit_code_file( job_wrapper.working_directory, job_id )
+ job_script_props = {
+ 'slots_statement': slots_statement,
+ 'command': command_line,
+ 'exit_code_path': exit_code_path,
+ 'working_directory': job_wrapper.working_directory,
+ }
+ job_file_contents = self.get_job_file( job_wrapper, **job_script_props )
+ open( job_file, 'w' ).write( job_file_contents )
+ os.chmod( job_file, 0755 )
+ return job_file, exit_code_path
def queue_job( self, job_wrapper ):
# prepare the job
@@ -75,8 +82,7 @@
exit_code = 0
# command line has been added to the wrapper by prepare_job()
- command_line = self.__command_line( job_wrapper )
-
+ command_line, exit_code_path = self.__command_line( job_wrapper )
job_id = job_wrapper.get_id_tag()
try:
@@ -99,6 +105,11 @@
# Reap the process and get the exit code.
exit_code = proc.wait()
+ try:
+ exit_code = int( open( exit_code_path, 'r' ).read() )
+ except Exception:
+ log.warn( "Failed to read exit code from path %s" % exit_code_path )
+ pass
stdout_file.seek( 0 )
stderr_file.seek( 0 )
stdout = shrink_stream_by_size( stdout_file, DATABASE_MAX_STRING_SIZE, join_by="\n..\n", left_larger=True, beginning_on_size_error=True )
https://bitbucket.org/galaxy/galaxy-central/commits/5bf39d99f789/
Changeset: 5bf39d99f789
User: jmchilton
Date: 2014-05-19 04:12:36
Summary: Merged in jmchilton/galaxy-central-fork-1 (pull request #384)
Local Job Runner Enhancements
Affected #: 5 files
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -1163,6 +1163,11 @@
return 'Job ran longer than the maximum allowed execution time (%s), please try different inputs or parameters' % self.app.job_config.limits.walltime
return None
+ def has_limits( self ):
+ has_output_limit = self.app.job_config.limits.output_size > 0
+ has_walltime_limit = self.app.job_config.limits.walltime_delta is not None
+ return has_output_limit or has_walltime_limit
+
def get_command_line( self ):
return self.command_line
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 lib/galaxy/jobs/runners/__init__.py
--- a/lib/galaxy/jobs/runners/__init__.py
+++ b/lib/galaxy/jobs/runners/__init__.py
@@ -196,7 +196,7 @@
output_pairs = []
# Walk job's output associations to find and use from_work_dir attributes.
job = job_wrapper.get_job()
- job_tool = self.app.toolbox.tools_by_id.get( job.tool_id, None )
+ job_tool = job_wrapper.tool
for dataset_assoc in job.output_datasets + job.output_library_datasets:
for dataset in dataset_assoc.dataset.dataset.history_associations + dataset_assoc.dataset.dataset.library_associations:
if isinstance( dataset, self.app.model.HistoryDatasetAssociation ):
@@ -269,7 +269,36 @@
self.work_queue.put( ( self.finish_job, ajs ) )
-class AsynchronousJobState( object ):
+class JobState( object ):
+ """
+ Encapsulate state of jobs.
+ """
+
+ def set_defaults( self, files_dir ):
+ if self.job_wrapper is not None:
+ id_tag = self.job_wrapper.get_id_tag()
+ if files_dir is not None:
+ self.job_file = JobState.default_job_file( files_dir, id_tag )
+ self.output_file = os.path.join( files_dir, 'galaxy_%s.o' % id_tag )
+ self.error_file = os.path.join( files_dir, 'galaxy_%s.e' % id_tag )
+ self.exit_code_file = os.path.join( files_dir, 'galaxy_%s.ec' % id_tag )
+ job_name = 'g%s' % id_tag
+ if self.job_wrapper.tool.old_id:
+ job_name += '_%s' % self.job_wrapper.tool.old_id
+ if self.job_wrapper.user:
+ job_name += '_%s' % self.job_wrapper.user
+ self.job_name = ''.join( map( lambda x: x if x in ( string.letters + string.digits + '_' ) else '_', job_name ) )
+
+ @staticmethod
+ def default_job_file( files_dir, id_tag ):
+ return os.path.join( files_dir, 'galaxy_%s.sh' % id_tag )
+
+ @staticmethod
+ def default_exit_code_file( files_dir, id_tag ):
+ return os.path.join( files_dir, 'galaxy_%s.ec' % id_tag )
+
+
+class AsynchronousJobState( JobState ):
"""
Encapsulate the state of an asynchronous job, this should be subclassed as
needed for various job runners to capture additional information needed
@@ -296,21 +325,6 @@
self.cleanup_file_attributes = [ 'job_file', 'output_file', 'error_file', 'exit_code_file' ]
- def set_defaults( self, files_dir ):
- if self.job_wrapper is not None:
- id_tag = self.job_wrapper.get_id_tag()
- if files_dir is not None:
- self.job_file = os.path.join( files_dir, 'galaxy_%s.sh' % id_tag )
- self.output_file = os.path.join( files_dir, 'galaxy_%s.o' % id_tag )
- self.error_file = os.path.join( files_dir, 'galaxy_%s.e' % id_tag )
- self.exit_code_file = os.path.join( files_dir, 'galaxy_%s.ec' % id_tag )
- job_name = 'g%s' % id_tag
- if self.job_wrapper.tool.old_id:
- job_name += '_%s' % self.job_wrapper.tool.old_id
- if self.job_wrapper.user:
- job_name += '_%s' % self.job_wrapper.user
- self.job_name = ''.join( map( lambda x: x if x in ( string.letters + string.digits + '_' ) else '_', job_name ) )
-
def cleanup( self ):
for file in [ getattr( self, a ) for a in self.cleanup_file_attributes if hasattr( self, a ) ]:
try:
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 lib/galaxy/jobs/runners/local.py
--- a/lib/galaxy/jobs/runners/local.py
+++ b/lib/galaxy/jobs/runners/local.py
@@ -11,13 +11,20 @@
from time import sleep
from galaxy import model
-from galaxy.jobs.runners import BaseJobRunner
+from ..runners import BaseJobRunner
+from ..runners import JobState
from galaxy.util import DATABASE_MAX_STRING_SIZE, shrink_stream_by_size
+from galaxy.util import asbool
log = logging.getLogger( __name__ )
__all__ = [ 'LocalJobRunner' ]
+DEFAULT_POOL_SLEEP_TIME = 1
+# TODO: Set to false and just get rid of this option. It would simplify this
+# class nicely. -John
+DEFAULT_EMBED_METADATA_IN_JOB = False
+
class LocalJobRunner( BaseJobRunner ):
"""
@@ -31,12 +38,6 @@
#create a local copy of os.environ to use as env for subprocess.Popen
self._environ = os.environ.copy()
- # put lib into the PYTHONPATH for subprocesses
- if 'PYTHONPATH' in self._environ:
- self._environ['PYTHONPATH'] = '%s:%s' % ( self._environ['PYTHONPATH'], os.path.abspath( 'lib' ) )
- else:
- self._environ['PYTHONPATH'] = os.path.abspath( 'lib' )
-
#Set TEMP if a valid temp value is not already set
if not ( 'TMPDIR' in self._environ or 'TEMP' in self._environ or 'TMP' in self._environ ):
self._environ[ 'TEMP' ] = os.path.abspath(tempfile.gettempdir())
@@ -52,24 +53,36 @@
## slots would be cleaner name, but don't want deployers to see examples and think it
## is going to work with other job runners.
slots = job_wrapper.job_destination.params.get( "local_slots", None )
- command_line = command_line.lstrip( " ;" )
if slots:
- command_line = 'GALAXY_SLOTS="%d"; export GALAXY_SLOTS; GALAXY_SLOTS_CONFIGURED="1"; export GALAXY_SLOTS_CONFIGURED; %s' % ( int( slots ), command_line )
+ slots_statement = 'GALAXY_SLOTS="%d"; export GALAXY_SLOTS; GALAXY_SLOTS_CONFIGURED="1"; export GALAXY_SLOTS_CONFIGURED;' % ( int( slots ) )
else:
- command_line = 'GALAXY_SLOTS="1"; export GALAXY_SLOTS; %s' % command_line
- return command_line
+ slots_statement = 'GALAXY_SLOTS="1"; export GALAXY_SLOTS;'
+
+ job_id = job_wrapper.get_id_tag()
+ job_file = JobState.default_job_file( job_wrapper.working_directory, job_id )
+ exit_code_path = JobState.default_exit_code_file( job_wrapper.working_directory, job_id )
+ job_script_props = {
+ 'slots_statement': slots_statement,
+ 'command': command_line,
+ 'exit_code_path': exit_code_path,
+ 'working_directory': job_wrapper.working_directory,
+ }
+ job_file_contents = self.get_job_file( job_wrapper, **job_script_props )
+ open( job_file, 'w' ).write( job_file_contents )
+ os.chmod( job_file, 0755 )
+ return job_file, exit_code_path
def queue_job( self, job_wrapper ):
# prepare the job
- if not self.prepare_job( job_wrapper ):
+ include_metadata = asbool( job_wrapper.job_destination.params.get( "embed_metadata_in_job", DEFAULT_EMBED_METADATA_IN_JOB ) )
+ if not self.prepare_job( job_wrapper, include_metadata=include_metadata ):
return
stderr = stdout = ''
exit_code = 0
# command line has been added to the wrapper by prepare_job()
- command_line = self.__command_line( job_wrapper )
-
+ command_line, exit_code_path = self.__command_line( job_wrapper )
job_id = job_wrapper.get_id_tag()
try:
@@ -85,22 +98,18 @@
preexec_fn=os.setpgrp )
job_wrapper.set_job_destination(job_wrapper.job_destination, proc.pid)
job_wrapper.change_state( model.Job.states.RUNNING )
- job_start = datetime.datetime.now()
- i = 0
- # Iterate until the process exits, periodically checking its limits
- while proc.poll() is None:
- i += 1
- if (i % 20) == 0:
- msg = job_wrapper.check_limits(runtime=datetime.datetime.now() - job_start)
- if msg is not None:
- job_wrapper.fail(msg)
- log.debug('(%s) Terminating process group' % job_id)
- self._terminate(proc)
- return
- else:
- sleep(1)
+
+ terminated = self.__poll_if_needed( proc, job_wrapper, job_id )
+ if terminated:
+ return
+
# Reap the process and get the exit code.
exit_code = proc.wait()
+ try:
+ exit_code = int( open( exit_code_path, 'r' ).read() )
+ except Exception:
+ log.warn( "Failed to read exit code from path %s" % exit_code_path )
+ pass
stdout_file.seek( 0 )
stderr_file.seek( 0 )
stdout = shrink_stream_by_size( stdout_file, DATABASE_MAX_STRING_SIZE, join_by="\n..\n", left_larger=True, beginning_on_size_error=True )
@@ -112,7 +121,9 @@
log.exception("failure running job %d" % job_wrapper.job_id)
job_wrapper.fail( "failure running job", exception=True )
return
- self._handle_metadata_externally( job_wrapper, resolve_requirements=True )
+ external_metadata = not asbool( job_wrapper.job_destination.params.get( "embed_metadata_in_job", DEFAULT_EMBED_METADATA_IN_JOB ) )
+ if external_metadata:
+ self._handle_metadata_externally( job_wrapper, resolve_requirements=True )
# Finish the job!
try:
job_wrapper.finish( stdout, stderr, exit_code )
@@ -168,3 +179,23 @@
if proc.poll() is None:
os.killpg( proc.pid, 9 )
return proc.wait() # reap
+
+ def __poll_if_needed( self, proc, job_wrapper, job_id ):
+ # Only poll if needed (i.e. job limits are set)
+ if not job_wrapper.has_limits():
+ return
+
+ job_start = datetime.datetime.now()
+ i = 0
+ # Iterate until the process exits, periodically checking its limits
+ while proc.poll() is None:
+ i += 1
+ if (i % 20) == 0:
+ msg = job_wrapper.check_limits(runtime=datetime.datetime.now() - job_start)
+ if msg is not None:
+ job_wrapper.fail(msg)
+ log.debug('(%s) Terminating process group' % job_id)
+ self._terminate(proc)
+ return True
+ else:
+ sleep( DEFAULT_POOL_SLEEP_TIME )
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 test/unit/jobs/test_runner_local.py
--- /dev/null
+++ b/test/unit/jobs/test_runner_local.py
@@ -0,0 +1,166 @@
+import os
+import threading
+import time
+from unittest import TestCase
+
+from galaxy.util import bunch
+from galaxy.jobs.runners import local
+from galaxy.jobs import metrics
+from galaxy import model
+
+from tools_support import (
+ UsesApp,
+ UsesTools
+)
+
+
+class TestLocalJobRunner( TestCase, UsesApp, UsesTools ):
+
+ def setUp( self ):
+ self.setup_app()
+ self._init_tool()
+ self.app.job_metrics = metrics.JobMetrics()
+ self.job_wrapper = MockJobWrapper( self.app, self.test_directory, self.tool )
+
+ def tearDown( self ):
+ self.tear_down_app()
+
+ def test_run( self ):
+ self.job_wrapper.command_line = "echo HelloWorld"
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.stdout.strip() == "HelloWorld"
+
+ def test_galaxy_lib_on_path( self ):
+ self.job_wrapper.command_line = '''python -c "import galaxy.util"'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.exit_code == 0
+
+ def test_default_slots( self ):
+ self.job_wrapper.command_line = '''echo $GALAXY_SLOTS'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.stdout.strip() == "1"
+
+ def test_slots_override( self ):
+ # Set local_slots in job destination to specify slots for
+ # local job runner.
+ self.job_wrapper.job_destination.params[ "local_slots" ] = 3
+ self.job_wrapper.command_line = '''echo $GALAXY_SLOTS'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.stdout.strip() == "3"
+
+ def test_exit_code( self ):
+ self.job_wrapper.command_line = '''sh -c "exit 4"'''
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert self.job_wrapper.exit_code == 4
+
+ def test_metadata_gets_set( self ):
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert os.path.exists( self.job_wrapper.mock_metadata_path )
+
+ def test_metadata_gets_set_if_embedded( self ):
+ self.job_wrapper.job_destination.params[ "embed_metadata_in_job" ] = "True"
+
+ # Kill off cruft for _handle_metadata_externally and make sure job stil works...
+ self.job_wrapper.external_output_metadata = None
+ self.app.datatypes_registry.set_external_metadata_tool = None
+
+ runner = local.LocalJobRunner( self.app, 1 )
+ runner.queue_job( self.job_wrapper )
+ assert os.path.exists( self.job_wrapper.mock_metadata_path )
+
+ def test_stopping_job( self ):
+ self.job_wrapper.command_line = '''python -c "import time; time.sleep(15)"'''
+ runner = local.LocalJobRunner( self.app, 1 )
+
+ def queue():
+ runner.queue_job( self.job_wrapper )
+
+ t = threading.Thread(target=queue)
+ t.start()
+ while True:
+ if self.job_wrapper.external_id:
+ break
+ time.sleep( .01 )
+ external_id = self.job_wrapper.external_id
+ mock_job = bunch.Bunch(
+ get_external_output_metadata=lambda: None,
+ get_job_runner_external_id=lambda: str(external_id),
+ get_id=lambda: 1
+ )
+ runner.stop_job( mock_job )
+ t.join(1)
+
+
+class MockJobWrapper( object ):
+
+ def __init__( self, app, test_directory, tool ):
+ working_directory = os.path.join( test_directory, "workdir" )
+ os.makedirs( working_directory )
+ self.app = app
+ self.tool = tool
+ self.state = model.Job.states.QUEUED
+ self.command_line = "echo HelloWorld"
+ self.prepare_called = False
+ self.write_version_cmd = None
+ self.dependency_shell_commands = None
+ self.working_directory = working_directory
+ self.requires_setting_metadata = True
+ self.job_destination = bunch.Bunch( id="default", params={} )
+ self.galaxy_lib_dir = os.path.abspath( "lib" )
+ self.job_id = 1
+ self.external_id = None
+ self.output_paths = [ '/tmp/output1.dat' ]
+ self.mock_metadata_path = os.path.abspath( os.path.join( test_directory, "METADATA_SET" ) )
+ self.metadata_command = "touch %s" % self.mock_metadata_path
+
+ # Cruft for setting metadata externally, axe at some point.
+ self.external_output_metadata = bunch.Bunch(
+ set_job_runner_external_pid=lambda pid, session: None
+ )
+ self.app.datatypes_registry.set_external_metadata_tool = bunch.Bunch(
+ build_dependency_shell_commands=lambda: []
+ )
+
+ def prepare( self ):
+ self.prepare_called = True
+
+ def set_job_destination( self, job_destination, external_id ):
+ self.external_id = external_id
+
+ def get_command_line( self ):
+ return self.command_line
+
+ def get_id_tag( self ):
+ return "1"
+
+ def get_state( self ):
+ return self.state
+
+ def change_state( self, state ):
+ self.state = state
+
+ def get_output_fnames( self ):
+ return []
+
+ def get_job( self ):
+ return model.Job()
+
+ def setup_external_metadata( self, **kwds ):
+ return self.metadata_command
+
+ def get_env_setup_clause( self ):
+ return ""
+
+ def has_limits( self ):
+ return False
+
+ def finish( self, stdout, stderr, exit_code ):
+ self.stdout = stdout
+ self.stderr = stderr
+ self.exit_code = exit_code
diff -r 632087d479859d0a8152267f6c21a623722bc875 -r 5bf39d99f7892bd8d9733f5efd68a8bb356c7bd9 test/unit/tools_support.py
--- a/test/unit/tools_support.py
+++ b/test/unit/tools_support.py
@@ -58,7 +58,7 @@
class UsesTools( object ):
- def _init_tool( self, tool_contents ):
+ def _init_tool( self, tool_contents=SIMPLE_TOOL_CONTENTS ):
self.tool_file = os.path.join( self.test_directory, "tool.xml" )
self.app.config.drmaa_external_runjob_script = ""
self.app.config.tool_secret = "testsecret"
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