14 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/b9b2d5fc998a/ Changeset: b9b2d5fc998a User: martenson Date: 2013-09-19 22:38:12 Summary: initial commit of email activation feature Affected #: 12 files diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed config/disposable_email_blacklist.conf.sample --- /dev/null +++ b/config/disposable_email_blacklist.conf.sample @@ -0,0 +1,9 @@ +If you want to disable registration for users that are using disposable email address +rename this file to disposable_email_blacklist.conf and fill it with the disposable domains +that you want to have blacklisted. Each on its own line without the '@' character as shown below. +Users using emails from these domains will get an error during the registration. + +mailinator.com +sogetthis.com +spamgourmet.com +trashmail.net \ No newline at end of file diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed lib/galaxy/config.py --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -132,6 +132,14 @@ self.admin_users = kwargs.get( "admin_users", "" ) self.mailing_join_addr = kwargs.get('mailing_join_addr',"galaxy-announce-join@bx.psu.edu") self.error_email_to = kwargs.get( 'error_email_to', None ) + self.admin_email = kwargs.get( 'admin_email', None ) + self.user_activation_on = kwargs.get( 'user_activation_on', None ) + self.activation_grace_period = kwargs.get( 'activation_grace_period', None ) + self.inactivity_box_visible = kwargs.get( 'inactivity_box_visible', None ) + self.inactivity_box_content = kwargs.get( 'inactivity_box_content', None ) + self.inactivity_box_class = kwargs.get( 'inactivity_box_class', None ) + # Get the disposable email domains blacklist file + self.blacklist_file = resolve_path( kwargs.get( 'blacklist_file', None ), self.root ) self.smtp_server = kwargs.get( 'smtp_server', None ) self.smtp_username = kwargs.get( 'smtp_username', None ) self.smtp_password = kwargs.get( 'smtp_password', None ) diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed lib/galaxy/jobs/handler.py --- a/lib/galaxy/jobs/handler.py +++ b/lib/galaxy/jobs/handler.py @@ -84,12 +84,25 @@ Checks all jobs that are in the 'new', 'queued' or 'running' state in the database and requeues or cleans up as necessary. Only run as the job handler starts. + In case the activation is enforced it will filter out the jobs of inactive users. """ - for job in self.sa_session.query( model.Job ).enable_eagerloads( False ) \ + jobs_at_startup = [] + if self.app.config.user_activation_on: + jobs_at_startup = self.sa_session.query( model.Job ).enable_eagerloads( False ) \ + .outerjoin( model.User ) \ .filter( ( ( model.Job.state == model.Job.states.NEW ) \ | ( model.Job.state == model.Job.states.RUNNING ) \ | ( model.Job.state == model.Job.states.QUEUED ) ) \ - & ( model.Job.handler == self.app.config.server_name ) ): + & ( model.Job.handler == self.app.config.server_name ) \ + & or_( ( model.Job.user_id == None ),( model.User.active == True ) ) ).all() + else: + jobs_at_startup = self.sa_session.query( model.Job ).enable_eagerloads( False ) \ + .filter( ( ( model.Job.state == model.Job.states.NEW ) \ + | ( model.Job.state == model.Job.states.RUNNING ) \ + | ( model.Job.state == model.Job.states.QUEUED ) ) \ + & ( model.Job.handler == self.app.config.server_name ) ).all() + + for job in jobs_at_startup: if job.tool_id not in self.app.toolbox.tools_by_id: log.warning( "(%s) Tool '%s' removed from tool config, unable to recover job" % ( job.id, job.tool_id ) ) JobWrapper( job, self ).fail( 'This tool was disabled before the job completed. Please contact your Galaxy administrator.' ) @@ -146,8 +159,9 @@ over all new and waiting jobs to check the state of the jobs each depends on. If the job has dependencies that have not finished, it it goes to the waiting queue. If the job has dependencies with errors, - it is marked as having errors and removed from the queue. Otherwise, - the job is dispatched. + it is marked as having errors and removed from the queue. If the job + belongs to an inactive user it is ignored. + Otherwise, the job is dispatched. """ # Pull all new jobs from the queue at once jobs_to_check = [] @@ -173,7 +187,17 @@ (model.LibraryDatasetDatasetAssociation.deleted == True), (model.Dataset.state != model.Dataset.states.OK), (model.Dataset.deleted == True)))).subquery() - jobs_to_check = self.sa_session.query(model.Job).enable_eagerloads(False) \ + if self.app.config.user_activation_on: + jobs_to_check = self.sa_session.query(model.Job).enable_eagerloads(False) \ + .outerjoin( model.User ) \ + .filter(and_((model.Job.state == model.Job.states.NEW), + or_((model.Job.user_id == None),(model.User.active == True)), + (model.Job.handler == self.app.config.server_name), + ~model.Job.table.c.id.in_(hda_not_ready), + ~model.Job.table.c.id.in_(ldda_not_ready))) \ + .order_by(model.Job.id).all() + else: + jobs_to_check = self.sa_session.query(model.Job).enable_eagerloads(False) \ .filter(and_((model.Job.state == model.Job.states.NEW), (model.Job.handler == self.app.config.server_name), ~model.Job.table.c.id.in_(hda_not_ready), diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -78,6 +78,8 @@ self.external = False self.deleted = False self.purged = False + self.active = False + self.activation_token = None self.username = None # Relationships self.histories = [] diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed lib/galaxy/model/mapping.py --- a/lib/galaxy/model/mapping.py +++ b/lib/galaxy/model/mapping.py @@ -52,7 +52,9 @@ Column( "form_values_id", Integer, ForeignKey( "form_values.id" ), index=True ), Column( "deleted", Boolean, index=True, default=False ), Column( "purged", Boolean, index=True, default=False ), - Column( "disk_usage", Numeric( 15, 0 ), index=True ) ) + Column( "disk_usage", Numeric( 15, 0 ), index=True ) , + Column( "active", Boolean, index=True, default=True, nullable=False ), + Column( "activation_token", TrimmedString( 64 ), nullable=True, index=True ) ) model.UserAddress.table = Table( "user_address", metadata, Column( "id", Integer, primary_key=True), diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed lib/galaxy/model/migrate/versions/0117_add_user_activation.py --- /dev/null +++ b/lib/galaxy/model/migrate/versions/0117_add_user_activation.py @@ -0,0 +1,57 @@ +''' +Created on Sep 10, 2013 + +@author: marten + +Adds 'active' and 'activation_token' columns to the galaxy_user table. +''' + +from sqlalchemy import * +from sqlalchemy.orm import * +from migrate import * +from migrate.changeset import * +from galaxy.model.custom_types import TrimmedString + +import logging +log = logging.getLogger( __name__ ) + +user_active_column = Column( "active", Boolean, default=True, nullable=True ) +user_activation_token_column = Column( "activation_token", TrimmedString( 64 ), nullable=True ) + + +def display_migration_details(): + print "" + print "This migration script adds active and activation_token columns to the user table" + +def upgrade(migrate_engine): + print __doc__ + metadata = MetaData() + metadata.bind = migrate_engine + metadata.reflect() + + # Add the active and activation_token columns to the user table in one try because the depend on each other. + try: + user_table = Table( "galaxy_user", metadata, autoload=True ) + user_active_column.create( table = user_table , populate_default = True) + user_activation_token_column.create( table = user_table ) + assert user_active_column is user_table.c.active + assert user_activation_token_column is user_table.c.activation_token + except Exception, e: + print str(e) + log.error( "Adding columns 'active' and 'activation_token' to galaxy_user table failed: %s" % str( e ) ) + return + +def downgrade(migrate_engine): + metadata = MetaData() + metadata.bind = migrate_engine + metadata.reflect() + + # Drop the user table's active and activation_token columns in one try because the depend on each other. + try: + user_table = Table( "galaxy_user", metadata, autoload=True ) + user_active = user_table.c.active + user_activation_token = user_table.c.activation_token + user_active.drop() + user_activation_token.drop() + except Exception, e: + log.debug( "Dropping 'active' and 'activation_token' columns from galaxy_user table failed: %s" % ( str( e ) ) ) \ No newline at end of file diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed lib/galaxy/security/validate_user_input.py --- a/lib/galaxy/security/validate_user_input.py +++ b/lib/galaxy/security/validate_user_input.py @@ -2,18 +2,31 @@ VALID_PUBLICNAME_RE = re.compile( "^[a-z0-9\-]+$" ) VALID_PUBLICNAME_SUB = re.compile( "[^a-z0-9\-]" ) +# Basic regular expression to check email validity. +VALID_EMAIL_RE = re.compile( "[^@]+@[^@]+\.[^@]+" ) FILL_CHAR = '-' def validate_email( trans, email, user=None, check_dup=True ): + """ + Validates the email format, also checks whether the domain is blacklisted in the disposable domains configuration. + """ message = '' + # Load the blacklist file location from the configuration file. + blacklist_file = trans.app.config.blacklist_file + if blacklist_file is not None: + email_blacklist = [ line.rstrip() for line in file( blacklist_file ).readlines() ] if user and user.email == email: return message - if len( email ) == 0 or "@" not in email or "." not in email: - message = "Enter a real email address" + if not( VALID_EMAIL_RE.match( email ) ): + message = "Please enter your real email address." elif len( email ) > 255: - message = "Email address exceeds maximum allowable length" + message = "Email address exceeds maximum allowable length." elif check_dup and trans.sa_session.query( trans.app.model.User ).filter_by( email=email ).first(): - message = "User with that email already exists" + message = "User with that email already exists." + # If the blacklist is not empty filter out the disposable domains. + elif email_blacklist is not None: + if email.split('@')[1] in email_blacklist: + message = "Please enter your permanent email address." return message def validate_publicname( trans, publicname, user=None ): diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed lib/galaxy/webapps/galaxy/buildapp.py --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -51,6 +51,8 @@ webapp.add_ui_controllers( 'galaxy.webapps.galaxy.controllers', app ) # Force /history to go to /root/history -- needed since the tests assume this webapp.add_route( '/history', controller='root', action='history' ) + # Force /activate to go to the controller + webapp.add_route( '/activate', controller='user', action='activate' ) # These two routes handle our simple needs at the moment webapp.add_route( '/async/:tool_id/:data_id/:data_secret', controller='async', action='index', tool_id=None, data_id=None, data_secret=None ) webapp.add_route( '/:controller/:action', action='index' ) diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed lib/galaxy/webapps/galaxy/controllers/user.py --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -8,6 +8,7 @@ import socket import string import random +import urllib from galaxy import web from galaxy import util, model from galaxy.model.orm import and_ @@ -17,6 +18,8 @@ from galaxy.web.base.controller import BaseUIController, UsesFormDefinitionsMixin from galaxy.web.form_builder import CheckboxField, build_select_field from galaxy.web.framework.helpers import time_ago, grids +from datetime import datetime, timedelta +from galaxy.util import hash_util log = logging.getLogger( __name__ ) @@ -147,7 +150,14 @@ if trans.user: if user_openid.user and user_openid.user.id != trans.user.id: message = "The OpenID <strong>%s</strong> is already associated with another Galaxy account, <strong>%s</strong>. Please disassociate it from that account before attempting to associate it with a new account." % ( display_identifier, user_openid.user.email ) - status = "error" + if not trans.user.active and trans.app.config.user_activation_on: # Account activation is ON and the user is INACTIVE. + if ( trans.app.config.activation_grace_period != 0 ): # grace period is ON + if self.is_outside_grace_period( trans, trans.user.create_time ): # User is outside the grace period. Login is disabled and he will have the activation email resent. + message = self.resend_verification_email( trans, trans.user.email ) + else: # User is within the grace period, let him log in. + pass + else: # Grace period is off. Login is disabled and user will have the activation email resent. + message = self.resend_verification_email( trans, trans.user.email ) elif not user_openid.user or user_openid.user == trans.user: if openid_provider_obj.id: user_openid.provider = openid_provider_obj.id @@ -282,7 +292,7 @@ subscribe_checked = CheckboxField.is_checked( subscribe ) error = '' if not trans.app.config.allow_user_creation and not trans.user_is_admin(): - error = 'User registration is disabled. Please contact your Galaxy administrator for an account.' + error = 'User registration is disabled. Please contact your local Galaxy administrator for an account.' else: # Check email and password validity error = self.__validate( trans, params, email, password, confirm, username ) @@ -465,9 +475,13 @@ openid_providers=trans.app.openid_providers, form_input_auto_focus=True, active_view="user" ) + def __validate_login( self, trans, **kwd ): + """ + Function validates numerous cases that might happen during the login time. + """ message = kwd.get( 'message', '' ) - status = kwd.get( 'status', 'done' ) + status = kwd.get( 'status', 'error' ) email = kwd.get( 'email', '' ) password = kwd.get( 'password', '' ) redirect = kwd.get( 'redirect', trans.request.referer ).strip() @@ -475,26 +489,68 @@ user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email==email ).first() if not user: message = "No such user (please note that login is case sensitive)" - status = 'error' elif user.deleted: - message = "This account has been marked deleted, contact your Galaxy administrator to restore the account." - status = 'error' + message = "This account has been marked deleted, contact your local Galaxy administrator to restore the account." + if trans.app.config.admin_email is not None: + message += 'Contact: %s' % trans.app.config.admin_email elif user.external: message = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it." - status = 'error' + if trans.app.config.admin_email is not None: + message += 'Contact: %s' % trans.app.config.admin_email elif not user.check_password( password ): message = "Invalid password" - status = 'error' + elif trans.app.config.user_activation_on and not user.active: # activation is ON and the user is INACTIVE + if ( trans.app.config.activation_grace_period != 0 ): # grace period is ON + if self.is_outside_grace_period( trans, user.create_time ): # User is outside the grace period. Login is disabled and he will have the activation email resent. + message = self.resend_verification_email( trans, email ) + else: # User is within the grace period, let him log in. + message, success, status = self.proceed_login( trans, user, redirect ) + else: # Grace period is off. Login is disabled and user will have the activation email resent. + message = self.resend_verification_email( trans, email ) + else: # activation is OFF + message, success, status = self.proceed_login( trans, user, redirect ) + return ( message, status, user, success ) + + def proceed_login ( self, trans, user, redirect ): + """ + Function processes user login. It is called in case all the login requirements are valid. + """ + trans.handle_user_login( user ) + if trans.webapp.name == 'galaxy': + trans.log_event( "User logged in" ) + message = 'You are now logged in as %s.<br>You can <a target="_top" href="%s">go back to the page you were visiting</a> or <a target="_top" href="%s">go to the home page</a>.' % \ + ( user.email, redirect, url_for( '/' ) ) + if trans.app.config.require_login: + message += ' <a target="_top" href="%s">Click here</a> to continue to the home page.' % web.url_for( controller="root", action="welcome" ) + success = True + status = 'done' + return message, success, status + + def resend_verification_email( self, trans, email ): + """ + Function resends the verification email in case user wants to log in with an inactive account. + """ + is_activation_sent = self.send_verification_email( trans, email ) + if is_activation_sent: + message = 'This account has not been activated yet. The activation link has been sent again. Please check your email address %s.<br>' % email else: - trans.handle_user_login( user ) - if trans.webapp.name == 'galaxy': - trans.log_event( "User logged in" ) - message = 'You are now logged in as %s.<br>You can <a target="_top" href="%s">go back to the page you were visiting</a> or <a target="_top" href="%s">go to the home page</a>.' % \ - ( user.email, redirect, url_for( '/' ) ) - if trans.app.config.require_login: - message += ' <a target="_top" href="%s">Click here</a> to continue to the home page.' % web.url_for( controller="root", action="welcome" ) - success = True - return ( message, status, user, success ) + message = 'This account has not been activated yet but we are unable to send the activation link. Please contact your local Galaxy administrator.' + if trans.app.config.admin_email is not None: + message += 'Contact: %s' % trans.app.config.admin_email + return message + + def is_outside_grace_period ( self, trans, create_time ): + """ + Function checks whether the user is outside the config-defined grace period for inactive accounts. + """ + # Activation is forced and the user is not active yet. Check the grace period. + activation_grace_period = trans.app.config.activation_grace_period + # Default value is 3 hours. + if activation_grace_period == None: + activation_grace_period = 3 + delta = timedelta( hours = int( activation_grace_period ) ) + time_difference = datetime.utcnow() - create_time + return ( time_difference > delta or activation_grace_period == 0 ) @web.expose def logout( self, trans, logout_all=False ): @@ -533,7 +589,9 @@ redirect = kwd.get( 'redirect', trans.request.referer ).strip() is_admin = cntrller == 'admin' and trans.user_is_admin if not trans.app.config.allow_user_creation and not trans.user_is_admin(): - message = 'User registration is disabled. Please contact your Galaxy administrator for an account.' + message = 'User registration is disabled. Please contact your local Galaxy administrator for an account.' + if trans.app.config.admin_email is not None: + message += 'Contact: %s' % trans.app.config.admin_email status = 'error' else: if not refresh_frames: @@ -606,6 +664,8 @@ user = trans.app.model.User( email=email ) user.set_password_cleartext( password ) user.username = username + if trans.app.config.user_activation_on: # Do not set the active flag in case activation is OFF. + user.active = False trans.sa_session.add( user ) trans.sa_session.flush() trans.app.security_agent.create_private_user_role( user ) @@ -633,7 +693,7 @@ if subscribe_checked: # subscribe user to email list if trans.app.config.smtp_server is None: - error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance." + error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance. <br>Please contact your local Galaxy administrator." else: body = 'Join Mailing list.\n' to = trans.app.config.mailing_join_addr @@ -659,9 +719,86 @@ status = 'error' success = False else: - message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) ) - success = True + is_activation_sent = self.send_verification_email( trans, email ) + if is_activation_sent: + message = 'Now logged in as %s.<br>Verification email has been sent to your email address. Please verify it by clicking the activation link in the email.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) ) + success = True + else: + message = 'Unable to send activation email, please contact your local Galaxy administrator.' + if trans.app.config.admin_email is not None: + message += 'Contact: %s' % trans.app.config.admin_email + success = False return ( message, status, user, success ) + + def send_verification_email( self, trans, email ): + """ + Send the verification email containing the activation link to the user's email. + """ + activation_link = self.prepare_activation_link( trans, email ) + + body = ("Hi %s,\n\n" + "Please click the activation link below in order to activate your account.\n\n" + "Activation link: %s \n\n" + "Your Galaxy Team" % ( email, activation_link )) + to = email + frm = trans.app.config.admin_email + subject = 'How to activate your Galaxy account' + try: + util.send_mail( frm, to, subject, body, trans.app.config ) + return True + except: + return False + + def prepare_activation_link( self, trans, email ): + """ + Prepares the account activation link for the user. + """ + activation_token = self.get_activation_token( trans, email ) + host = trans.request.host.split( ':' )[ 0 ] + if host == 'localhost': + host = socket.getfqdn() + activation_link = str( trans.request.host ) + url_for( controller='user', action='activate' ) + "?activation_token=" + str( activation_token ) + "&email=" + urllib.quote( email ) + return activation_link + + def get_activation_token ( self, trans, email ): + """ + Checks for the activation token. Creates new activation token and stores it in the database if none found. + """ + user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email == email ).first() + activation_token = user.activation_token + if activation_token == None: + activation_token = hash_util.new_secure_hash( str( random.getrandbits( 256 ) ) ) + user.activation_token = activation_token + trans.sa_session.add( user ) + trans.sa_session.flush() + return activation_token + + @web.expose + def activate( self, trans, **kwd ): + """ + Function checks whether token fits the user and then activates the user's account. + """ + params = util.Params( kwd, sanitize=False ) + email = urllib.unquote( params.get( 'email', None ) ) + activation_token = params.get( 'activation_token', None ) + + if email == None or activation_token == None: + # We don't have the email or activation_token, show error. + return trans.show_error_message( "You are using wrong activation link. Try to log-in and we will send you a new activation email.<br><a href='%s'>Go to login page.</a>" ) % web.url_for( controller="root", action="index" ) + else: + # Find the user + user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email==email ).first() + if user.activation_token == activation_token: + user.activation_token = None + user.active = True + trans.sa_session.add(user) + trans.sa_session.flush() + return trans.show_ok_message( "Your account has been successfully activated!<br><a href='%s'>Go to login page.</a>" ) % web.url_for( controller='root', action='index' ) + else: + # Tokens don't match. Activation is denied. + return trans.show_error_message( "You are using wrong activation link. Try to log in and we will send you a new activation email.<br><a href='%s'>Go to login page.</a>" ) % web.url_for( controller='root', action='index' ) + return + def __get_user_type_form_definition( self, trans, user=None, **kwd ): params = util.Params( kwd ) if user and user.values: @@ -885,7 +1022,7 @@ @web.expose def reset_password( self, trans, email=None, **kwd ): if trans.app.config.smtp_server is None: - return trans.show_error_message( "Mail is not configured for this Galaxy instance. Please contact an administrator." ) + return trans.show_error_message( "Mail is not configured for this Galaxy instance. Please contact your local Galaxy administrator." ) message = util.restore_text( kwd.get( 'message', '' ) ) status = 'done' if kwd.get( 'reset_password_button', False ): @@ -1042,7 +1179,7 @@ phone = util.restore_text( params.get( 'phone', '' ) ) ok = True if not trans.app.config.allow_user_creation and not is_admin: - return trans.show_error_message( 'User registration is disabled. Please contact your Galaxy administrator for an account.' ) + return trans.show_error_message( 'User registration is disabled. Please contact your local Galaxy administrator for an account.' ) if params.get( 'new_address_button', False ): if not short_desc: ok = False diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed static/style/blue/base.css --- a/static/style/blue/base.css +++ b/static/style/blue/base.css @@ -1140,6 +1140,7 @@ body{background:#fff;color:#000;margin:10px}body.full-content{overflow:hidden;margin:0;padding:0;width:100%;height:100%} #background{position:absolute;background:#fff;z-index:-1;top:0;left:0;margin:0;padding:0;width:100%;height:100%} #messagebox{position:absolute;top:34px;left:0;width:100%;height:30px !important;overflow:hidden;border-bottom:solid #999 1px;font-size:90%} +#inactivebox{position:absolute;top:34px;left:0;width:100%;height:30px !important;overflow:hidden;border-bottom:solid #999 1px;font-size:90%} #left,#left-border,#center,#right-border,#right{position:absolute;top:34px;bottom:0px;overflow:hidden;background:#fff} #left{left:0px;width:250px;z-index:200;border-right:solid #999 1px} #left-border{left:250px} diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed templates/base/base_panels.mako --- a/templates/base/base_panels.mako +++ b/templates/base/base_panels.mako @@ -4,6 +4,9 @@ self.has_left_panel = hasattr( self, 'left_panel' ) self.has_right_panel = hasattr( self, 'right_panel' ) self.message_box_visible = app.config.message_box_visible + self.show_inactivity_warning = False + if trans.user: + self.show_inactivity_warning = ( ( trans.user.active is False ) and ( app.config.user_activation_on is True) and ( app.config.inactivity_box_content is not None ) ) self.overlay_visible=False self.active_view=None self.body_class="" @@ -26,12 +29,20 @@ right: 0 !important; %endif } - %if self.message_box_visible: +## This is some dirty hack happening + %if self.message_box_visible or self.show_inactivity_warning: #left, #left-border, #center, #right-border, #right { top: 64px; } %endif + %if self.message_box_visible and self.show_inactivity_warning: + #left, #left-border, #center, #right-border, #right + { + top: 94px; + } + #inactivebox{top:64px;} + %endif </style></%def> @@ -300,11 +311,16 @@ <div id="masthead" class="navbar navbar-fixed-top navbar-inverse"> ${self.masthead()} </div> + %if self.message_box_visible and app.config.message_box_content: <div id="messagebox" class="panel-${app.config.message_box_class}-message"> - %if self.message_box_visible and app.config.message_box_content: ${app.config.message_box_content} + </div> %endif - </div> + %if self.show_inactivity_warning: + <div id="inactivebox" class="panel-warning-message"> + ${app.config.inactivity_box_content} + </div> + %endif ${self.overlay(visible=self.overlay_visible)} %if self.has_left_panel: <div id="left"> diff -r 3a15758ba67e2429698184a4300c9608c65ce06d -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed universe_wsgi.ini.sample --- a/universe_wsgi.ini.sample +++ b/universe_wsgi.ini.sample @@ -242,8 +242,8 @@ # Galaxy sends mail for various things: Subscribing users to the mailing list # if they request it, emailing password resets, notification from the Galaxy -# Sample Tracking system, and reporting dataset errors. To do this, it needs -# to send mail through an SMTP server, which you may define here (host:port). +# Sample Tracking system, reporting dataset errors, and sending activation emails. +# To do this, it needs to send mail through an SMTP server, which you may define here (host:port). # Galaxy will automatically try STARTTLS but will continue upon failure. #smtp_server = None @@ -261,6 +261,33 @@ # will be sent to this address. Error reports are disabled if no address is set. #error_email_to = None +# Administrator's email is shown to user in case of Galaxy misconfiguration or a generic error. +# It is also used as a sender for the account activation mail. +#admin_email = None + +# E-mail domains blacklist is used for filtering out users that are using disposable email address +# during the registration. If their address domain matches any domain in the BL they are refused the registration. +#blacklist_file = config/disposable_email_blacklist.conf + + +# -- Account activation + +# This is user account activation feature global flag. If set to "False" the rest of the Account +# activation configuration is ignored and user activation is disabled (a.k.a. accounts are active since registration). +# Note the activation is also not working in case the smtp server is not defined. +#user_activation_on = False + +# Activation grace period. Activation is not forced (login is not disabled) until +# grace period has passed. Users under grace period can't run jobs (see inactivity_box_content). +# In hours. Default is 3. Enter 0 to disable grace period. +# Users with OpenID logins have grace period forever. +#activation_grace_period = 0 + +# Used for warning box for inactive accounts (unable to run jobs). +# In use only if activation_grace_period is set. +#inactivity_box_content = Your account has not been activated yet. Please activate your account by verifying your email address. For now you can access everything at Galaxy but your jobs won't run. + + # -- Display sites # Galaxy can display data at various external browsers. These options specify https://bitbucket.org/galaxy/galaxy-central/commits/cd1b21880d59/ Changeset: cd1b21880d59 User: martenson Date: 2013-09-20 02:51:24 Summary: Merged galaxy/galaxy-central into default Affected #: 8 files diff -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 lib/galaxy/web/framework/helpers/grids.py --- a/lib/galaxy/web/framework/helpers/grids.py +++ b/lib/galaxy/web/framework/helpers/grids.py @@ -198,7 +198,10 @@ if page_num == 0: # Show all rows in page. total_num_rows = query.count() + # persistant page='all' page_num = 1 + #page_num = 'all' + #extra_url_args['page'] = page_num num_pages = 1 else: # Show a limited number of rows. Before modifying query, get the total number of rows that query diff -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 static/scripts/galaxy.grids.js --- a/static/scripts/galaxy.grids.js +++ b/static/scripts/galaxy.grids.js @@ -472,7 +472,7 @@ go_to_URL(); return; } - + // If there's an operation, do POST; otherwise, do GET. var method = (grid.get('operation') ? "POST" : "GET" ); $('.loading-elt-overlay').show(); // Show overlay to indicate loading and prevent user actions. @@ -565,4 +565,4 @@ // return return true; -} \ No newline at end of file +} diff -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 static/scripts/packed/galaxy.upload.js --- a/static/scripts/packed/galaxy.upload.js +++ b/static/scripts/packed/galaxy.upload.js @@ -1,1 +1,1 @@ -define(["utils/galaxy.css","galaxy.modal","galaxy.master","utils/galaxy.uploadbox","libs/backbone/backbone-relational"],function(c,b,d){var a=Backbone.View.extend({modal:null,button_show:null,file_counter:0,initialize:function(){c.load_file("static/style/galaxy.upload.css");var e=this;this.button_show=new d.GalaxyMasterIcon({icon:"fa-icon-upload",tooltip:"Upload Files",on_click:function(f){e.event_show(f)},with_number:true});Galaxy.master.prepend(this.button_show)},events:{mouseover:"event_mouseover",mouseleave:"event_mouseleave"},event_mouseover:function(f){$("#galaxy-upload-box").addClass("galaxy-upload-highlight")},event_mouseleave:function(f){$("#galaxy-upload-box").removeClass("galaxy-upload-highlight")},event_start:function(e,f,g){var h="#galaxy-upload-file-"+e;$("#galaxy-upload-box").append(this.template_file(h));$("#galaxy-upload-file-"+e).find(".title").html(f.name);this.event_progress(e,f,0);this.file_counter++;this.refresh()},event_progress:function(f,g,i){var h=$("#galaxy-upload-file-"+f);var e=parseInt(i);h.find(".progress").css({width:e+"%"});h.find(".info").html(e+"% of "+this.size_to_string(g.size))},event_success:function(e,f,g){Galaxy.currHistoryPanel.refresh();this.file_counter--;this.refresh()},event_error:function(e,f,h){var g=$("#galaxy-upload-file-"+e);g.find(".progress-frame").addClass("failed");g.find(".error").html("<strong>Failed:</strong> "+h);this.event_progress(e,f,0);this.file_counter--;this.refresh()},event_show:function(h){h.preventDefault();if(!Galaxy.currHistoryPanel){var g=this;window.setTimeout(function(){g.event_show(h)},200);return}if(!this.modal){this.modal=new b.GalaxyModal({title:"Upload files from your local drive",body:this.template()});var f=Galaxy.currHistoryPanel.model.get("id");var g=this;$("#galaxy-upload-box").uploadbox({url:galaxy_config.root+"api/histories/"+f+"/contents",dragover:g.event_mouseover,dragleave:g.event_mouseleave,start:function(e,i,j){g.event_start(e,i,j)},success:function(e,i,j){g.event_success(e,i,j)},progress:function(e,i,j){g.event_progress(e,i,j)},error:function(e,i,j){g.event_error(e,i,j)},data:{source:"upload"}});this.setElement("#galaxy-upload-box")}this.modal.show()},refresh:function(){if(this.file_counter>0){this.button_show.number(this.file_counter)}else{this.button_show.number("")}},size_to_string:function(e){var f="";if(e>=100000000000){e=e/100000000000;f="TB"}else{if(e>=100000000){e=e/100000000;f="GB"}else{if(e>=100000){e=e/100000;f="MB"}else{if(e>=100){e=e/100;f="KB"}else{e=e*10;f="b"}}}}return"<strong>"+(Math.round(e)/10)+"</strong> "+f},template:function(){return'<form id="galaxy-upload-box" class="galaxy-upload-box galaxy-corner"></form>'},template_file:function(e){return'<div id="'+e.substr(1)+'" class="galaxy-upload-file galaxy-corner-soft galaxy-shadow"><div class="title"></div><div class="error"></div><div class="progress-frame galaxy-corner-soft"><div class="progress"></div></div><div class="info"></div></div>'}});return{GalaxyUpload:a}}); \ No newline at end of file +define(["galaxy.modal","galaxy.master","utils/galaxy.uploadbox","libs/backbone/backbone-relational"],function(b,c){var a=Backbone.View.extend({modal:null,button_show:null,file_counter:0,initialize:function(){var d=this;this.button_show=new c.GalaxyMasterIcon({icon:"fa-icon-upload",tooltip:"Upload Files",on_click:function(f){d.event_show(f)},with_number:true});Galaxy.master.prepend(this.button_show)},events:{mouseover:"event_mouseover",mouseleave:"event_mouseleave"},event_mouseover:function(d){$("#galaxy-upload-box").addClass("highlight")},event_mouseleave:function(d){$("#galaxy-upload-box").removeClass("highlight")},event_start:function(d,e,f){var g="#galaxy-upload-file-"+d;$("#galaxy-upload-box").append(this.template_file(g));$("#galaxy-upload-file-"+d).find(".title").html(e.name);this.event_progress(d,e,0);this.file_counter++;this.refresh()},event_progress:function(e,f,h){var g=$("#galaxy-upload-file-"+e);var d=parseInt(h);g.find(".progress").css({width:d+"%"});g.find(".info").html(d+"% of "+this.size_to_string(f.size))},event_success:function(d,e,f){Galaxy.currHistoryPanel.refresh();this.file_counter--;this.refresh()},event_error:function(d,e,g){var f=$("#galaxy-upload-file-"+d);f.find(".progress-frame").addClass("failed");f.find(".error").html("<strong>Failed:</strong> "+g);this.event_progress(d,e,0);this.file_counter--;this.refresh()},event_show:function(g){g.preventDefault();if(!Galaxy.currHistoryPanel){var f=this;window.setTimeout(function(){f.event_show(g)},200);return}if(!this.modal){var f=this;this.modal=new b.GalaxyModal({title:"Upload files from your local drive",body:this.template(),buttons:{Close:function(){f.modal.hide()}}});var d=Galaxy.currHistoryPanel.model.get("id");var f=this;$("#galaxy-upload-box").uploadbox({url:galaxy_config.root+"api/histories/"+d+"/contents",dragover:f.event_mouseover,dragleave:f.event_mouseleave,start:function(e,h,i){f.event_start(e,h,i)},success:function(e,h,i){f.event_success(e,h,i)},progress:function(e,h,i){f.event_progress(e,h,i)},error:function(e,h,i){f.event_error(e,h,i)},data:{source:"upload"}});this.setElement("#galaxy-upload-box")}this.modal.show()},refresh:function(){if(this.file_counter>0){this.button_show.number(this.file_counter)}else{this.button_show.number("")}},size_to_string:function(d){var e="";if(d>=100000000000){d=d/100000000000;e="TB"}else{if(d>=100000000){d=d/100000000;e="GB"}else{if(d>=100000){d=d/100000;e="MB"}else{if(d>=100){d=d/100;e="KB"}else{d=d*10;e="b"}}}}return"<strong>"+(Math.round(d)/10)+"</strong> "+e},template:function(){return'<form id="galaxy-upload-box" class="galaxy-upload-box"></form>'},template_file:function(d){return'<div id="'+d.substr(1)+'" class="file corner-soft shadow"><div class="title"></div><div class="error"></div><div class="progress-frame corner-soft"><div class="progress"></div></div><div class="info"></div></div>'}});return{GalaxyUpload:a}}); \ No newline at end of file diff -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 static/scripts/packed/galaxy.workflow_editor.canvas.js --- a/static/scripts/packed/galaxy.workflow_editor.canvas.js +++ b/static/scripts/packed/galaxy.workflow_editor.canvas.js @@ -1,1 +1,1 @@ -function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(b,c,a){Terminal.call(this,b);this.datatypes=c;this.multiple=a}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1||this.multiple){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){if(f[b]=="input"||issubtype(f[b],this.datatypes[c])){return true}}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};if(!this.handle1||!this.handle2){return}var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(f,b,c,a){var d=this;$(f).each(function(){var g=this.terminal=new InputTerminal(this,c,a);g.node=d;g.name=b;$(this).bind("dropinit",function(h,i){return $(i.drag).hasClass("output-terminal")&&g.can_accept(i.drag.terminal)}).bind("dropstart",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#BBFFBB"}}).bind("dropend",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#FFFFFF"}}).bind("drop",function(h,i){(new Connector(i.drag.terminal,g)).redraw()}).bind("hover",function(){if(g.connectors.length>0){var h=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/delete_icon.png").click(function(){$.each(g.connectors,function(j,i){if(i){i.destroy()}});h.remove()}))).bind("mouseleave",function(){$(this).remove()});h.css({top:$(this).offset().top-2,left:$(this).offset().left-h.width(),"padding-right":$(this).width()}).show()}});d.input_terminals[b]=g})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j,k){$(k.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var l=new Connector();l.dragging=true;l.connect(this.terminal,i.terminal);return i}).bind("drag",function(i,j){var h=function(){var l=$(j.proxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.proxy).css({left:k,top:m});j.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h,i){i.proxy.terminal.connectors[0].destroy();$(i.proxy).remove();$(i.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(h){var g=this.element;if(h.type){this.type=h.type}this.name=h.name;this.form_html=h.form_html;this.tool_state=h.tool_state;this.tool_errors=h.tool_errors;this.tooltip=h.tooltip?h.tooltip:"";this.annotation=h.annotation;this.post_job_actions=h.post_job_actions?h.post_job_actions:{};this.workflow_outputs=h.workflow_outputs?h.workflow_outputs:[];if(this.tool_errors){g.addClass("tool-node-error")}else{g.removeClass("tool-node-error")}var d=this;var c=Math.max(150,g.width());var a=g.find(".toolFormBody");a.find("div").remove();var i=$("<div class='inputs'></div>").appendTo(a);$.each(h.data_inputs,function(k,f){var j=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(j,f.name,f.extensions,f.multiple);var b=$("<div class='form-row dataRow input-data-row' name='"+f.name+"'>"+f.label+"</div>");b.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(b);c=Math.max(c,b.outerWidth());b.css({position:"",left:"",top:"",display:""});b.remove();i.append(b.prepend(j))});if((h.data_inputs.length>0)&&(h.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(h.data_outputs,function(k,b){var j=$("<div class='terminal output-terminal'></div>");d.enable_output_terminal(j,b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions.join(", ")+")"}var m=$("<div class='form-row dataRow'>"+f+"</div>");if(d.type=="tool"){var l=$("<div class='callout "+f+"'></div>").css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(b.name,d.workflow_outputs)!=-1){d.workflow_outputs.splice($.inArray(b.name,d.workflow_outputs),1);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{d.workflow_outputs.push(b.name);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Flag this as a workflow output. All non-flagged outputs will be hidden."});l.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});l.show();m.append(l);if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}m.hover(function(){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")},function(){if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}})}m.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(m);c=Math.max(c,m.outerWidth()+17);m.css({position:"",left:"",top:"",display:""});m.detach();a.append(m.append(j))});g.css("width",Math.min(250,Math.max(g.width(),c)));workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;this.annotation=f.annotation;var g=$.parseJSON(f.post_job_actions);this.post_job_actions=g?g:{};if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var h=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=h.find("div.input-data-row");$.each(f.data_inputs,function(l,j){var k=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(k,j.name,j.extensions,j.multiple);h.find("div[name='"+j.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){k[0].terminal.connectors[0]=i;i.handle2=k[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+j.name+"'>"+j.label+"</div>").prepend(k))});h.replaceWith(b);h.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node("tool",f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if($.isArray(h)){$.each(h,function(m,k){var n=wf.nodes[k.id];var o=new Connector();o.connect(n.output_terminals[k.output_name],d.input_terminals[i]);o.redraw()})}else{var j=wf.nodes[h.id];var l=new Connector();l.connect(j.output_terminals[h.output_name],d.input_terminals[i]);l.redraw()}}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<img/>").attr("src",galaxy_config.root+"static/images/delete_icon.png").click(function(b){g.destroy()}).hover(function(){$(this).attr("src",galaxy_config.root+"static/images/delete_icon_dark.png")},function(){$(this).attr("src",galaxy_config.root+"static/images/delete_icon.png")}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}}); \ No newline at end of file +function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(b,c,a){Terminal.call(this,b);this.datatypes=c;this.multiple=a}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1||this.multiple){for(var c in this.datatypes){var f=new Array();f=f.concat(a.datatypes);if(a.node.post_job_actions){for(var d in a.node.post_job_actions){var g=a.node.post_job_actions[d];if(g.action_type=="ChangeDatatypeAction"&&(g.output_name==""||g.output_name==a.name)&&g.action_arguments){f.push(g.action_arguments.newtype)}}}for(var b in f){if(f[b]=="input"||issubtype(f[b],this.datatypes[c])){return true}}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_color="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;if(this.handle1){this.handle1.connect(this)}this.handle2=a;if(this.handle2){this.handle2.connect(this)}},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};if(!this.handle1||!this.handle2){return}var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(f,b,c,a){var d=this;$(f).each(function(){var g=this.terminal=new InputTerminal(this,c,a);g.node=d;g.name=b;$(this).bind("dropinit",function(h,i){return $(i.drag).hasClass("output-terminal")&&g.can_accept(i.drag.terminal)}).bind("dropstart",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#BBFFBB"}}).bind("dropend",function(h,i){if(i.proxy.terminal){i.proxy.terminal.connectors[0].inner_color="#FFFFFF"}}).bind("drop",function(h,i){(new Connector(i.drag.terminal,g)).redraw()}).bind("hover",function(){if(g.connectors.length>0){var h=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='button'></div>").append($("<div/>").addClass("fa-icon-button fa-icon-remove").click(function(){$.each(g.connectors,function(j,i){if(i){i.destroy()}});h.remove()}))).bind("mouseleave",function(){$(this).remove()});h.css({top:$(this).offset().top-2,left:$(this).offset().left-h.width(),"padding-right":$(this).width()}).show()}});d.input_terminals[b]=g})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j,k){$(k.available).addClass("input-terminal-active");workflow.check_changes_in_active_form();var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var l=new Connector();l.dragging=true;l.connect(this.terminal,i.terminal);return i}).bind("drag",function(i,j){var h=function(){var l=$(j.proxy).offsetParent().offset(),k=j.offsetX-l.left,m=j.offsetY-l.top;$(j.proxy).css({left:k,top:m});j.proxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h,i){i.proxy.terminal.connectors[0].destroy();$(i.proxy).remove();$(i.available).removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(h){var g=this.element;if(h.type){this.type=h.type}this.name=h.name;this.form_html=h.form_html;this.tool_state=h.tool_state;this.tool_errors=h.tool_errors;this.tooltip=h.tooltip?h.tooltip:"";this.annotation=h.annotation;this.post_job_actions=h.post_job_actions?h.post_job_actions:{};this.workflow_outputs=h.workflow_outputs?h.workflow_outputs:[];if(this.tool_errors){g.addClass("tool-node-error")}else{g.removeClass("tool-node-error")}var d=this;var c=Math.max(150,g.width());var a=g.find(".toolFormBody");a.find("div").remove();var i=$("<div class='inputs'></div>").appendTo(a);$.each(h.data_inputs,function(k,f){var j=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(j,f.name,f.extensions,f.multiple);var b=$("<div class='form-row dataRow input-data-row' name='"+f.name+"'>"+f.label+"</div>");b.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(b);c=Math.max(c,b.outerWidth());b.css({position:"",left:"",top:"",display:""});b.remove();i.append(b.prepend(j))});if((h.data_inputs.length>0)&&(h.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(h.data_outputs,function(k,b){var j=$("<div class='terminal output-terminal'></div>");d.enable_output_terminal(j,b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions.join(", ")+")"}var m=$("<div class='form-row dataRow'>"+f+"</div>");if(d.type=="tool"){var l=$("<div class='callout "+f+"'></div>").css({display:"none"}).append($("<div class='buttons'></div>").append($("<img/>").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png").click(function(){if($.inArray(b.name,d.workflow_outputs)!=-1){d.workflow_outputs.splice($.inArray(b.name,d.workflow_outputs),1);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{d.workflow_outputs.push(b.name);l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}workflow.has_changes=true;canvas_manager.draw_overview()}))).tooltip({delay:500,title:"Flag this as a workflow output. All non-flagged outputs will be hidden."});l.css({top:"50%",margin:"-8px 0px 0px 0px",right:8});l.show();m.append(l);if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}m.hover(function(){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-yellow.png")},function(){if($.inArray(b.name,d.workflow_outputs)===-1){l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small-outline.png")}else{l.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png")}})}m.css({position:"absolute",left:-1000,top:-1000,display:"none"});$("body").append(m);c=Math.max(c,m.outerWidth()+17);m.css({position:"",left:"",top:"",display:""});m.detach();a.append(m.append(j))});g.css("width",Math.min(250,Math.max(g.width(),c)));workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;this.annotation=f.annotation;var g=$.parseJSON(f.post_job_actions);this.post_job_actions=g?g:{};if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var h=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=h.find("div.input-data-row");$.each(f.data_inputs,function(l,j){var k=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(k,j.name,j.extensions,j.multiple);h.find("div[name='"+j.name+"']").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){k[0].terminal.connectors[0]=i;i.handle2=k[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+j.name+"'>"+j.label+"</div>").prepend(k))});h.replaceWith(b);h.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},rectify_workflow_outputs:function(){var b=false;var a=false;$.each(this.nodes,function(c,d){if(d.workflow_outputs&&d.workflow_outputs.length>0){b=true}$.each(d.post_job_actions,function(g,f){if(f.action_type==="HideDatasetAction"){a=true}})});if(b!==false||a!==false){$.each(this.nodes,function(c,g){if(g.type==="tool"){var f=false;if(g.post_job_actions==null){g.post_job_actions={};f=true}var d=[];$.each(g.post_job_actions,function(i,h){if(h.action_type=="HideDatasetAction"){d.push(i)}});if(d.length>0){$.each(d,function(h,j){f=true;delete g.post_job_actions[j]})}if(b){$.each(g.output_terminals,function(i,j){var h=true;$.each(g.workflow_outputs,function(l,m){if(j.name===m){h=false}});if(h===true){f=true;var k={action_type:"HideDatasetAction",output_name:j.name,action_arguments:{}};g.post_job_actions["HideDatasetAction"+j.name]=null;g.post_job_actions["HideDatasetAction"+j.name]=k}})}if(workflow.active_node==g&&f===true){workflow.reload_active_node()}}})}},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(i,j){g[j.name]=null;var h=[];$.each(j.connectors,function(k,l){h[k]={id:l.handle1.node.id,output_name:l.handle1.name};g[j.name]=h})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.action_type+h.output_name]=null;b[h.action_type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(b){wf=this;var c=0;wf.name=b.name;var a=false;$.each(b.steps,function(g,f){var d=prebuild_node("tool",f.name,f.tool_id);d.init_field_data(f);if(f.position){d.element.css({top:f.position.top,left:f.position.left})}d.id=f.id;wf.nodes[d.id]=d;c=Math.max(c,parseInt(g));if(!a&&d.type==="tool"){if(d.workflow_outputs.length>0){a=true}else{$.each(d.post_job_actions,function(i,h){if(h.action_type==="HideDatasetAction"){a=true}})}}});wf.id_counter=c+1;$.each(b.steps,function(g,f){var d=wf.nodes[g];$.each(f.input_connections,function(i,h){if(h){if($.isArray(h)){$.each(h,function(m,k){var n=wf.nodes[k.id];var o=new Connector();o.connect(n.output_terminals[k.output_name],d.input_terminals[i]);o.redraw()})}else{var j=wf.nodes[h.id];var l=new Connector();l.connect(j.output_terminals[h.output_name],d.input_terminals[i]);l.redraw()}}});if(a&&d.type==="tool"){$.each(d.output_terminals,function(h,i){if(d.post_job_actions["HideDatasetAction"+i.name]===undefined){d.workflow_outputs.push(i.name);callout=$(d.element).find(".callout."+i.name);callout.find("img").attr("src",galaxy_config.root+"static/images/fugue/asterisk-small.png");workflow.has_changes=true}})}})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},reload_active_node:function(){if(this.active_node){var a=this.active_node;this.clear_active_node();this.activate_node(a)}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+galaxy_config.root+"static/images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<div>").addClass("fa-icon-button fa-icon-remove").click(function(b){g.destroy()}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o,p){var f=$(this).offsetParent().offset(),b=p.offsetX-f.left,s=p.offsetY-f.top;$(this).css({left:b,top:s});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(){var g=$(this).offset();var f=b.cc.position();c=f.top-g.top;d=f.left-g.left}).bind("drag",function(f,g){a(g.offsetX+d,g.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k,l){var h=b.cc.width(),n=b.cc.height(),m=b.oc.width(),j=b.oc.height(),f=$(this).offsetParent().offset(),i=l.offsetX-f.left,g=l.offsetY-f.top;a(-(i/m*h),-(g/j*n))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g,i){var j=$(this).offsetParent();var h=j.offset();var f=Math.max(j.width()-(i.offsetX-h.left),j.height()-(i.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);$.each(workflow.nodes,function(t,q){i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;if(q.tool_errors){i.fillStyle="#FFCCCC";i.strokeStyle="#AA6666"}else{if(q.workflow_outputs!=undefined&&q.workflow_outputs.length>0){i.fillStyle="#E8A92D";i.strokeStyle="#E8A92D"}}i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}}); \ No newline at end of file diff -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 templates/grid_base.mako --- a/templates/grid_base.mako +++ b/templates/grid_base.mako @@ -84,10 +84,9 @@ /** Returns true if string denotes true. */ var is_true = function(s) { return _.indexOf(['True', 'true', 't'], s) !== -1; }; - // Create grid. var grid = new Grid({ - url_base: '${trans.request.path_url}', + url_base: location.pathname, async: is_true('${grid.use_async}'), async_ops: async_ops, categorical_filters: categorical_filters, @@ -95,6 +94,8 @@ sort_key: '${sort_key}', show_item_checkboxes: is_true('${context.get('show_item_checkboxes', False)}'), cur_page: ${cur_page_num}, + // persistant page="all" + //cur_page: ('${cur_page_num}' === 'all')?('all'):(Number('${cur_page_num}')), num_pages: ${num_pages} }); diff -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 templates/grid_common.mako --- a/templates/grid_common.mako +++ b/templates/grid_common.mako @@ -102,8 +102,26 @@ ## Print grid search/filtering UI. <%def name="render_grid_filters( grid, render_advanced_search=True )"> + <% + # Show advanced search if flag set or if there are filters for advanced search fields. + advanced_search_display = "none" + if 'advanced-search' in kwargs and kwargs['advanced-search'] in ['True', 'true']: + advanced_search_display = "block" + + for column in grid.columns: + if column.filterable == "advanced": + ## Show div if current filter has value that is different from the default filter. + if column.key in cur_filter_dict and column.key in default_filter_dict and \ + cur_filter_dict[column.key] != default_filter_dict[column.key]: + advanced_search_display = "block" + + # do not show standard search if showing adv. + standard_search_display = "block" + if advanced_search_display == "block": + standard_search_display = "none" + %> ## Standard search. - <div id="standard-search"> + <div id="standard-search" style="display: ${standard_search_display};"><table><tr><td style="padding: 0;"><table> @@ -139,19 +157,6 @@ </div> ## Advanced search. - <% - # Show advanced search if flag set or if there are filters for advanced search fields. - advanced_search_display = "none" - if 'advanced-search' in kwargs and kwargs['advanced-search'] in ['True', 'true']: - advanced_search_display = "block" - - for column in grid.columns: - if column.filterable == "advanced": - ## Show div if current filter has value that is different from the default filter. - if column.key in cur_filter_dict and column.key in default_filter_dict and \ - cur_filter_dict[column.key] != default_filter_dict[column.key]: - advanced_search_display = "block" - %><div id="advanced-search" style="display: ${advanced_search_display}; margin-top: 5px; border: 1px solid #ccc;"><table><tr><td style="text-align: left" colspan="100"> @@ -170,7 +175,7 @@ %if column.key in cur_filter_dict and column.key in default_filter_dict and \ cur_filter_dict[column.key] != default_filter_dict[column.key]: <script type="text/javascript"> - $('#advanced-search').css("display", "none"); + $('#advanced-search').css("display", "block"); </script> %endif diff -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 test/casperjs/casperjs_runner.py --- a/test/casperjs/casperjs_runner.py +++ b/test/casperjs/casperjs_runner.py @@ -176,7 +176,14 @@ err_string = ( "%s\n%s" %( get_msg( last_error ), self.browser_backtrace_to_string( get_trace( last_error ) ) ) ) - # if we couldn't parse json from what's returned on the error, raise a vanilla exc + # if we couldn't parse json from what's returned on the error, dump stdout + except ValueError, val_err: + if str( val_err ) == 'No JSON object could be decoded': + log.debug( '(error parsing returned JSON from casperjs, dumping stdout...)\n:%s', stdout_output ) + else: + raise + + # otherwise, raise a vanilla exc except Exception, exc: log.debug( '(failed to parse error returned from %s: %s)', _PATH_TO_HEADLESS, str( exc ) ) return HeadlessJSJavascriptError( diff -r b9b2d5fc998a8067866f95d71cc446f8a6b34eed -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 test/functional/test_get_data.py --- a/test/functional/test_get_data.py +++ b/test/functional/test_get_data.py @@ -22,7 +22,7 @@ """ # in order to remove a lot of boiler plate - and not have cascading errors history = get_latest_history_for_user( user ) - self.delete_history( id=self.security.encode_id( history.id ) ) + self.delete_current_history() self.is_history_empty() return get_latest_history_for_user( user ) https://bitbucket.org/galaxy/galaxy-central/commits/12502e3d1ff1/ Changeset: 12502e3d1ff1 User: martenson Date: 2013-09-20 14:55:46 Summary: Merged galaxy/galaxy-central into default Affected #: 9 files diff -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 -r 12502e3d1ff1cb221907a7641d31e7803bce30ff lib/galaxy/webapps/galaxy/api/history_contents.py --- a/lib/galaxy/webapps/galaxy/api/history_contents.py +++ b/lib/galaxy/webapps/galaxy/api/history_contents.py @@ -235,8 +235,15 @@ # get file destination file_destination = dataset.get_file_name() + # check if the directory exists + dn = os.path.dirname(file_destination) + if not os.path.exists(dn): + os.makedirs(dn) + + # get file and directory names + fn = os.path.basename(content.filename) + # save file locally - fn = os.path.basename(content.filename) open(file_destination, 'wb').write(content.file.read()) # log diff -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 -r 12502e3d1ff1cb221907a7641d31e7803bce30ff static/scripts/galaxy.modal.js --- a/static/scripts/galaxy.modal.js +++ b/static/scripts/galaxy.modal.js @@ -77,13 +77,25 @@ // link functions $.each(options.buttons, function(name, value) { - footer.append($('<button></button>').text(name).click(value)).append(" "); + footer.append($('<button id="' + String(name).toLowerCase() + '"></button>').text(name).click(value)).append(" "); }); } else // default close button footer.append($('<button></button>').text('Close').click(function() { self.hide() })).append(" "); }, + // enable buttons + enable: function(name) + { + $(this.el).find('#' + String(name).toLowerCase()).prop('disabled', false); + }, + + // disable buttons + disable: function(name) + { + $(this.el).find('#' + String(name).toLowerCase()).prop('disabled', true); + }, + /* HTML TEMPLATES */ diff -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 -r 12502e3d1ff1cb221907a7641d31e7803bce30ff static/scripts/galaxy.upload.js --- a/static/scripts/galaxy.upload.js +++ b/static/scripts/galaxy.upload.js @@ -1,5 +1,5 @@ /* - galaxy upload v1.0 + galaxy upload */ // dependencies @@ -14,12 +14,20 @@ // button button_show : null, - // file counter - file_counter: 0, + // upload mod + uploadbox: null, // initialize initialize : function() { + // wait for galaxy history panel (workaround due to the use of iframes) + if (!Galaxy.currHistoryPanel) + { + var self = this; + window.setTimeout(function() { self.initialize() }, 500) + return; + } + // add activate icon var self = this; this.button_show = new mod_master.GalaxyMasterIcon ( @@ -37,87 +45,252 @@ // events events : { - 'mouseover' : 'event_mouseover', - 'mouseleave' : 'event_mouseleave' + 'mouseover' : 'event_mouseover', + 'mouseleave' : 'event_mouseleave' }, // mouse over event_mouseover : function (e) { - $('#galaxy-upload-box').addClass('highlight'); }, // mouse left event_mouseleave : function (e) { - $('#galaxy-upload-box').removeClass('highlight'); }, // start - event_start : function(index, file, message) + event_announce : function(index, file, message) { + // hide info + this.uploadbox.info().hide(); + // make id - var id = '#galaxy-upload-file-' + index; + var id = '#upload-' + index; - // add tag - $('#galaxy-upload-box').append(this.template_file(id)); + // add upload item + $(this.el).append(this.template_file(id)); + + // scroll to bottom + $(this.el).scrollTop($(this.el).prop('scrollHeight')); + + // access upload item + var it = this.get_upload_item(index); + + // fade in + it.fadeIn(); // update title - $('#galaxy-upload-file-' + index).find('.title').html(file.name); + it.find('.title').html(file.name); + // configure select field + it.find('#extension').select2( + { + placeholder: 'Auto-detect', + width: 'copy', + ajax: { + url: "http://www.weighttraining.com/sm/search", + dataType: 'jsonp', + quietMillis: 100, + data: function(term, page) + { + return { + types: ["exercise"], + limit: -1, + term: term + }; + }, + results: function(data, page) + { + return { results: data.results.exercise } + } + }, + formatResult: function(exercise) + { + return "<div class='select2-user-result'>" + exercise.term + "</div>"; + }, + formatSelection: function(exercise) + { + return exercise.term; + }, + initSelection : function (element, callback) + { + var elementText = $(element).attr('data-init-text'); + callback({"term":elementText}); + } + }); + + // add functionality to remove button + var self = this; + it.find('.remove').on('click', function() { self.event_remove (index) }); + // initialize progress this.event_progress(index, file, 0); - // update counter - this.file_counter++; - this.refresh(); + // update button status + this.modal.enable('Upload'); + this.modal.enable('Reset'); + }, + + // start + event_initialize : function(index, file, message) + { + // update on screen counter + this.button_show.number(message); + + // get element + var it = this.get_upload_item(index); + + // read in configuration + var data = { + source : "upload", + space_to_tabs : it.find('#space_to_tabs').is(':checked'), + extension : it.find('#extension').val() + } + + // return additional data to be send with file + return data; }, // progress event_progress : function(index, file, message) { - // get progress bar - var el = $('#galaxy-upload-file-' + index); + // get element + var it = this.get_upload_item(index); // get value var percentage = parseInt(message); // update progress - el.find('.progress').css({ width : percentage + '%' }); + it.find('.progress-bar').css({ width : percentage + '%' }); // update info - el.find('.info').html(percentage + '% of ' + this.size_to_string (file.size)); + it.find('.info').html(percentage + '% of ' + this.size_to_string (file.size)); }, // end event_success : function(index, file, message) - { + { + // get element + var it = this.get_upload_item(index); + + // update progress frame + it.addClass('panel-success'); + it.removeClass('panel-default'); + // update galaxy history Galaxy.currHistoryPanel.refresh(); - // update counter - this.file_counter--; - this.refresh(); + // make sure progress is shown correctly + this.event_progress(index, file, 100); + + // update on screen counter + this.button_show.number(''); }, // end event_error : function(index, file, message) { - // get file box - var el = $('#galaxy-upload-file-' + index); + // get element + var it = this.get_upload_item(index); // update progress frame - el.find('.progress-frame').addClass('failed'); + it.addClass('panel-danger'); + it.removeClass('panel-default'); - // update error message - el.find('.error').html("<strong>Failed:</strong> " + message); - - // update progress + // remove progress bar + it.find('.progress').remove(); + + // write error message + it.find('.error').html('<strong>Failed:</strong> ' + message); + + // make sure progress is shown correctly this.event_progress(index, file, 0); - // update counter - this.file_counter--; - this.refresh(); + // update on screen counter + this.button_show.number(''); + }, + + // start upload process + event_upload : function() + { + // hide configuration + $(this.el).find('.panel-body').hide(); + + // switch icon + $(this.el).find('.remove').each(function() + { + $(this).removeClass('fa-icon-trash'); + $(this).addClass('fa-icon-caret-down'); + }); + + // update button status + this.modal.disable('Upload'); + + // configure url + var current_history = Galaxy.currHistoryPanel.model.get('id'); + this.uploadbox.configure({url : galaxy_config.root + "api/histories/" + current_history + "/contents"}); + + // initiate upload procedure in plugin + this.uploadbox.upload(); + }, + + // remove all + event_reset : function() + { + // remove from screen + var panels = $(this.el).find('.panel'); + var self = this; + panels.fadeOut({complete: function() + { + // remove panels + panels.remove(); + + // show on screen info + self.uploadbox.info().fadeIn(); + }}); + + // update button status + this.modal.disable('Upload'); + this.modal.disable('Reset'); + + // remove from queue + this.uploadbox.reset(); + }, + + // remove item from upload list + event_remove : function(index) + { + // remove + var self = this; + var it = this.get_upload_item(index); + + // fade out and update button status + it.fadeOut({complete: function() + { + // remove from screen + it.remove(); + + // remove from queue + self.uploadbox.remove(index); + + // update reset button + if ($(self.el).find('.panel').length > 0) + self.modal.enable('Reset'); + else { + // disable reset button + self.modal.disable('Reset'); + + // show on screen info + self.uploadbox.info().fadeIn(); + } + + // update upload button + if (self.uploadbox.length() > 0) + self.modal.enable('Upload'); + else + self.modal.disable('Upload'); + }}); }, // show/hide upload frame @@ -126,14 +299,6 @@ // prevent default e.preventDefault(); - // wait for galaxy history panel (workaround due to the use of iframes) - if (!Galaxy.currHistoryPanel) - { - var self = this; - window.setTimeout(function() { self.event_show(e) }, 200) - return; - } - // create modal if (!this.modal) { @@ -142,44 +307,45 @@ this.modal = new mod_modal.GalaxyModal( { title : 'Upload files from your local drive', - body : this.template(), + body : this.template('upload-box'), buttons : { - 'Close' : function() {self.modal.hide()} + 'Select' : function() {self.uploadbox.select()}, + 'Upload' : function() {self.event_upload()}, + 'Reset' : function() {self.event_reset()}, + 'Close' : function() {self.modal.hide()} } }); - // get current history - var current_history = Galaxy.currHistoryPanel.model.get('id'); - + // set element + this.setElement('#upload-box'); + // file upload var self = this; - $('#galaxy-upload-box').uploadbox( + this.uploadbox = this.$el.uploadbox( { - url : galaxy_config.root + "api/histories/" + current_history + "/contents", dragover : self.event_mouseover, dragleave : self.event_mouseleave, - start : function(index, file, message) { self.event_start(index, file, message) }, + announce : function(index, file, message) { self.event_announce(index, file, message) }, + initialize : function(index, file, message) { return self.event_initialize(index, file, message) }, success : function(index, file, message) { self.event_success(index, file, message) }, progress : function(index, file, message) { self.event_progress(index, file, message) }, error : function(index, file, message) { self.event_error(index, file, message) }, - data : {source : "upload"} }); - // set element - this.setElement('#galaxy-upload-box'); + // update button status + this.modal.disable('Upload'); + this.modal.disable('Reset'); } - + // show modal this.modal.show(); }, - // update counter - refresh: function () + // get upload item + get_upload_item: function(index) { - if (this.file_counter > 0) - this.button_show.number(this.file_counter); - else - this.button_show.number(''); + // get element + return $(this.el).find('#upload-' + index); }, // to string @@ -197,21 +363,32 @@ }, // load html template - template: function() + template: function(id) { - return '<form id="galaxy-upload-box" class="galaxy-upload-box"></form>'; + return '<div id="' + id + '" class="upload-box"></div>'; }, // load html template template_file: function(id) { - return '<div id="' + id.substr(1) + '" class="file corner-soft shadow">' + - '<div class="title"></div>' + - '<div class="error"></div>' + - '<div class="progress-frame corner-soft">' + - '<div class="progress"></div>' + + return '<div id="' + id.substr(1) + '" class="panel panel-default">' + + '<div class="panel-heading">' + + '<h5 class="title"></h5>' + + '<h5 class="info"></h5>' + + '<div class="remove fa-icon-trash"></div>' + '</div>' + - '<div class="info"></div>' + + '<div class="panel-body">' + + '<div class="menu">' + + //'<input id="extension" type="hidden" width="10px"/> ' + + '<span><input id="space_to_tabs" type="checkbox">Convert spaces to tabs</input></span>' + + '</div>' + + '</div>' + + '<div class="panel-footer">' + + '<div class="progress">' + + '<div class="progress-bar progress-bar-success"></div>' + + '</div>' + + '<h6 class="error"></h6>' + + '</div>' + '</div>'; } }); diff -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 -r 12502e3d1ff1cb221907a7641d31e7803bce30ff static/scripts/utils/galaxy.uploadbox.js --- a/static/scripts/utils/galaxy.uploadbox.js +++ b/static/scripts/utils/galaxy.uploadbox.js @@ -1,5 +1,5 @@ /* - galaxy upload lib v1.0 - uses FileReader, FormData and XMLHttpRequest + galaxy upload lib - uses FileReader, FormData and XMLHttpRequest */ ;(function($) { @@ -11,67 +11,71 @@ { url : '', paramname : 'content', - maxfilesize : 2048, - data : {}, + maxfilesize : 250, dragover : function() {}, dragleave : function() {}, + announce : function() {}, initialize : function() {}, - start : function() {}, progress : function() {}, success : function() {}, error : function(index, file, message) { alert(message); }, error_browser : "Your browser does not support drag-and-drop file uploads.", - error_filesize : "This file is too large. Please use an FTP client to upload it.", - error_default : "The upload failed. Please make sure the file is available and accessible.", - text_default : "Drag&drop files here or click to browse your local drive.", - text_degrade : "Click here to browse your local drive. <br><br>Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+." + error_filesize : "This file is too large (>250MB). Please use an FTP client to upload it.", + error_default : "Please make sure the file is available.", + text_default : "Drag&drop files into this box or click 'Select' to select files!", + text_degrade : "Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+." } - // global file queue - var queue = []; + // options + var opts = {}; + + // file queue + var queue = {}; - // global counter for file being currently processed - var queue_index = -1; + // counter for file being currently processed + var queue_index = 0; - // global queue status + // queue length + var queue_length = 0; + + // indicates if queue is currently running var queue_status = false; + // element + var el = null; + // attach to element $.fn.uploadbox = function(options) { // parse options - var opts = $.extend({}, default_opts, options); + opts = $.extend({}, default_opts, options); // compatibility var mode = window.File && window.FileReader && window.FormData && window.XMLHttpRequest; + // element + el = this; + // append upload button - this.append('<input id="uploadbox_input" type="file" style="display: none" multiple>'); - this.append('<div id="uploadbox_info"></div>'); + el.append('<input id="uploadbox_input" type="file" style="display: none" multiple>'); + el.append('<div id="uploadbox_info"></div>'); // set info text if (mode) - this.find('#uploadbox_info').html(opts.text_default); + el.find('#uploadbox_info').html(opts.text_default); else - this.find('#uploadbox_info').html(opts.text_degrade); + el.find('#uploadbox_info').html(opts.text_degrade); // attach events - this.on('drop', drop); - this.on('dragover', dragover); - this.on('dragleave', dragleave); - - // attach click event - this.on('click', function(e) - { - e.stopPropagation(); - $('#uploadbox_input').trigger(e); - }); + el.on('drop', drop); + el.on('dragover', dragover); + el.on('dragleave', dragleave); // attach change event $('#uploadbox_input').change(function(e) { - var files = e.target.files; - upload(files); + // add files to queue + add(e.target.files); }); // drop event @@ -81,11 +85,8 @@ if(!e.dataTransfer) return; - // get files from event - var files = e.dataTransfer.files; - - // start upload - upload(files); + // add files to queue + add(e.dataTransfer.files); // prevent default e.preventDefault(); @@ -98,14 +99,14 @@ function dragover(e) { e.preventDefault(); - opts.dragover.call(this, e); + opts.dragover.call(e); } // drag leave function dragleave(e) { e.stopPropagation(); - opts.dragleave.call(this, e); + opts.dragleave.call(e); } // progress @@ -117,39 +118,61 @@ } // respond to an upload request - function upload(files) + function add(files) { - // get current queue size - var queue_sofar = queue.length; + // add new files to queue + for (var i = 0; i < files.length; i++) + { + // new identifier + var index = String(++queue_index); - // add new files to queue - for (var index = 0; index < files.length; index++) - queue.push(files[index]); + // add to queue + queue[index] = files[i]; - // tell client about new uploads - for (var index = queue_sofar; index < queue.length; index++) - opts.start(index, queue[index], ""); + // increase counter + queue_length++; - // initiate processing loop if process loop is not running already - if (!queue_status) - process(); + // announce + opts.announce(index, queue[index], ""); + } } + // remove entry from queue + function remove(index) + { + if (queue[index]) + { + // remove from queue + delete queue[index]; + + // update counter + queue_length--; + } + } + // process an upload, recursive function process() { - // check if for files - if (queue_index + 1 == queue.length) + // get an identifier from the queue + var index = -1; + for (var key in queue) { - queue_status = false; - return; + index = key; + break; } - // set status - queue_status = true; + // validate + if (queue_length == 0) + return; - // identify current index - var index = ++queue_index; + // get current file from queue + var file = queue[index]; + + // remove from queue + remove(index) + + // start + var data = opts.initialize(index, file, length); // add file to queue try @@ -158,50 +181,45 @@ var reader = new FileReader(); // identify maximum file size - var file = queue[index]; var filesize = file.size; var maxfilesize = 1048576 * opts.maxfilesize; - + // set index reader.index = index; if (filesize < maxfilesize) { - // link loadend is always called at the end - reader.onloadend = function(e) + // link load + reader.onload = function(e) { - send(index, file) + send(index, file, data) }; // link error reader.onerror = function(e) { - opts.error(index, file, opts.error_default); - queue_status = false; + error(index, file, opts.error_default); }; // read data reader.readAsDataURL(file); } else { // skip file - opts.error(index, file, opts.error_filesize); - - // restart process - process(); + error(index, file, opts.error_filesize); } } catch (err) { // parse error - opts.error(index, file, err); + error(index, file, err); } } // send file - function send (index, file) + function send (index, file, data) { // construct form data var formData = new FormData(); - for (var key in opts.data) - formData.append(key, opts.data[key]); + for (var key in data) + formData.append(key, data[key]); formData.append(opts.paramname, file, file.name); // prepare request @@ -237,22 +255,94 @@ // pass any error to the error option if (xhr.status < 200 || xhr.status > 299) { + // format error + var text = xhr.statusText; + if (!xhr.statusText) + text = opts.error_default; + // request error - opts.error(index, file, xhr.statusText + " (Server Code " + xhr.status + ")"); - - // reset status - queue_status = false; - } else { + error(index, file, text + " (Server Code " + xhr.status + ")"); + } else // parse response - opts.success(index, file, response); - - // upload next file - process(); - } + success(index, file, response); } } - // return - return this; + // success + function success (index, file, msg) + { + // parse message + opts.success(index, file, msg); + + // restart process after success + process(); + } + + // error + function error (index, file, err) + { + // parse error + opts.error(index, file, err); + + // restart process after error + process(); + } + + /* + public interface + */ + + // open file browser for selection + function select() + { + $('#uploadbox_input').trigger('click'); + } + + // remove all entries from queue + function reset(index) + { + for (index in queue) + remove(index); + } + + // initiate upload process + function upload() + { + if (!queue_status) + process(); + } + + // current queue length + function length() + { + return queue_length; + } + + // set options + function configure(options) + { + // update current configuration + opts = $.extend({}, opts, options); + + // return new configuration + return opts; + } + + // visibility of on screen information + function info() + { + return el.find('#uploadbox_info'); + } + + // export functions + return { + 'select' : select, + 'remove' : remove, + 'upload' : upload, + 'reset' : reset, + 'length' : length, + 'configure' : configure, + 'info' : info + }; } })(jQuery); \ No newline at end of file diff -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 -r 12502e3d1ff1cb221907a7641d31e7803bce30ff static/style/blue/base.css --- a/static/style/blue/base.css +++ b/static/style/blue/base.css @@ -1122,15 +1122,12 @@ .galaxy-frame .frame .f-close{right:5px;top:1px} .galaxy-frame .frame .f-pin{left:6px;top:1px} .galaxy-frame .frame .f-resize{background:#fff;width:16px;height:16px;color:#2c3143;right:0px;bottom:0px;text-align:center;line-height:16px;border:0px} -.galaxy-upload-box{width:100%;height:200px;max-height:200px;padding:10px 0px 0px 0px;text-align:center;cursor:pointer;overflow:scroll;font-size:12px;line-height:1.428571429;-moz-border-radius:5px;border-radius:5px;border:1px dashed #bfbfbf}.galaxy-upload-box .corner-soft{-moz-border-radius:3px;border-radius:3px} -.galaxy-upload-box .shadow{-webkit-box-shadow:0 0 2px rgba(0,0,0,0.3)} -.galaxy-upload-box .highlight{border:1px dashed #333} -.galaxy-upload-box .file{position:relative;margin:5px 20px 5px 20px;border:1px solid #bfbfbf;color:#333}.galaxy-upload-box .file .title{margin:3px 130px 0px 5px;text-align:left;overflow:hidden;border:0px} -.galaxy-upload-box .file .progress-frame{border:0px;margin:0px 5px 3px 5px;height:7px;background:#bfbfbf} -.galaxy-upload-box .file .progress{background:#5cb85c;height:100%;width:0%} -.galaxy-upload-box .file .failed{background:#d9534f} -.galaxy-upload-box .file .error{font-size:11px;text-align:left;overflow:hidden;margin:0px 5px 0px 5px} -.galaxy-upload-box .file .info{position:absolute;top:4px;right:5px;font-size:11px;text-align:right;overflow:hidden;max-width:100px;max-height:12px} +.upload-box{width:100%;height:250px;max-height:250px;text-align:center;overflow:scroll;font-size:12px;line-height:1.33;-moz-border-radius:5px;border-radius:5px;border:1px dashed #bfbfbf;padding:20px}.upload-box .panel{display:none}.upload-box .panel .panel-heading{position:relative;height:19px;padding:5px}.upload-box .panel .panel-heading .title{position:absolute;top:2px;font-weight:normal;text-align:left;margin:0px;max-width:300px;overflow:hidden} +.upload-box .panel .panel-heading .info{position:absolute;top:3px;font-weight:normal;right:20px;text-align:right;margin:0px} +.upload-box .panel .panel-heading .remove{position:absolute;cursor:pointer;top:0px;right:3px} +.upload-box .panel .panel-body{position:relative;padding:5px} +.upload-box .panel .panel-footer{position:relative;height:20px;padding:0px}.upload-box .panel .panel-footer .progress{height:10px;margin:5px} +.upload-box .panel .panel-footer .error{font-weight:normal;margin:2px} .unselectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none} .parent-width{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:100%;*width:90%} .clear:before,.clear:after{content:" ";display:table;} diff -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 -r 12502e3d1ff1cb221907a7641d31e7803bce30ff static/style/blue/sprite-fugue.png Binary file static/style/blue/sprite-fugue.png has changed diff -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 -r 12502e3d1ff1cb221907a7641d31e7803bce30ff static/style/blue/sprite-history-buttons.png Binary file static/style/blue/sprite-history-buttons.png has changed diff -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 -r 12502e3d1ff1cb221907a7641d31e7803bce30ff static/style/blue/sprite-history-states.png Binary file static/style/blue/sprite-history-states.png has changed diff -r cd1b21880d597a2a3efd9f3abc23909f38b525b6 -r 12502e3d1ff1cb221907a7641d31e7803bce30ff static/style/src/less/upload.less --- a/static/style/src/less/upload.less +++ b/static/style/src/less/upload.less @@ -1,87 +1,80 @@ -.galaxy-upload-box +.upload-box { width : 100%; - height : 200px; - max-height : 200px; - padding : 10px 0px 0px 0px; + height : 250px; + max-height : 250px; text-align : center; - cursor : pointer; overflow : scroll; font-size : @font-size-base; - line-height : @line-height-base; + line-height : @line-height-large; -moz-border-radius: @border-radius-large; - border-radius: @border-radius-large; + border-radius : @border-radius-large; border : 1px dashed @btn-default-border; + padding : 20px; - .corner-soft + .panel { - -moz-border-radius: @border-radius-base; - border-radius: @border-radius-base; - } + display: none; - .shadow - { - -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.3); - } + .panel-heading + { + position: relative; + height: 19px; + padding: 5px; - .highlight - { - border : 1px dashed @btn-default-color; - } + .title + { + position: absolute; + top: 2px; + font-weight: normal; + text-align: left; + margin: 0px; + max-width: 300px; + overflow: hidden; + } - .file - { - position : relative; - margin : 5px 20px 5px 20px; - border : 1px solid @btn-default-border; - color : @btn-default-color; + .info + { + position: absolute; + top: 3px; + font-weight: normal; + right: 20px; + text-align: right; + margin: 0px; + } - .title - { - margin : 3px 130px 0px 5px; - text-align : left; - overflow : hidden; - border : 0px; + .remove + { + position: absolute; + cursor: pointer; + top: 0px; + right: 3px; + } } - .progress-frame + .panel-body { - border : 0px; - margin : 0px 5px 3px 5px; - height : 7px; - background : @btn-default-border; + position: relative; + padding: 5px; } - .progress + .panel-footer { - background : @bs-success; - height : 100%; - width : 0%; - } - - .failed - { - background : @bs-danger; - } - - .error - { - font-size : @font-size-small; - text-align : left; - overflow : hidden; - margin : 0px 5px 0px 5px; - } - - .info - { - position : absolute; - top : 4px; - right : 5px; - font-size : @font-size-small; - text-align : right; - overflow : hidden; - max-width : 100px; - max-height : 12px; + position:relative; + height: 20px; + padding: 0px; + + .progress + { + height: 10px; + margin: 5px; + } + + .error + { + font-weight: normal; + margin: 2px; + } } } } \ No newline at end of file https://bitbucket.org/galaxy/galaxy-central/commits/7c5b45d615b8/ Changeset: 7c5b45d615b8 User: martenson Date: 2013-09-20 16:05:54 Summary: loading missing configuration parameters Affected #: 1 file diff -r 12502e3d1ff1cb221907a7641d31e7803bce30ff -r 7c5b45d615b84e820b621890e18eceb4750fc629 lib/galaxy/config.py --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -135,9 +135,7 @@ self.admin_email = kwargs.get( 'admin_email', None ) self.user_activation_on = kwargs.get( 'user_activation_on', None ) self.activation_grace_period = kwargs.get( 'activation_grace_period', None ) - self.inactivity_box_visible = kwargs.get( 'inactivity_box_visible', None ) self.inactivity_box_content = kwargs.get( 'inactivity_box_content', None ) - self.inactivity_box_class = kwargs.get( 'inactivity_box_class', None ) # Get the disposable email domains blacklist file self.blacklist_file = resolve_path( kwargs.get( 'blacklist_file', None ), self.root ) self.smtp_server = kwargs.get( 'smtp_server', None ) https://bitbucket.org/galaxy/galaxy-central/commits/976bab742c0f/ Changeset: 976bab742c0f User: martenson Date: 2013-09-20 22:10:01 Summary: Merged galaxy/galaxy-central into default Affected #: 20 files diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/galaxy/config.py --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -215,6 +215,7 @@ if self.nginx_upload_store: self.nginx_upload_store = os.path.abspath( self.nginx_upload_store ) self.object_store = kwargs.get( 'object_store', 'disk' ) + self.object_store_check_old_style = string_as_bool( kwargs.get( 'object_store_check_old_style', False ) ) self.object_store_cache_path = resolve_path( kwargs.get( "object_store_cache_path", "database/object_store_cache" ), self.root ) # Handle AWS-specific config options for backward compatibility if kwargs.get( 'aws_access_key', None) is not None: diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -25,7 +25,7 @@ from galaxy.datatypes.metadata import MetadataCollection from galaxy.model.item_attrs import Dictifiable, UsesAnnotations from galaxy.security import get_permitted_actions -from galaxy.util import is_multi_byte, nice_size, Params, restore_text, send_mail +from galaxy.util import asbool, is_multi_byte, nice_size, Params, restore_text, send_mail from galaxy.util.bunch import Bunch from galaxy.util.hash_util import new_secure_hash from galaxy.web.framework.helpers import to_unicode @@ -34,6 +34,7 @@ WorkflowMappingField) from sqlalchemy.orm import object_session from sqlalchemy.sql.expression import func +from tool_shed.util import common_util log = logging.getLogger( __name__ ) @@ -3465,7 +3466,28 @@ @property def has_repository_dependencies( self ): if self.metadata: - return 'repository_dependencies' in self.metadata + repository_dependencies_dict = self.metadata.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + # [["http://localhost:9009", "package_libgtextutils_0_6", "test", "e2003cbf18cd", "True", "True"]] + for rd_tup in repository_dependencies: + tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ + common_util.parse_repository_dependency_tuple( rd_tup ) + if not asbool( only_if_compiling_contained_td ): + return True + return False + + @property + def has_repository_dependencies_only_if_compiling_contained_td( self ): + if self.metadata: + repository_dependencies_dict = self.metadata.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + # [["http://localhost:9009", "package_libgtextutils_0_6", "test", "e2003cbf18cd", "True", "True"]] + for rd_tup in repository_dependencies: + tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ + common_util.parse_repository_dependency_tuple( rd_tup ) + if not asbool( only_if_compiling_contained_td ): + return False + return True return False @property @@ -3697,10 +3719,14 @@ @property def tuples_of_repository_dependencies_needed_for_compiling_td( self ): - """Return this repository's repository dependencies that are necessary only for compiling this repository's tool dependencies.""" + """ + Return tuples defining this repository's repository dependencies that are necessary only for compiling this repository's tool + dependencies. + """ rd_tups_of_repositories_needed_for_compiling_td = [] - if self.has_repository_dependencies: - rd_tups = self.metadata[ 'repository_dependencies' ][ 'repository_dependencies' ] + if self.metadata: + repository_dependencies = self.metadata.get( 'repository_dependencies', None ) + rd_tups = repository_dependencies[ 'repository_dependencies' ] for rd_tup in rd_tups: if len( rd_tup ) == 6: tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = rd_tup diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/galaxy/objectstore/__init__.py --- a/lib/galaxy/objectstore/__init__.py +++ b/lib/galaxy/objectstore/__init__.py @@ -198,6 +198,7 @@ super(DiskObjectStore, self).__init__(config, file_path=file_path, extra_dirs=extra_dirs) self.file_path = file_path or config.file_path self.config = config + self.check_old_style = config.object_store_check_old_style self.extra_dirs['job_work'] = config.job_working_directory self.extra_dirs['temp'] = config.new_file_path if extra_dirs is not None: @@ -264,14 +265,13 @@ return os.path.abspath(path) def exists(self, obj, **kwargs): - path = self._construct_path(obj, old_style=True, **kwargs) - # For backward compatibility, check root path first; otherwise, construct - # and check hashed path - if os.path.exists(path): - return True - else: - path = self._construct_path(obj, **kwargs) - return os.path.exists(path) + if self.check_old_style: + path = self._construct_path(obj, old_style=True, **kwargs) + # For backward compatibility, check root path first; otherwise, construct + # and check hashed path + if os.path.exists(path): + return True + return os.path.exists(self._construct_path(obj, **kwargs)) def create(self, obj, **kwargs): if not self.exists(obj, **kwargs): @@ -320,13 +320,13 @@ return content def get_filename(self, obj, **kwargs): - path = self._construct_path(obj, old_style=True, **kwargs) - # For backward compatibility, check root path first; otherwise, construct - # and return hashed path - if os.path.exists(path): - return path - else: - return self._construct_path(obj, **kwargs) + if self.check_old_style: + path = self._construct_path(obj, old_style=True, **kwargs) + # For backward compatibility, check root path first; otherwise, construct + # and return hashed path + if os.path.exists(path): + return path + return self._construct_path(obj, **kwargs) def update_from_file(self, obj, file_name=None, create=False, **kwargs): """ `create` parameter is not used in this implementation """ diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py --- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py +++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py @@ -812,7 +812,7 @@ status = kwd.get( 'status', 'done' ) shed_tool_conf = kwd.get( 'shed_tool_conf', None ) tool_shed_url = kwd[ 'tool_shed_url' ] - # Handle repository dependencies. + # Handle repository dependencies, which do not include those that are required only for compiling a dependent repository's tool dependencies. has_repository_dependencies = util.string_as_bool( kwd.get( 'has_repository_dependencies', False ) ) install_repository_dependencies = kwd.get( 'install_repository_dependencies', '' ) # Every repository will be installed into the same tool panel section or all will be installed outside of any sections. @@ -1061,7 +1061,7 @@ repository_clone_url, metadata, trans.model.ToolShedRepository.installation_status.NEW, - tool_shed_repository.installed_changeset_revision, + tool_shed_repository.changeset_revision, tool_shed_repository.owner, tool_shed_repository.dist_to_shed ) ctx_rev = suc.get_ctx_rev( trans.app, @@ -1320,7 +1320,6 @@ missing_tool_dependencies = dependencies_for_repository_dict.get( 'missing_tool_dependencies', None ) repository_name = dependencies_for_repository_dict.get( 'name', None ) repository_owner = dependencies_for_repository_dict.get( 'repository_owner', None ) - if installed_repository_dependencies or missing_repository_dependencies: has_repository_dependencies = True else: diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/galaxy/webapps/galaxy/controllers/history.py --- a/lib/galaxy/webapps/galaxy/controllers/history.py +++ b/lib/galaxy/webapps/galaxy/controllers/history.py @@ -309,7 +309,6 @@ # If deleting the current history, make a new current. if history == trans.get_history(): deleted_current = True - trans.get_or_create_default_history() trans.log_event( "History (%s) marked as deleted" % history.name ) n_deleted += 1 if purge and trans.app.config.allow_user_dataset_purge: @@ -339,6 +338,8 @@ part += " but the datasets were not removed from disk because that feature is not enabled in this Galaxy instance" message_parts.append( "%s. " % part ) if deleted_current: + #note: this needs to come after commits above or will use an empty history that was deleted above + trans.get_or_create_default_history() message_parts.append( "Your active history was deleted, a new empty history is now active. " ) status = INFO return ( status, " ".join( message_parts ) ) diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/galaxy/webapps/tool_shed/api/repositories.py --- a/lib/galaxy/webapps/tool_shed/api/repositories.py +++ b/lib/galaxy/webapps/tool_shed/api/repositories.py @@ -73,6 +73,7 @@ "changeset_revision": "3a08cc21466f", "downloadable": true, "has_repository_dependencies": false, + "has_repository_dependencies_only_if_compiling_contained_td": false, "id": "f9cad7b01a472135", "includes_datatypes": false, "includes_tool_dependencies": false, @@ -125,7 +126,8 @@ action='show', id=encoded_repository_metadata_id ) # Get the repo_info_dict for installing the repository. - repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, has_repository_dependencies = \ + repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, \ + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ repository_util.get_repo_info_dict( trans, encoded_repository_id, changeset_revision ) return repository_dict, repository_metadata_dict, repo_info_dict else: diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/galaxy/webapps/tool_shed/controllers/repository.py --- a/lib/galaxy/webapps/tool_shed/controllers/repository.py +++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py @@ -1343,32 +1343,36 @@ def get_changeset_revision_and_ctx_rev( self, trans, **kwd ): """Handle a request from a local Galaxy instance to retrieve the changeset revision hash to which an installed repository can be updated.""" def has_galaxy_utilities( repository_metadata ): - includes_data_managers = False - includes_datatypes = False - includes_tools = False - includes_tools_for_display_in_tool_panel = False - has_repository_dependencies = False - includes_tool_dependencies = False - includes_workflows = False + has_galaxy_utilities_dict = dict( includes_data_managers=False, + includes_datatypes=False, + includes_tools=False, + includes_tools_for_display_in_tool_panel=False, + has_repository_dependencies=False, + has_repository_dependencies_only_if_compiling_contained_td=False, + includes_tool_dependencies=False, + includes_workflows=False ) if repository_metadata: includes_tools_for_display_in_tool_panel = repository_metadata.includes_tools_for_display_in_tool_panel metadata = repository_metadata.metadata if metadata: if 'data_manager' in metadata: - includes_data_managers = True + has_galaxy_utilities_dict[ 'includes_data_managers' ] = True if 'datatypes' in metadata: - includes_datatypes = True + has_galaxy_utilities_dict[ 'includes_datatypes' ] = True if 'tools' in metadata: - includes_tools = True + has_galaxy_utilities_dict[ 'includes_tools' ] = True if 'tool_dependencies' in metadata: - includes_tool_dependencies = True - if 'repository_dependencies' in metadata: - has_repository_dependencies = True + has_galaxy_utilities_dict[ 'includes_tool_dependencies' ] = True + repository_dependencies_dict = metadata.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( repository_dependencies ) + has_galaxy_utilities_dict[ 'has_repository_dependencies' ] = has_repository_dependencies + has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = \ + has_repository_dependencies_only_if_compiling_contained_td if 'workflows' in metadata: - includes_workflows = True - return includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows - message = kwd.get( 'message', '' ) - status = kwd.get( 'status', 'done' ) + has_galaxy_utilities_dict[ 'includes_workflows' ] = True + return has_galaxy_utilities_dict name = kwd.get( 'name', None ) owner = kwd.get( 'owner', None ) changeset_revision = kwd.get( 'changeset_revision', None ) @@ -1376,8 +1380,15 @@ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, trans.security.encode_id( repository.id ), changeset_revision ) - includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \ - has_galaxy_utilities( repository_metadata ) + has_galaxy_utilities_dict = has_galaxy_utilities( repository_metadata ) + includes_data_managers = has_galaxy_utilities_dict[ 'includes_data_managers' ] + includes_datatypes = has_galaxy_utilities_dict[ 'includes_datatypes' ] + includes_tools = has_galaxy_utilities_dict[ 'includes_tools' ] + includes_tools_for_display_in_tool_panel = has_galaxy_utilities_dict[ 'includes_tools_for_display_in_tool_panel' ] + includes_tool_dependencies = has_galaxy_utilities_dict[ 'includes_tool_dependencies' ] + has_repository_dependencies = has_galaxy_utilities_dict[ 'has_repository_dependencies' ] + has_repository_dependencies_only_if_compiling_contained_td = has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] + includes_workflows = has_galaxy_utilities_dict[ 'includes_workflows' ] repo_dir = repository.repo_path( trans.app ) repo = hg.repository( suc.get_configured_ui(), repo_dir ) # Default to the received changeset revision and ctx_rev. @@ -1392,6 +1403,7 @@ includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, includes_tool_dependencies=includes_tool_dependencies, has_repository_dependencies=has_repository_dependencies, + has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td, includes_workflows=includes_workflows ) if changeset_revision == repository.tip( trans.app ): # If changeset_revision is the repository tip, there are no additional updates. @@ -1407,6 +1419,7 @@ for changeset in repo.changelog: includes_tools = False has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False changeset_hash = str( repo.changectx( changeset ) ) ctx = suc.get_changectx_for_changeset( repo, changeset_hash ) if update_to_changeset_hash: @@ -1414,8 +1427,15 @@ trans.security.encode_id( repository.id ), changeset_hash ) if update_to_repository_metadata: - includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \ - has_galaxy_utilities( update_to_repository_metadata ) + has_galaxy_utilities_dict = has_galaxy_utilities( repository_metadata ) + includes_data_managers = has_galaxy_utilities_dict[ 'includes_data_managers' ] + includes_datatypes = has_galaxy_utilities_dict[ 'includes_datatypes' ] + includes_tools = has_galaxy_utilities_dict[ 'includes_tools' ] + includes_tools_for_display_in_tool_panel = has_galaxy_utilities_dict[ 'includes_tools_for_display_in_tool_panel' ] + includes_tool_dependencies = has_galaxy_utilities_dict[ 'includes_tool_dependencies' ] + has_repository_dependencies = has_galaxy_utilities_dict[ 'has_repository_dependencies' ] + has_repository_dependencies_only_if_compiling_contained_td = has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] + includes_workflows = has_galaxy_utilities_dict[ 'includes_workflows' ] # We found a RepositoryMetadata record. if changeset_hash == repository.tip( trans.app ): # The current ctx is the repository tip, so use it. @@ -1435,6 +1455,7 @@ update_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies update_dict[ 'includes_workflows' ] = includes_workflows update_dict[ 'has_repository_dependencies' ] = has_repository_dependencies + update_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = has_repository_dependencies_only_if_compiling_contained_td update_dict[ 'changeset_revision' ] = str( latest_changeset_revision ) update_dict[ 'ctx_rev' ] = str( update_to_ctx.rev() ) return encoding_util.tool_shed_encode( update_dict ) @@ -1611,14 +1632,18 @@ includes_tools = False includes_tools_for_display_in_tool_panel = False has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False includes_tool_dependencies = False repo_info_dicts = [] for tup in zip( util.listify( repository_ids ), util.listify( changeset_revisions ) ): repository_id, changeset_revision = tup - repo_info_dict, cur_includes_tools, cur_includes_tool_dependencies, cur_includes_tools_for_display_in_tool_panel, cur_has_repository_dependencies = \ + repo_info_dict, cur_includes_tools, cur_includes_tool_dependencies, cur_includes_tools_for_display_in_tool_panel, \ + cur_has_repository_dependencies, cur_has_repository_dependencies_only_if_compiling_contained_td = \ repository_util.get_repo_info_dict( trans, repository_id, changeset_revision ) if cur_has_repository_dependencies and not has_repository_dependencies: has_repository_dependencies = True + if cur_has_repository_dependencies_only_if_compiling_contained_td and not has_repository_dependencies_only_if_compiling_contained_td: + has_repository_dependencies_only_if_compiling_contained_td = True if cur_includes_tools and not includes_tools: includes_tools = True if cur_includes_tool_dependencies and not includes_tool_dependencies: @@ -1629,6 +1654,7 @@ return dict( includes_tools=includes_tools, includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, has_repository_dependencies=has_repository_dependencies, + has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td, includes_tool_dependencies=includes_tool_dependencies, repo_info_dicts=repo_info_dicts ) @@ -1708,7 +1734,9 @@ tool_version_dicts = [] for changeset in repo.changelog: current_changeset_revision = str( repo.changectx( changeset ) ) - repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, trans.security.encode_id( repository.id ), current_changeset_revision ) + repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, + trans.security.encode_id( repository.id ), + current_changeset_revision ) if repository_metadata and repository_metadata.tool_versions: tool_version_dicts.append( repository_metadata.tool_versions ) if current_changeset_revision == changeset_revision: @@ -1766,22 +1794,30 @@ includes_workflows = True readme_files_dict = readme_util.build_readme_files_dict( metadata ) # See if the repo_info_dict was populated with repository_dependencies or tool_dependencies. + has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False + includes_tool_dependencies = False for name, repo_info_tuple in repo_info_dict.items(): - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ - suc.get_repo_info_tuple_contents( repo_info_tuple ) - if repository_dependencies: - has_repository_dependencies = True - else: - has_repository_dependencies = False - if tool_dependencies: - includes_tool_dependencies = True - else: - includes_tool_dependencies = False + if not has_repository_dependencies or not has_repository_dependencies_only_if_compiling_contained_td or not includes_tool_dependencies: + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ + suc.get_repo_info_tuple_contents( repo_info_tuple ) + for rd_key, rd_tups in repository_dependencies.items(): + if rd_key in [ 'root_key', 'description' ]: + continue + curr_has_repository_dependencies, curr_has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( rd_tups ) + if curr_has_repository_dependencies and not has_repository_dependencies: + has_repository_dependencies = True + if curr_has_repository_dependencies_only_if_compiling_contained_td and not has_repository_dependencies_only_if_compiling_contained_td: + has_repository_dependencies_only_if_compiling_contained_td = True + if tool_dependencies and not includes_tool_dependencies: + includes_tool_dependencies = True return dict( includes_data_managers=includes_data_managers, includes_datatypes=includes_datatypes, includes_tools=includes_tools, includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, has_repository_dependencies=has_repository_dependencies, + has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td, includes_tool_dependencies=includes_tool_dependencies, includes_workflows=includes_workflows, readme_files_dict=readme_files_dict, @@ -2434,7 +2470,9 @@ try: commands.remove( repo.ui, repo, selected_file, force=True ) except Exception, e: - log.debug( "Error removing files using the mercurial API, so trying a different approach, the error was: %s" % str( e )) + log.debug( "Error removing the following file using the mercurial API:\n %s" % str( selected_file ) ) + log.debug( "The error was: %s" % str( e )) + log.debug( "Attempting to remove the file using a different approach." ) relative_selected_file = selected_file.split( 'repo_%d' % repository.id )[1].lstrip( '/' ) repo.dirstate.remove( relative_selected_file ) repo.dirstate.write() diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/galaxy/webapps/tool_shed/model/__init__.py --- a/lib/galaxy/webapps/tool_shed/model/__init__.py +++ b/lib/galaxy/webapps/tool_shed/model/__init__.py @@ -253,6 +253,7 @@ self.time_last_tested = time_last_tested self.tool_test_results = tool_test_results self.has_repository_dependencies = has_repository_dependencies + # We don't consider the special case has_repository_dependencies_only_if_compiling_contained_td here. self.includes_datatypes = includes_datatypes self.includes_tools = includes_tools self.includes_tool_dependencies = includes_tool_dependencies diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/tool_shed/galaxy_install/repository_util.py --- a/lib/tool_shed/galaxy_install/repository_util.py +++ b/lib/tool_shed/galaxy_install/repository_util.py @@ -234,10 +234,10 @@ else: includes_tools = False includes_tools_for_display_in_tool_panel = repository_metadata.includes_tools_for_display_in_tool_panel - if 'repository_dependencies' in metadata: - has_repository_dependencies = True - else: - has_repository_dependencies = False + repository_dependencies_dict = metadata.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( repository_dependencies ) if 'tool_dependencies' in metadata: includes_tool_dependencies = True else: @@ -246,6 +246,7 @@ # Here's where we may have to handle enhancements to the callers. See above comment. includes_tools = False has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False includes_tool_dependencies = False includes_tools_for_display_in_tool_panel = False ctx = suc.get_changectx_for_changeset( repo, changeset_revision ) @@ -259,7 +260,8 @@ repository_metadata=repository_metadata, tool_dependencies=None, repository_dependencies=None ) - return repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, has_repository_dependencies + return repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, \ + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td def get_repository_components_for_installation( encoded_tsr_id, encoded_tsr_ids, repo_info_dicts, tool_panel_section_keys ): """ @@ -311,6 +313,7 @@ includes_tool_dependencies = update_dict.get( 'includes_tool_dependencies', False ) includes_workflows = update_dict.get( 'includes_workflows', False ) has_repository_dependencies = update_dict.get( 'has_repository_dependencies', False ) + has_repository_dependencies_only_if_compiling_contained_td = update_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False ) changeset_revision = update_dict.get( 'changeset_revision', None ) ctx_rev = update_dict.get( 'ctx_rev', None ) changeset_revision_dict[ 'includes_data_managers' ] = includes_data_managers @@ -320,6 +323,7 @@ changeset_revision_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies changeset_revision_dict[ 'includes_workflows' ] = includes_workflows changeset_revision_dict[ 'has_repository_dependencies' ] = has_repository_dependencies + changeset_revision_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = has_repository_dependencies_only_if_compiling_contained_td changeset_revision_dict[ 'changeset_revision' ] = changeset_revision changeset_revision_dict[ 'ctx_rev' ] = ctx_rev except Exception, e: @@ -331,6 +335,7 @@ changeset_revision_dict[ 'includes_tool_dependencies' ] = False changeset_revision_dict[ 'includes_workflows' ] = False changeset_revision_dict[ 'has_repository_dependencies' ] = False + changeset_revision_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = False changeset_revision_dict[ 'changeset_revision' ] = None changeset_revision_dict[ 'ctx_rev' ] = None return changeset_revision_dict diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/tool_shed/galaxy_install/tool_dependencies/install_util.py --- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py +++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py @@ -394,7 +394,7 @@ if not binary_installed: print 'Binary installation did not occur, so proceeding with install and compile recipe.' # Make sure to reset for installation if attempt at binary installation resulted in an error. - if tool_dependency.status != app.model.ToolDependency.installation_status.NEW: + if tool_dependency.status != app.model.ToolDependency.installation_status.NEVER_INSTALLED: removed, error_message = tool_dependency_util.remove_tool_dependency( app, tool_dependency ) install_via_fabric( app, tool_dependency, diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/tool_shed/util/common_install_util.py --- a/lib/tool_shed/util/common_install_util.py +++ b/lib/tool_shed/util/common_install_util.py @@ -12,6 +12,7 @@ from tool_shed.util import encoding_util from tool_shed.util import data_manager_util from tool_shed.util import datatype_util +from tool_shed.util import tool_dependency_util from tool_shed.util import tool_util from tool_shed.util import xml_util from tool_shed.galaxy_install.tool_dependencies.install_util import install_package @@ -69,16 +70,28 @@ Return dictionaries containing the sets of installed and missing tool dependencies and repository dependencies associated with the repository defined by the received repo_info_dict. """ + repository = None + installed_rd = {} + installed_td = {} + missing_rd = {} + missing_td = {} name = repo_info_dict.keys()[ 0 ] repo_info_tuple = repo_info_dict[ name ] - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td = \ + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ suc.get_repo_info_tuple_contents( repo_info_tuple ) + if tool_dependencies: + if not includes_tool_dependencies: + includes_tool_dependencies = True + # Inspect the tool_dependencies dictionary to separate the installed and missing tool dependencies. We don't add to installed_td + # and missing_td here because at this point they are empty. + installed_td, missing_td = get_installed_and_missing_tool_dependencies( trans, tool_shed_url, tool_dependencies ) + # In cases where a repository dependency is required only for compiling a dependent repository's tool dependency, the value of + # repository_dependencies will be an empty dictionary here. if repository_dependencies: # We have a repository with one or more defined repository dependencies. missing_td = {} - # Handle the scenario where a repository was installed, then uninstalled and an error occurred during the re-installation process. - # In this case, a record for the repository will exist in the database with the status of 'New'. - repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed_url, name, repository_owner, changeset_revision ) + if not repository: + repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed_url, name, repository_owner, changeset_revision ) if repository and repository.metadata: installed_rd, missing_rd = get_installed_and_missing_repository_dependencies( trans, repository ) else: @@ -86,73 +99,70 @@ # Discover all repository dependencies and retrieve information for installing them. all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) ) has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False ) + has_repository_dependencies_only_if_compiling_contained_td = all_repo_info_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False ) includes_tools_for_display_in_tool_panel = all_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False ) includes_tool_dependencies = all_repo_info_dict.get( 'includes_tool_dependencies', False ) includes_tools = all_repo_info_dict.get( 'includes_tools', False ) required_repo_info_dicts = all_repo_info_dict.get( 'all_repo_info_dicts', [] ) # Display tool dependencies defined for each of the repository dependencies. if required_repo_info_dicts: - all_tool_dependencies = {} + required_tool_dependencies = {} for rid in required_repo_info_dicts: for name, repo_info_tuple in rid.items(): - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, rid_installed_td = \ + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, rid_repository_dependencies, rid_tool_dependencies = \ suc.get_repo_info_tuple_contents( repo_info_tuple ) - if rid_installed_td: - for td_key, td_dict in rid_installed_td.items(): - if td_key not in all_tool_dependencies: - all_tool_dependencies[ td_key ] = td_dict - if all_tool_dependencies: - if installed_td is None: - installed_td = {} - else: - # Move all tool dependencies to the missing_tool_dependencies container. - for td_key, td_dict in installed_td.items(): - if td_key not in missing_td: - missing_td[ td_key ] = td_dict - installed_td = {} + if rid_tool_dependencies: + for td_key, td_dict in rid_tool_dependencies.items(): + if td_key not in required_tool_dependencies: + required_tool_dependencies[ td_key ] = td_dict + if required_tool_dependencies: # Discover and categorize all tool dependencies defined for this repository's repository dependencies. - required_tool_dependencies, required_missing_tool_dependencies = \ - get_installed_and_missing_tool_dependencies_for_new_install( trans, all_tool_dependencies ) - if required_tool_dependencies: + required_installed_td, required_missing_td = get_installed_and_missing_tool_dependencies( trans, + tool_shed_url, + required_tool_dependencies ) + if required_installed_td: if not includes_tool_dependencies: includes_tool_dependencies = True - for td_key, td_dict in required_tool_dependencies.items(): + for td_key, td_dict in required_installed_td.items(): if td_key not in installed_td: installed_td[ td_key ] = td_dict - if required_missing_tool_dependencies: + if required_missing_td: if not includes_tool_dependencies: includes_tool_dependencies = True - for td_key, td_dict in required_missing_tool_dependencies.items(): + for td_key, td_dict in required_missing_td.items(): if td_key not in missing_td: missing_td[ td_key ] = td_dict else: - # We have a single repository with no defined repository dependencies. + # We have a single repository with (possibly) no defined repository dependencies. all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) ) has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False ) + has_repository_dependencies_only_if_compiling_contained_td = all_repo_info_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False ) includes_tools_for_display_in_tool_panel = all_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False ) includes_tool_dependencies = all_repo_info_dict.get( 'includes_tool_dependencies', False ) includes_tools = all_repo_info_dict.get( 'includes_tools', False ) required_repo_info_dicts = all_repo_info_dict.get( 'all_repo_info_dicts', [] ) - installed_rd = None - missing_rd = None - missing_td = None - dependencies_for_repository_dict = dict( changeset_revision=changeset_revision, - has_repository_dependencies=has_repository_dependencies, - includes_tool_dependencies=includes_tool_dependencies, - includes_tools=includes_tools, - includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, - installed_repository_dependencies=installed_rd, - installed_tool_dependencies=installed_td, - missing_repository_dependencies=missing_rd, - missing_tool_dependencies=missing_td, - name=name, - repository_owner=repository_owner ) + dependencies_for_repository_dict = \ + dict( changeset_revision=changeset_revision, + has_repository_dependencies=has_repository_dependencies, + has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td, + includes_tool_dependencies=includes_tool_dependencies, + includes_tools=includes_tools, + includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, + installed_repository_dependencies=installed_rd, + installed_tool_dependencies=installed_td, + missing_repository_dependencies=missing_rd, + missing_tool_dependencies=missing_td, + name=name, + repository_owner=repository_owner ) return dependencies_for_repository_dict def get_installed_and_missing_repository_dependencies( trans, repository ): """ Return the installed and missing repository dependencies for a tool shed repository that has a record in the Galaxy database, but - may or may not be installed. In this case, the repository dependencies are associated with the repository in the database. + may or may not be installed. In this case, the repository dependencies are associated with the repository in the database. Do not + include a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since these + special kinds of repository dependencies are really a dependency of the dependent repository's contained tool dependency, and only if + that tool dependency requires compilation. """ missing_repository_dependencies = {} installed_repository_dependencies = {} @@ -166,7 +176,14 @@ for tsr in repository.repository_dependencies: prior_installation_required = suc.set_prior_installation_required( repository, tsr ) only_if_compiling_contained_td = suc.set_only_if_compiling_contained_td( repository, tsr ) - rd_tup = [ tsr.tool_shed, tsr.name, tsr.owner, tsr.changeset_revision, prior_installation_required, only_if_compiling_contained_td, tsr.id, tsr.status ] + rd_tup = [ tsr.tool_shed, + tsr.name, + tsr.owner, + tsr.changeset_revision, + prior_installation_required, + only_if_compiling_contained_td, + tsr.id, + tsr.status ] if tsr.status == trans.model.ToolShedRepository.installation_status.INSTALLED: installed_rd_tups.append( rd_tup ) else: @@ -184,7 +201,7 @@ repository_dependencies = metadata.get( 'repository_dependencies', {} ) description = repository_dependencies.get( 'description', None ) # We need to add a root_key entry to one or both of installed_repository_dependencies dictionary and the missing_repository_dependencies - # dictionary for proper display parsing. + # dictionaries for proper display parsing. root_key = container_util.generate_repository_dependencies_key_for_repository( repository.tool_shed, repository.name, repository.owner, @@ -210,7 +227,7 @@ installed_repository_dependencies = {} missing_rd_tups = [] installed_rd_tups = [] - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td = \ + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ suc.get_repo_info_tuple_contents( repo_info_tuple ) if repository_dependencies: description = repository_dependencies[ 'description' ] @@ -228,7 +245,7 @@ # tuple looks like: ( description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td ) tmp_clone_url = suc.generate_clone_url_from_repo_info_tup( rd_tup ) tmp_repo_info_tuple = ( None, tmp_clone_url, changeset_revision, None, owner, None, None ) - repository, current_changeset_revision = suc.repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple ) + repository, installed_changeset_revision = suc.repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple ) if repository: new_rd_tup = [ tool_shed, name, @@ -273,29 +290,46 @@ missing_repository_dependencies[ 'description' ] = description return installed_repository_dependencies, missing_repository_dependencies -def get_installed_and_missing_tool_dependencies_for_new_install( trans, all_tool_dependencies ): +def get_installed_and_missing_tool_dependencies( trans, tool_shed_url, tool_dependencies_dict ): """Return the lists of installed tool dependencies and missing tool dependencies for a set of repositories being installed into Galaxy.""" - # FIXME: confirm that this method currently populates and returns only missing tool dependencies. If so, this method should be enhanced to search for - # installed tool dependencies defined as complex repository dependency relationships. - if all_tool_dependencies: - tool_dependencies = {} - missing_tool_dependencies = {} - for td_key, val in all_tool_dependencies.items(): - # Set environment tool dependencies are a list, set each member to never installed. + installed_tool_dependencies = {} + missing_tool_dependencies = {} + if tool_dependencies_dict: + for td_key, val in tool_dependencies_dict.items(): + # Default the status to NEVER_INSTALLED. + tool_dependency_status = trans.model.ToolDependency.installation_status.NEVER_INSTALLED + # Set environment tool dependencies are a list. if td_key == 'set_environment': new_val = [] for requirement_dict in val: - requirement_dict[ 'status' ] = trans.model.ToolDependency.installation_status.NEVER_INSTALLED + # {'repository_name': 'xx', 'name': 'bwa', 'version': '0.5.9', 'repository_owner': 'yy', 'changeset_revision': 'zz', 'type': 'package'} + tool_dependency = tool_dependency_util.get_tool_dependency_by_name_version_type( trans.app, + requirement_dict.get( 'name', None ), + requirement_dict.get( 'version', None ), + requirement_dict.get( 'type', 'package' ) ) + if tool_dependency: + tool_dependency_status = tool_dependency.status + requirement_dict[ 'status' ] = tool_dependency_status new_val.append( requirement_dict ) - missing_tool_dependencies[ td_key ] = new_val + if tool_dependency_status in [ trans.model.ToolDependency.installation_status.INSTALLED ]: + installed_tool_dependencies[ td_key ] = new_val + else: + missing_tool_dependencies[ td_key ] = new_val else: - # Since we have a new install, missing tool dependencies have never been installed. - val[ 'status' ] = trans.model.ToolDependency.installation_status.NEVER_INSTALLED + # The val dictionary looks something like this: + # {'repository_name': 'xx', 'name': 'bwa', 'version': '0.5.9', 'repository_owner': 'yy', 'changeset_revision': 'zz', 'type': 'package'} + tool_dependency = tool_dependency_util.get_tool_dependency_by_name_version_type( trans.app, + val.get( 'name', None ), + val.get( 'version', None ), + val.get( 'type', 'package' ) ) + if tool_dependency: + tool_dependency_status = tool_dependency.status + val[ 'status' ] = tool_dependency_status + if tool_dependency_status in [ trans.model.ToolDependency.installation_status.INSTALLED ]: + installed_tool_dependencies[ td_key ] = val + else: missing_tool_dependencies[ td_key ] = val - else: - tool_dependencies = None - missing_tool_dependencies = None - return tool_dependencies, missing_tool_dependencies + return installed_tool_dependencies, missing_tool_dependencies def get_required_repo_info_dicts( trans, tool_shed_url, repo_info_dicts ): """ @@ -328,7 +362,9 @@ toolshed, name, owner, changeset_revision = container_util.get_components_from_key( key ) components_list = [ toolshed, name, owner, changeset_revision ] only_if_compiling_contained_td = 'False' - # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository. + # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since + # in this case, the repository dependency is really a dependency of the dependent repository's contained tool dependency, and only if + # that tool dependency requires compilation. if not util.asbool( only_if_compiling_contained_td ): if components_list not in required_repository_tups: required_repository_tups.append( components_list ) @@ -337,8 +373,8 @@ only_if_compiling_contained_td = components_list[ 5 ] except: only_if_compiling_contained_td = 'False' - # TODO: Fix this to display the tool dependency if only_if_compiling_contained_td is True, but clarify that installation may not - # happen. + # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository + # (see above comment). if not util.asbool( only_if_compiling_contained_td ): if components_list not in required_repository_tups: required_repository_tups.append( components_list ) diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/tool_shed/util/common_util.py --- a/lib/tool_shed/util/common_util.py +++ b/lib/tool_shed/util/common_util.py @@ -1,3 +1,4 @@ +import logging import os import urllib2 from galaxy.util import json @@ -5,6 +6,8 @@ from tool_shed.util import encoding_util from tool_shed.util import xml_util +log = logging.getLogger( __name__ ) + REPOSITORY_OWNER = 'devteam' def accumulate_tool_dependencies( tool_shed_accessible, tool_dependencies, all_tool_dependencies ): diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/tool_shed/util/metadata_util.py --- a/lib/tool_shed/util/metadata_util.py +++ b/lib/tool_shed/util/metadata_util.py @@ -280,13 +280,16 @@ def create_or_update_repository_metadata( trans, id, repository, changeset_revision, metadata_dict ): """Create or update a repository_metadatqa record in the tool shed.""" has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False includes_datatypes = False includes_tools = False includes_tool_dependencies = False includes_workflows = False if metadata_dict: - if 'repository_dependencies' in metadata_dict: - has_repository_dependencies = True + repository_dependencies_dict = metadata_dict.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( repository_dependencies ) if 'datatypes' in metadata_dict: includes_datatypes = True if 'tools' in metadata_dict: @@ -295,7 +298,11 @@ includes_tool_dependencies = True if 'workflows' in metadata_dict: includes_workflows = True - downloadable = has_repository_dependencies or includes_datatypes or includes_tools or includes_tool_dependencies or includes_workflows + if has_repository_dependencies or has_repository_dependencies_only_if_compiling_contained_td or includes_datatypes or \ + includes_tools or includes_tool_dependencies or includes_workflows: + downloadable = True + else: + downloadable = False repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, id, changeset_revision ) if repository_metadata: # A repository metadata record already exists with the received changeset_revision, so we don't need to check the skip_tool_test table. @@ -1851,10 +1858,13 @@ repository_metadata.includes_datatypes = True else: repository_metadata.includes_datatypes = False - if 'repository_dependencies' in metadata_dict: - repository_metadata.has_repository_dependencies = True - else: - repository_metadata.has_repository_dependencies = False + # We don't store information about the special type of repository dependency that is needed only for compiling a tool dependency + # defined for the dependent repository. + repository_dependencies_dict = metadata_dict.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( repository_dependencies ) + repository_metadata.has_repository_dependencies = has_repository_dependencies if 'tool_dependencies' in metadata_dict: repository_metadata.includes_tool_dependencies = True else: diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/tool_shed/util/repository_dependency_util.py --- a/lib/tool_shed/util/repository_dependency_util.py +++ b/lib/tool_shed/util/repository_dependency_util.py @@ -139,6 +139,7 @@ # repository dependencies are not to be installed, only those items contained in the received repo_info_dicts list will be processed. if is_in_repo_info_dicts( repo_info_dict, repo_info_dicts ) or install_repository_dependencies: if installed_tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.ERROR, + trans.model.ToolShedRepository.installation_status.NEW, trans.model.ToolShedRepository.installation_status.UNINSTALLED ]: # The current tool shed repository is not currently installed, so we can update it's record in the database. can_update = True diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/tool_shed/util/shed_util_common.py --- a/lib/tool_shed/util/shed_util_common.py +++ b/lib/tool_shed/util/shed_util_common.py @@ -868,6 +868,31 @@ .first() return None +def get_repository_dependency_types( repository_dependencies ): + """ + Inspect the received list of repository_dependencies tuples and return boolean values for has_repository_dependencies and + has_repository_dependencies_only_if_compiling_contained_td. + """ + # Set has_repository_dependencies, which will be True only if at least one repository_dependency is defined with the value of + # only_if_compiling_contained_td as False. + has_repository_dependencies = False + for rd_tup in repository_dependencies: + tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ + common_util.parse_repository_dependency_tuple( rd_tup ) + if not asbool( only_if_compiling_contained_td ): + has_repository_dependencies = True + break + # Set has_repository_dependencies_only_if_compiling_contained_td, which will be True only if at least one repository_dependency is + # defined with the value of only_if_compiling_contained_td as True. + has_repository_dependencies_only_if_compiling_contained_td = False + for rd_tup in repository_dependencies: + tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ + common_util.parse_repository_dependency_tuple( rd_tup ) + if asbool( only_if_compiling_contained_td ): + has_repository_dependencies_only_if_compiling_contained_td = True + break + return has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td + def get_repository_for_dependency_relationship( app, tool_shed, name, owner, changeset_revision ): """Return an installed tool_shed_repository database record that is defined by either the current changeset revision or the installed_changeset_revision.""" # This method is used only in Galaxy, not the tool shed. @@ -1389,14 +1414,23 @@ def repository_was_previously_installed( trans, tool_shed_url, repository_name, repo_info_tuple ): """ - Handle the case where the repository was previously installed using an older changeset_revsion, but later the repository was updated - in the tool shed and now we're trying to install the latest changeset revision of the same repository instead of updating the one - that was previously installed. We'll look in the database instead of on disk since the repository may be uninstalled. + Find out if a repository is already installed into Galaxy - there are several scenarios where this is necessary. For example, this method + will handle the case where the repository was previously installed using an older changeset_revsion, but later the repository was updated + in the tool shed and now we're trying to install the latest changeset revision of the same repository instead of updating the one that was + previously installed. We'll look in the database instead of on disk since the repository may be currently uninstalled. """ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ get_repo_info_tuple_contents( repo_info_tuple ) tool_shed = get_tool_shed_from_clone_url( repository_clone_url ) - # Get all previous change set revisions from the tool shed for the repository back to, but excluding, the previous valid changeset + # See if we can locate the repository using the value of changeset_revision. + tool_shed_repository = get_tool_shed_repository_by_shed_name_owner_installed_changeset_revision( trans.app, + tool_shed, + repository_name, + repository_owner, + changeset_revision ) + if tool_shed_repository: + return tool_shed_repository, changeset_revision + # Get all previous changeset revisions from the tool shed for the repository back to, but excluding, the previous valid changeset # revision to see if it was previously installed using one of them. url = url_join( tool_shed_url, 'repository/previous_changeset_revisions?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s' % \ @@ -1410,14 +1444,14 @@ repository_name, repository_owner, previous_changeset_revision ) - if tool_shed_repository and tool_shed_repository.status not in [ trans.model.ToolShedRepository.installation_status.NEW ]: + if tool_shed_repository: return tool_shed_repository, previous_changeset_revision return None, None def reset_previously_installed_repository( trans, repository ): """ Reset the atrributes of a tool_shed_repository that was previsouly installed. The repository will be in some state other than with a - status of INSTALLED, so all atributes will be set to the default (NEW( state. This will enable the repository to be freshly installed. + status of INSTALLED, so all atributes will be set to the default NEW state. This will enable the repository to be freshly installed. """ repository.deleted = False repository.tool_shed_status = None diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/tool_shed/util/tool_dependency_util.py --- a/lib/tool_shed/util/tool_dependency_util.py +++ b/lib/tool_shed/util/tool_dependency_util.py @@ -258,6 +258,14 @@ app.model.ToolDependency.table.c.type == type ) ) \ .first() +def get_tool_dependency_by_name_version_type( app, name, version, type ): + sa_session = app.model.context.current + return sa_session.query( app.model.ToolDependency ) \ + .filter( and_( app.model.ToolDependency.table.c.name == name, + app.model.ToolDependency.table.c.version == version, + app.model.ToolDependency.table.c.type == type ) ) \ + .first() + def get_tool_dependency_by_name_version_type_repository( app, repository, name, version, type ): sa_session = app.model.context.current return sa_session.query( app.model.ToolDependency ) \ diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 lib/tool_shed/util/tool_util.py --- a/lib/tool_shed/util/tool_util.py +++ b/lib/tool_shed/util/tool_util.py @@ -962,7 +962,7 @@ suc.config_elems_to_xml_file( trans.app, config_elems, shed_tool_conf, tool_path ) def remove_from_tool_panel( trans, repository, shed_tool_conf, uninstall ): - """A tool shed repository is being deactivated or uninstalled so handle tool panel alterations accordingly.""" + """A tool shed repository is being deactivated or uninstalled, so handle tool panel alterations accordingly.""" # Determine where the tools are currently defined in the tool panel and store this information so the tools can be displayed # in the same way when the repository is activated or reinstalled. tool_panel_dict = suc.generate_tool_panel_dict_from_shed_tool_conf_entries( trans.app, repository ) diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 test/functional/test_get_data.py --- a/test/functional/test_get_data.py +++ b/test/functional/test_get_data.py @@ -22,7 +22,7 @@ """ # in order to remove a lot of boiler plate - and not have cascading errors history = get_latest_history_for_user( user ) - self.delete_current_history() + self.delete_history( id=self.security.encode_id( history.id ) ) self.is_history_empty() return get_latest_history_for_user( user ) diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 test/tool_shed/base/twilltestcase.py --- a/test/tool_shed/base/twilltestcase.py +++ b/test/tool_shed/base/twilltestcase.py @@ -114,7 +114,7 @@ # version=section_version ) # This dict is appended to tool_panel_section_metadata[ tool_guid ] tool_panel_section = tool_panel_section_metadata[ tool_guid ][ 0 ][ 'name' ] - assert tool_panel_section == expected_tool_panel_section, 'Expected tool panel section %s, found %s\nMetadata: %s\n' % \ + assert tool_panel_section == expected_tool_panel_section, 'Expected to find tool panel section *%s*, but instead found *%s*\nMetadata: %s\n' % \ ( expected_tool_panel_section, tool_panel_section, metadata ) def check_installed_repository_tool_dependencies( self, diff -r 7c5b45d615b84e820b621890e18eceb4750fc629 -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 universe_wsgi.ini.sample --- a/universe_wsgi.ini.sample +++ b/universe_wsgi.ini.sample @@ -209,6 +209,12 @@ # distributed, hierarchical) #object_store = disk +# *Extremely* old Galaxy instances created datasets at the root of the +# `file_path` defined above. If your Galaxy instance has datasets at the root +# (instead of in directories composed by hashing the dataset id), you should +# enable this option to allow Galaxy to find them. +#object_store_check_old_style = False + # Credentials used by certain (s3, swift) object store backends #os_access_key = <your cloud object store access key> #os_secret_key = <your cloud object store secret key> https://bitbucket.org/galaxy/galaxy-central/commits/47a440430f4a/ Changeset: 47a440430f4a User: martenson Date: 2013-09-23 01:41:47 Summary: Merged galaxy/galaxy-central into default Affected #: 6 files diff -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 -r 47a440430f4a7ffa546c1740664527ecfbd5d62f lib/galaxy/web/base/controller.py --- a/lib/galaxy/web/base/controller.py +++ b/lib/galaxy/web/base/controller.py @@ -587,8 +587,10 @@ hda_dict[ 'api_type' ] = "file" # Add additional attributes that depend on trans can hence must be added here rather than at the model level. - - #NOTE: access is an expensive operation - removing it and adding the precondition of access is already checked + can_access_hda = trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset ) + can_access_hda = ( trans.user_is_admin() or can_access_hda ) + if not can_access_hda: + return self.get_inaccessible_hda_dict( trans, hda ) hda_dict[ 'accessible' ] = True # ---- return here if deleted AND purged OR can't access @@ -634,6 +636,18 @@ return trans.security.encode_dict_ids( hda_dict ) + def get_inaccessible_hda_dict( self, trans, hda ): + return trans.security.encode_dict_ids({ + 'id' : hda.id, + 'history_id': hda.history.id, + 'hid' : hda.hid, + 'name' : hda.name, + 'state' : hda.state, + 'deleted' : hda.deleted, + 'visible' : hda.visible, + 'accessible': False + }) + def get_hda_dict_with_error( self, trans, hda, error_msg='' ): return trans.security.encode_dict_ids({ 'id' : hda.id, diff -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 -r 47a440430f4a7ffa546c1740664527ecfbd5d62f static/scripts/galaxy.base.js --- a/static/scripts/galaxy.base.js +++ b/static/scripts/galaxy.base.js @@ -66,7 +66,10 @@ }; /** - * Sets up popupmenu rendering and binds options functions to the appropriate links + * Sets up popupmenu rendering and binds options functions to the appropriate links. + * initial_options is a dict with text describing the option pointing to either (a) a + * function to perform; or (b) another dict with two required keys, 'url' and 'action' (the + * function to perform. (b) is useful for exposing the underlying URL of the option. */ function make_popupmenu(button_element, initial_options) { /* Use the $.data feature to store options with the link element. @@ -92,7 +95,9 @@ } $.each( options, function( k, v ) { if (v) { - menu_element.append( $("<li></li>").append( $("<a href='#'></a>").html(k).click(v) ) ); + // Action can be either an anonymous function and a mapped dict. + var action = v.action || v; + menu_element.append( $("<li></li>").append( $("<a>").attr("href", v.url).html(k).click(action) ) ); } else { menu_element.append( $("<li></li>").addClass( "head" ).append( $("<a href='#'></a>").html(k) ) ); } @@ -164,43 +169,24 @@ options[ link.text() ] = null; } else { - options[ link.text() ] = function() { + options[ link.text() ] = { + url: href, + action: function() { - // if theres confirm text, send the dialog - if ( !confirmtext || confirm( confirmtext ) ) { - var f; - // relocate the center panel - if ( target === "_parent" ) { - window.parent.location = href; - - // relocate the entire window - } else if ( target === "_top" ) { - window.top.location = href; - - // Http request target is a window named demolocal on the local box - } else if ( target === "demo" ) { - if ( f === undefined || f.closed ) { - f = window.open( href,target ); - f.creator = self; + // if theres confirm text, send the dialog + if ( !confirmtext || confirm( confirmtext ) ) { + var f; + // Http request target is a window named demolocal on the local box + if ( target === "demo" ) { + if ( f === undefined || f.closed ) { + f = window.open( href,target ); + f.creator = self; + } + } - - // this panel or other, valid panels - } else { - // it may be that the button and menu href are not in the same frame: - // allow certain frame names to be used as a target - var other_valid_targets = [ - 'galaxy_main' - // following are blocked until needed - //'galaxy_tools', - //'galaxy_history' - ]; - if( ( target && ( target in window ) - && ( other_valid_targets.indexOf( target ) !== -1 ) ) ){ - window[ target ].location = href; - - // relocate this panel - } else { - window.location = href; + // For all other links, do the default action. + else { + link.trigger('click'); } } } diff -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 -r 47a440430f4a7ffa546c1740664527ecfbd5d62f static/scripts/galaxy.panels.js --- a/static/scripts/galaxy.panels.js +++ b/static/scripts/galaxy.panels.js @@ -168,16 +168,17 @@ this.$overlay.show(); this.$dialog.show(); this.$overlay.addClass("in"); - // Fix min-width so that modal cannot shrink considerably if - // new content is loaded. + // Fix min-width so that modal cannot shrink considerably if new content is loaded. this.$body.css( "min-width", this.$body.width() ); - // Set max-height so that modal does not exceed window size. - // FIXME: this could perhaps be handled better using a container for the modal - // header-body-footer and setting max-height for the container. + // Set max-height so that modal does not exceed window size and is in middle of page. + // TODO: this could perhaps be handled better using CSS. this.$body.css( "max-height", - // 2* to provide buffer between bottom of modal and bottom of page. - $(window).height() - 2 * this.$dialog.offset().top - - this.$footer.outerHeight() - this.$header.outerHeight()); + $(window).height() - + this.$footer.outerHeight() - + this.$header.outerHeight() - + parseInt( this.$dialog.css( "padding-top" ), 10 ) - + parseInt( this.$dialog.css( "padding-bottom" ), 10 ) + ); } // Callback on init if ( callback ) { diff -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 -r 47a440430f4a7ffa546c1740664527ecfbd5d62f static/style/blue/base.css --- a/static/style/blue/base.css +++ b/static/style/blue/base.css @@ -756,6 +756,7 @@ .btn.active,.btn:active{color:inherit} .dropdown-menu{max-width:auto} input[type="checkbox"],input[type="radio"]{margin-left:0.5ex;margin-right:0.5ex} +.modal-body{overflow:auto} .nav-tabs{margin-bottom:15px} a{text-decoration:underline} label{font-weight:normal} @@ -1389,9 +1390,9 @@ div.historyItem-setting_metadata{background:#ffc}div.historyItem-setting_metadata .state-icon{background-image:url(data_running.gif)} div.historyItem-upload{background:#a6e4f7}div.historyItem-upload .state-icon{background-image:url(data_upload.gif)} div.historyItem-queued{background:#eee}div.historyItem-queued .state-icon{background-image:url(sprite-history-states.png);background-position:0px -45px;width:15px;height:15px;height:15px} -div.historyItem-noPermission{filter:alpha(opacity=60);-moz-opacity:.60;opacity:.60} -div.historyItem-paused{background:#d9edf7}div.historyItem-paused .state-icon{font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-paused .state-icon:before{content:"\f04c"} -div.historyItem-new .state-icon{font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-new .state-icon:before{content:"\f071"} +div.historyItem-noPermission{filter:alpha(opacity=60);-moz-opacity:.60;opacity:.60}div.historyItem-noPermission .state-icon{line-height:16px;font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-noPermission .state-icon:before{content:"\f05e"} +div.historyItem-paused{background:#d9edf7}div.historyItem-paused .state-icon{line-height:16px;font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-paused .state-icon:before{content:"\f04c"} +div.historyItem-new .state-icon{line-height:16px;font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}div.historyItem-new .state-icon:before{content:"\f071"} div.historyItemTitleBar.spinner .state-icon{background:url(data_running.gif) 0 1px no-repeat !important} div.historyItemButtons{float:right}div.historyItemButtons .icon-button.display{background-image:url(sprite-history-buttons.png);background-position:0px -48px;width:16px;height:16px} div.historyItemButtons .icon-button.display:hover{background-image:url(sprite-history-buttons.png);background-position:0px -64px;width:16px;height:16px} diff -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 -r 47a440430f4a7ffa546c1740664527ecfbd5d62f static/style/src/less/base.less --- a/static/style/src/less/base.less +++ b/static/style/src/less/base.less @@ -1509,11 +1509,19 @@ filter: alpha(opacity=60); -moz-opacity: .60; opacity: .60; + .state-icon { + line-height: 16px; + .fa-icon(); + &:before { + content: "\f05e"; + } + } } div.historyItem-paused { background: @state-paused-bg; .state-icon { + line-height: 16px; .fa-icon(); &:before { content: "\f04c"; @@ -1523,6 +1531,7 @@ div.historyItem-new { .state-icon { + line-height: 16px; .fa-icon(); &:before { content: "\f071"; diff -r 976bab742c0fb077beb131e6b0a09cb1eb8f58d9 -r 47a440430f4a7ffa546c1740664527ecfbd5d62f static/style/src/less/galaxy_bootstrap/overrides.less --- a/static/style/src/less/galaxy_bootstrap/overrides.less +++ b/static/style/src/less/galaxy_bootstrap/overrides.less @@ -32,6 +32,9 @@ // Modal -- wider by default, scroll like Trello /* + +NOTE: these styles do not currently work. + .modal { position: absolute; top: 50px; @@ -54,6 +57,11 @@ } */ +// Scroll modal body. +.modal-body { + overflow: auto; +} + // Tabs -- border color is hardcoded in navs.less, change to @btnBorder here .nav-tabs { https://bitbucket.org/galaxy/galaxy-central/commits/fe2f53fbf68d/ Changeset: fe2f53fbf68d User: martenson Date: 2013-09-23 20:29:36 Summary: Merged galaxy/galaxy-central into default Affected #: 4 files diff -r 47a440430f4a7ffa546c1740664527ecfbd5d62f -r fe2f53fbf68db53c694382c0447a23dfa9c56aea eggs.ini --- a/eggs.ini +++ b/eggs.ini @@ -40,13 +40,14 @@ docutils = 0.7 drmaa = 0.4b3 elementtree = 1.2.6_20050316 -Fabric = 1.4.2 +Fabric = 1.7.0 GeneTrack = 2.0.0_beta_1 lrucache = 0.2 Mako = 0.4.1 nose = 0.11.1 NoseHTML = 0.4.1 NoseTestDiff = 0.1 +paramiko = 1.11.1 Parsley = 1.1 Paste = 1.7.5.1 PasteDeploy = 1.5.0 diff -r 47a440430f4a7ffa546c1740664527ecfbd5d62f -r fe2f53fbf68db53c694382c0447a23dfa9c56aea lib/galaxy/config.py --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -63,7 +63,7 @@ elif 'tool_config_files' in kwargs: tcf = kwargs[ 'tool_config_files' ] else: - tcf = 'tool_conf.xml' + tcf = 'tool_conf.xml,shed_tool_conf.xml' self.tool_filters = listify( kwargs.get( "tool_filters", [] ) ) self.tool_label_filters = listify( kwargs.get( "tool_label_filters", [] ) ) self.tool_section_filters = listify( kwargs.get( "tool_section_filters", [] ) ) diff -r 47a440430f4a7ffa546c1740664527ecfbd5d62f -r fe2f53fbf68db53c694382c0447a23dfa9c56aea lib/galaxy/webapps/tool_shed/controllers/repository.py --- a/lib/galaxy/webapps/tool_shed/controllers/repository.py +++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py @@ -973,9 +973,9 @@ flush_needed = True if flush_needed: trans.sa_session.flush() - message = "Repository '%s' has been created." % repository.name + message = "Repository <b>%s</b> has been created." % str( repository.name ) trans.response.send_redirect( web.url_for( controller='repository', - action='view_repository', + action='manage_repository', message=message, id=trans.security.encode_id( repository.id ) ) ) repository_type_select_field = rt_util.build_repository_type_select_field( trans ) diff -r 47a440430f4a7ffa546c1740664527ecfbd5d62f -r fe2f53fbf68db53c694382c0447a23dfa9c56aea test/tool_shed/functional/test_0440_deleting_dependency_definitions.py --- a/test/tool_shed/functional/test_0440_deleting_dependency_definitions.py +++ b/test/tool_shed/functional/test_0440_deleting_dependency_definitions.py @@ -74,7 +74,7 @@ description='Description of Deleted Dependency Definitions category for test 0440' ) self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) - strings_displayed = [ "Repository 'column_maker_0440' has been created" ] + strings_displayed = [ "Repository <b>column_maker_0440</b> has been created" ] repository = self.get_or_create_repository( name=column_repository_name, description=column_repository_description, long_description=column_repository_long_description, @@ -99,7 +99,7 @@ category = test_db_util.get_category_by_name( 'Test 0440 Deleted Dependency Definitions' ) self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) - strings_displayed = [ "Repository 'convert_chars_0440' has been created" ] + strings_displayed = [ "Repository <b>convert_chars_0440</b> has been created" ] repository = self.get_or_create_repository( name=convert_repository_name, description=convert_repository_description, long_description=convert_repository_long_description, @@ -182,7 +182,7 @@ category = test_db_util.get_category_by_name( 'Test 0440 Deleted Dependency Definitions' ) self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) - strings_displayed = [ "Repository 'bwa_package_0440' has been created" ] + strings_displayed = [ "Repository <b>bwa_package_0440</b> has been created" ] repository = self.get_or_create_repository( name=bwa_package_repository_name, description=bwa_package_repository_description, long_description=bwa_package_repository_long_description, @@ -208,7 +208,7 @@ category = test_db_util.get_category_by_name( 'Test 0440 Deleted Dependency Definitions' ) self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) - strings_displayed = [ "Repository 'bwa_base_0440' has been created" ] + strings_displayed = [ "Repository <b>bwa_base_0440</b> has been created" ] repository = self.get_or_create_repository( name=bwa_base_repository_name, description=bwa_base_repository_description, long_description=bwa_base_repository_long_description, @@ -291,7 +291,7 @@ category = test_db_util.get_category_by_name( 'Test 0440 Deleted Dependency Definitions' ) self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) - strings_displayed = [ "Repository 'bwa_tool_dependency_0440' has been created" ] + strings_displayed = [ "Repository <b>bwa_tool_dependency_0440</b> has been created" ] repository = self.get_or_create_repository( name=bwa_tool_dependency_repository_name, description=bwa_tool_dependency_repository_description, long_description=bwa_tool_dependency_repository_long_description, https://bitbucket.org/galaxy/galaxy-central/commits/779171e9d245/ Changeset: 779171e9d245 User: martenson Date: 2013-09-23 20:30:37 Summary: activation feature refactoring Affected #: 5 files diff -r fe2f53fbf68db53c694382c0447a23dfa9c56aea -r 779171e9d2452d825087d548adc862ed67f61c3b lib/galaxy/config.py --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -136,8 +136,16 @@ self.user_activation_on = kwargs.get( 'user_activation_on', None ) self.activation_grace_period = kwargs.get( 'activation_grace_period', None ) self.inactivity_box_content = kwargs.get( 'inactivity_box_content', None ) - # Get the disposable email domains blacklist file - self.blacklist_file = resolve_path( kwargs.get( 'blacklist_file', None ), self.root ) + # Get the disposable email domains blacklist file and its contents + self.blacklist_location = kwargs.get( 'blacklist_file', None ) + self.blacklist_content = None + if self.blacklist_location is not None: + self.blacklist_file = resolve_path( kwargs.get( 'blacklist_file', None ), self.root ) + try: + with open(self.blacklist_file) as blacklist: + self.blacklist_content = [ line.rstrip() for line in blacklist.readlines() ] + except IOError: + print ( "CONFIGURATION ERROR: Can't open supplied blacklist file from path: " + str( self.blacklist_file ) ) self.smtp_server = kwargs.get( 'smtp_server', None ) self.smtp_username = kwargs.get( 'smtp_username', None ) self.smtp_password = kwargs.get( 'smtp_password', None ) diff -r fe2f53fbf68db53c694382c0447a23dfa9c56aea -r 779171e9d2452d825087d548adc862ed67f61c3b lib/galaxy/jobs/handler.py --- a/lib/galaxy/jobs/handler.py +++ b/lib/galaxy/jobs/handler.py @@ -94,7 +94,7 @@ | ( model.Job.state == model.Job.states.RUNNING ) \ | ( model.Job.state == model.Job.states.QUEUED ) ) \ & ( model.Job.handler == self.app.config.server_name ) \ - & or_( ( model.Job.user_id == None ),( model.User.active == True ) ) ).all() + & or_( ( model.Job.user_id is None ),( model.User.active is True ) ) ).all() else: jobs_at_startup = self.sa_session.query( model.Job ).enable_eagerloads( False ) \ .filter( ( ( model.Job.state == model.Job.states.NEW ) \ @@ -175,23 +175,23 @@ .join(model.Dataset) \ .filter(and_((model.Job.state == model.Job.states.NEW), or_((model.HistoryDatasetAssociation._state == model.HistoryDatasetAssociation.states.FAILED_METADATA), - (model.HistoryDatasetAssociation.deleted == True ), + (model.HistoryDatasetAssociation.deleted is True ), (model.Dataset.state != model.Dataset.states.OK ), - (model.Dataset.deleted == True)))).subquery() + (model.Dataset.deleted is True)))).subquery() ldda_not_ready = self.sa_session.query(model.Job.id).enable_eagerloads(False) \ .join(model.JobToInputLibraryDatasetAssociation) \ .join(model.LibraryDatasetDatasetAssociation) \ .join(model.Dataset) \ .filter(and_((model.Job.state == model.Job.states.NEW), or_((model.LibraryDatasetDatasetAssociation._state != None), - (model.LibraryDatasetDatasetAssociation.deleted == True), + (model.LibraryDatasetDatasetAssociation.deleted is True), (model.Dataset.state != model.Dataset.states.OK), - (model.Dataset.deleted == True)))).subquery() + (model.Dataset.deleted is True)))).subquery() if self.app.config.user_activation_on: jobs_to_check = self.sa_session.query(model.Job).enable_eagerloads(False) \ .outerjoin( model.User ) \ .filter(and_((model.Job.state == model.Job.states.NEW), - or_((model.Job.user_id == None),(model.User.active == True)), + or_((model.Job.user_id is None),(model.User.active is True)), (model.Job.handler == self.app.config.server_name), ~model.Job.table.c.id.in_(hda_not_ready), ~model.Job.table.c.id.in_(ldda_not_ready))) \ diff -r fe2f53fbf68db53c694382c0447a23dfa9c56aea -r 779171e9d2452d825087d548adc862ed67f61c3b lib/galaxy/security/validate_user_input.py --- a/lib/galaxy/security/validate_user_input.py +++ b/lib/galaxy/security/validate_user_input.py @@ -11,10 +11,6 @@ Validates the email format, also checks whether the domain is blacklisted in the disposable domains configuration. """ message = '' - # Load the blacklist file location from the configuration file. - blacklist_file = trans.app.config.blacklist_file - if blacklist_file is not None: - email_blacklist = [ line.rstrip() for line in file( blacklist_file ).readlines() ] if user and user.email == email: return message if not( VALID_EMAIL_RE.match( email ) ): @@ -23,9 +19,9 @@ message = "Email address exceeds maximum allowable length." elif check_dup and trans.sa_session.query( trans.app.model.User ).filter_by( email=email ).first(): message = "User with that email already exists." - # If the blacklist is not empty filter out the disposable domains. - elif email_blacklist is not None: - if email.split('@')[1] in email_blacklist: + # If the blacklist is not empty filter out the disposable domains. + elif trans.app.config.blacklist_content is not None: + if email.split('@')[1] in trans.app.config.blacklist_content: message = "Please enter your permanent email address." return message diff -r fe2f53fbf68db53c694382c0447a23dfa9c56aea -r 779171e9d2452d825087d548adc862ed67f61c3b lib/galaxy/webapps/galaxy/controllers/user.py --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -546,7 +546,7 @@ # Activation is forced and the user is not active yet. Check the grace period. activation_grace_period = trans.app.config.activation_grace_period # Default value is 3 hours. - if activation_grace_period == None: + if activation_grace_period is None: activation_grace_period = 3 delta = timedelta( hours = int( activation_grace_period ) ) time_difference = datetime.utcnow() - create_time @@ -766,7 +766,7 @@ """ user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email == email ).first() activation_token = user.activation_token - if activation_token == None: + if activation_token is None: activation_token = hash_util.new_secure_hash( str( random.getrandbits( 256 ) ) ) user.activation_token = activation_token trans.sa_session.add( user ) @@ -782,7 +782,7 @@ email = urllib.unquote( params.get( 'email', None ) ) activation_token = params.get( 'activation_token', None ) - if email == None or activation_token == None: + if email is None or activation_token is None: # We don't have the email or activation_token, show error. return trans.show_error_message( "You are using wrong activation link. Try to log-in and we will send you a new activation email.<br><a href='%s'>Go to login page.</a>" ) % web.url_for( controller="root", action="index" ) else: diff -r fe2f53fbf68db53c694382c0447a23dfa9c56aea -r 779171e9d2452d825087d548adc862ed67f61c3b static/style/src/less/base.less --- a/static/style/src/less/base.less +++ b/static/style/src/less/base.less @@ -80,6 +80,17 @@ font-size: 90%; } +#inactivebox { + position:absolute; + top: @navbar-height + @layout_top_padding + 1; + left:0; + width:100%; + height: @panel_header_height !important; + overflow: hidden; + border-bottom: solid #999 1px; + font-size: 90%; +} + @layout_top_padding: 0px; @border-default-color_padding: 0px; https://bitbucket.org/galaxy/galaxy-central/commits/8ed6de16640d/ Changeset: 8ed6de16640d User: martenson Date: 2013-09-23 20:43:05 Summary: Merged galaxy/galaxy-central into default Affected #: 2 files diff -r 779171e9d2452d825087d548adc862ed67f61c3b -r 8ed6de16640d1003725cdb0793ec2f84051371cd lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -1683,7 +1683,7 @@ rval += child.get_disk_usage( user ) return rval - def to_dict( self, view='collection' ): + def to_dict( self, view='collection', expose_dataset_path=False ): """ Return attributes of this HDA that are exposed using the API. """ @@ -1716,6 +1716,9 @@ for name, spec in hda.metadata.spec.items(): val = hda.metadata.get( name ) if isinstance( val, MetadataFile ): + # only when explicitly set: fetching filepaths can be expensive + if not expose_dataset_path: + continue val = val.file_name # If no value for metadata, look in datatype for metadata. elif val == None and hasattr( hda.datatype, name ): diff -r 779171e9d2452d825087d548adc862ed67f61c3b -r 8ed6de16640d1003725cdb0793ec2f84051371cd lib/galaxy/web/base/controller.py --- a/lib/galaxy/web/base/controller.py +++ b/lib/galaxy/web/base/controller.py @@ -583,7 +583,8 @@ """ #precondition: the user's access to this hda has already been checked #TODO:?? postcondition: all ids are encoded (is this really what we want at this level?) - hda_dict = hda.to_dict( view='element' ) + expose_dataset_path = trans.user_is_admin() or trans.app.config.expose_dataset_path + hda_dict = hda.to_dict( view='element', expose_dataset_path=expose_dataset_path ) hda_dict[ 'api_type' ] = "file" # Add additional attributes that depend on trans can hence must be added here rather than at the model level. @@ -599,7 +600,7 @@ #TODO: to_dict should really go AFTER this - only summary data return trans.security.encode_dict_ids( hda_dict ) - if trans.user_is_admin() or trans.app.config.expose_dataset_path: + if expose_dataset_path: hda_dict[ 'file_name' ] = hda.file_name hda_dict[ 'download_url' ] = url_for( 'history_contents_display', https://bitbucket.org/galaxy/galaxy-central/commits/ffde896496c1/ Changeset: ffde896496c1 User: martenson Date: 2013-09-23 20:55:17 Summary: removed the 'is None' fix, in queries previously used '== None' works differently (and correctly) Affected #: 1 file diff -r 8ed6de16640d1003725cdb0793ec2f84051371cd -r ffde896496c119f8785519d9c6f8831b24847ad6 lib/galaxy/jobs/handler.py --- a/lib/galaxy/jobs/handler.py +++ b/lib/galaxy/jobs/handler.py @@ -94,7 +94,7 @@ | ( model.Job.state == model.Job.states.RUNNING ) \ | ( model.Job.state == model.Job.states.QUEUED ) ) \ & ( model.Job.handler == self.app.config.server_name ) \ - & or_( ( model.Job.user_id is None ),( model.User.active is True ) ) ).all() + & or_( ( model.Job.user_id == None ),( model.User.active == True ) ) ).all() else: jobs_at_startup = self.sa_session.query( model.Job ).enable_eagerloads( False ) \ .filter( ( ( model.Job.state == model.Job.states.NEW ) \ @@ -175,23 +175,23 @@ .join(model.Dataset) \ .filter(and_((model.Job.state == model.Job.states.NEW), or_((model.HistoryDatasetAssociation._state == model.HistoryDatasetAssociation.states.FAILED_METADATA), - (model.HistoryDatasetAssociation.deleted is True ), + (model.HistoryDatasetAssociation.deleted == True ), (model.Dataset.state != model.Dataset.states.OK ), - (model.Dataset.deleted is True)))).subquery() + (model.Dataset.deleted == True)))).subquery() ldda_not_ready = self.sa_session.query(model.Job.id).enable_eagerloads(False) \ .join(model.JobToInputLibraryDatasetAssociation) \ .join(model.LibraryDatasetDatasetAssociation) \ .join(model.Dataset) \ .filter(and_((model.Job.state == model.Job.states.NEW), or_((model.LibraryDatasetDatasetAssociation._state != None), - (model.LibraryDatasetDatasetAssociation.deleted is True), + (model.LibraryDatasetDatasetAssociation.deleted == True), (model.Dataset.state != model.Dataset.states.OK), - (model.Dataset.deleted is True)))).subquery() + (model.Dataset.deleted == True)))).subquery() if self.app.config.user_activation_on: jobs_to_check = self.sa_session.query(model.Job).enable_eagerloads(False) \ .outerjoin( model.User ) \ .filter(and_((model.Job.state == model.Job.states.NEW), - or_((model.Job.user_id is None),(model.User.active is True)), + or_((model.Job.user_id == None),(model.User.active == True)), (model.Job.handler == self.app.config.server_name), ~model.Job.table.c.id.in_(hda_not_ready), ~model.Job.table.c.id.in_(ldda_not_ready))) \ https://bitbucket.org/galaxy/galaxy-central/commits/397de5e98f7a/ Changeset: 397de5e98f7a User: martenson Date: 2013-09-23 21:00:18 Summary: Merged galaxy/galaxy-central into default Affected #: 2 files diff -r ffde896496c119f8785519d9c6f8831b24847ad6 -r 397de5e98f7a828aaf78068c348c5633de352a4f templates/user/register.mako --- a/templates/user/register.mako +++ b/templates/user/register.mako @@ -107,6 +107,9 @@ <input type="submit" name="create_user_button" value="Submit"/></div></form> + <div class="alert alert-danger" style="margin: 30px 12px 12px 12px;"> + Please register only one account - we provide this service free of charge and have limited computational resources. Multi-accounts are tracked and will be subjected to account termination and data deletion. + </div></div></%def> https://bitbucket.org/galaxy/galaxy-central/commits/edf026397ac0/ Changeset: edf026397ac0 User: martenson Date: 2013-09-24 16:31:56 Summary: Merged galaxy/galaxy-central into default Affected #: 36 files diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 dist-eggs.ini --- a/dist-eggs.ini +++ b/dist-eggs.ini @@ -1,88 +1,54 @@ ; ; Config for building eggs for distribution (via a site such as -; eggs.g2.bx.psu.edu). Probably only useful to Galaxy developers at -; Penn State. This file is used by scripts/dist-scramble.py +; eggs.galaxyproject.org). Probably only useful to members of the Galaxy Team +; building eggs for distribution. This file is used by +; scripts/dist-scramble.py ; -; More information: http://wiki.g2.bx.psu.edu/Admin/Config/Eggs +; More information: http://wiki.galaxyproject.org/Admin/Config/Eggs ; [hosts] -py2.5-linux-i686-ucs2 = stegmaier.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-i686-ucs2/bin/python2.5 -py2.5-linux-i686-ucs4 = stegmaier.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-i686-ucs4/bin/python2.5 py2.6-linux-i686-ucs2 = stegmaier.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-i686-ucs2/bin/python2.6 py2.6-linux-i686-ucs4 = stegmaier.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-i686-ucs4/bin/python2.6 py2.7-linux-i686-ucs2 = stegmaier.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-i686-ucs2/bin/python2.7 py2.7-linux-i686-ucs4 = stegmaier.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-i686-ucs4/bin/python2.7 -py2.5-linux-x86_64-ucs2 = straub.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-x86_64-ucs2/bin/python2.5 -py2.5-linux-x86_64-ucs4 = straub.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-x86_64-ucs4/bin/python2.5 py2.6-linux-x86_64-ucs2 = straub.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-x86_64-ucs2/bin/python2.6 py2.6-linux-x86_64-ucs4 = straub.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-x86_64-ucs4/bin/python2.6 py2.7-linux-x86_64-ucs2 = straub.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-x86_64-ucs2/bin/python2.7 py2.7-linux-x86_64-ucs4 = straub.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-x86_64-ucs4/bin/python2.7 -py2.5-macosx-10.3-fat-ucs2 = weyerbacher.bx.psu.edu /Library/Frameworks/Python.framework/Versions/2.5/bin/python2.5 py2.6-macosx-10.3-fat-ucs2 = weyerbacher.bx.psu.edu /Library/Frameworks/Python.framework/Versions/2.6/bin/python2.6 py2.7-macosx-10.3-fat-ucs2 = weyerbacher.bx.psu.edu /Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 py2.6-macosx-10.6-universal-ucs2 = lion.bx.psu.edu /usr/bin/python2.6 py2.7-macosx-10.6-intel-ucs2 = lion.bx.psu.edu /usr/local/bin/python2.7 -py2.5-solaris-2.10-i86pc_32-ucs2 = thumper.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.10-i86pc_32-ucs2/bin/python2.5 -py2.6-solaris-2.10-i86pc_32-ucs2 = thumper.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.10-i86pc_32-ucs2/bin/python2.6 -py2.7-solaris-2.10-i86pc_32-ucs2 = thumper.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.10-i86pc_32-ucs2/bin/python2.7 -py2.5-solaris-2.10-i86pc_64-ucs2 = thumper.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.10-i86pc_64-ucs2/bin/python2.5 -py2.6-solaris-2.10-i86pc_64-ucs2 = thumper.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.10-i86pc_64-ucs2/bin/python2.6 -py2.7-solaris-2.10-i86pc_64-ucs2 = thumper.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.10-i86pc_64-ucs2/bin/python2.7 -py2.5-solaris-2.10-sun4u_32-ucs2 = early.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.8-sun4u_32-ucs2/bin/python2.5 -py2.6-solaris-2.10-sun4u_32-ucs2 = early.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.8-sun4u_32-ucs2/bin/python2.6 -py2.7-solaris-2.10-sun4u_32-ucs2 = early.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.8-sun4u_32-ucs2/bin/python2.7 -py2.5-solaris-2.10-sun4u_64-ucs2 = early.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.10-sun4u_64-ucs2/bin/python2.5 -py2.6-solaris-2.10-sun4u_64-ucs2 = early.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.10-sun4u_64-ucs2/bin/python2.6 -py2.7-solaris-2.10-sun4u_64-ucs2 = early.bx.psu.edu /afs/bx.psu.edu/project/pythons/solaris-2.10-sun4u_64-ucs2/bin/python2.7 - +; ; these hosts are used to build eggs with no C extensions -py2.5 = straub.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-x86_64-ucs4/bin/python2.5 py2.6 = straub.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-x86_64-ucs4/bin/python2.6 py2.7 = straub.bx.psu.edu /afs/bx.psu.edu/project/pythons/linux-x86_64-ucs4/bin/python2.7 [groups] -py2.5-linux-i686 = py2.5-linux-i686-ucs2 py2.5-linux-i686-ucs4 -py2.5-linux-x86_64 = py2.5-linux-x86_64-ucs2 py2.5-linux-x86_64-ucs4 py2.6-linux-i686 = py2.6-linux-i686-ucs2 py2.6-linux-i686-ucs4 py2.6-linux-x86_64 = py2.6-linux-x86_64-ucs2 py2.6-linux-x86_64-ucs4 py2.7-linux-i686 = py2.7-linux-i686-ucs2 py2.7-linux-i686-ucs4 py2.7-linux-x86_64 = py2.7-linux-x86_64-ucs2 py2.7-linux-x86_64-ucs4 -py2.5-linux = py2.5-linux-i686 py2.5-linux-x86_64 py2.6-linux = py2.6-linux-i686 py2.6-linux-x86_64 py2.7-linux = py2.7-linux-i686 py2.7-linux-x86_64 -linux-i686 = py2.5-linux-i686 py2.6-linux-i686 py2.7-linux-i686 -linux-x86_64 = py2.5-linux-x86_64 py2.6-linux-x86_64 py2.7-linux-x86_64 +linux-i686 = py2.6-linux-i686 py2.7-linux-i686 +linux-x86_64 = py2.6-linux-x86_64 py2.7-linux-x86_64 linux = linux-i686 linux-x86_64 -py2.5-macosx = py2.5-macosx-10.3-fat-ucs2 py2.6-macosx = py2.6-macosx-10.3-fat-ucs2 py2.6-macosx-10.6-universal-ucs2 py2.7-macosx = py2.7-macosx-10.3-fat-ucs2 py2.7-macosx-10.6-intel-ucs2 -macosx = py2.5-macosx py2.6-macosx py2.7-macosx -py2.5-solaris-i86pc = py2.5-solaris-2.10-i86pc_32-ucs2 py2.5-solaris-2.10-i86pc_64-ucs2 -py2.6-solaris-i86pc = py2.6-solaris-2.10-i86pc_32-ucs2 py2.6-solaris-2.10-i86pc_64-ucs2 -py2.7-solaris-i86pc = py2.7-solaris-2.10-i86pc_32-ucs2 py2.7-solaris-2.10-i86pc_64-ucs2 -py2.5-solaris-sun4u = py2.5-solaris-2.10-sun4u_32-ucs2 py2.5-solaris-2.10-sun4u_64-ucs2 -py2.6-solaris-sun4u = py2.6-solaris-2.10-sun4u_32-ucs2 py2.6-solaris-2.10-sun4u_64-ucs2 -py2.7-solaris-sun4u = py2.7-solaris-2.10-sun4u_32-ucs2 py2.7-solaris-2.10-sun4u_64-ucs2 -py2.5-solaris = py2.5-solaris-i86pc py2.5-solaris-sun4u -py2.6-solaris = py2.6-solaris-i86pc py2.6-solaris-sun4u -py2.7-solaris = py2.7-solaris-i86pc py2.7-solaris-sun4u -solaris-i86pc = py2.5-solaris-i86pc py2.6-solaris-i86pc py2.7-solaris-i86pc -solaris-sun4u = py2.5-solaris-sun4u py2.6-solaris-sun4u py2.7-solaris-sun4u -solaris = solaris-i86pc solaris-sun4u -py2.5-all = py2.5-linux py2.5-macosx py2.5-solaris -py2.6-all = py2.6-linux py2.6-macosx py2.6-solaris -py2.7-all = py2.7-linux py2.7-macosx py2.7-solaris +macosx = py2.6-macosx py2.7-macosx +py2.6-all = py2.6-linux py2.6-macosx +py2.7-all = py2.7-linux py2.7-macosx ; the 'all' key is used internally by the build system to specify which hosts ; to build on when no hosts are specified on the dist-eggs.py command line. -all = linux macosx solaris +all = linux macosx ; the 'noplatform' key, likewise, is for which build hosts should be used when ; building pure python (noplatform) eggs. -noplatform = py2.5 py2.6 py2.7 +noplatform = py2.6 py2.7 ; don't build these eggs on these platforms: [ignore] -ctypes = py2.5-linux-i686-ucs2 py2.5-linux-i686-ucs4 py2.6-linux-i686-ucs2 py2.6-linux-i686-ucs4 py2.7-linux-i686-ucs2 py2.7-linux-i686-ucs4 py2.5-linux-x86_64-ucs2 py2.5-linux-x86_64-ucs4 py2.6-linux-x86_64-ucs2 py2.6-linux-x86_64-ucs4 py2.7-linux-x86_64-ucs2 py2.7-linux-x86_64-ucs4 py2.5-macosx-10.3-fat-ucs2 py2.6-macosx-10.3-fat-ucs2 py2.6-macosx-10.6-universal-ucs2 py2.7-macosx-10.3-fat-ucs2 py2.5-solaris-2.10-i86pc_32-ucs2 py2.6-solaris-2.10-i86pc_32-ucs2 py2.7-solaris-2.10-i86pc_32-ucs2 py2.5-solaris-2.10-i86pc_64-ucs2 py2.6-solaris-2.10-i86pc_64-ucs2 py2.7-solaris-2.10-i86pc_64-ucs2 py2.5-solaris-2.10-sun4u_32-ucs2 py2.6-solaris-2.10-sun4u_32-ucs2 py2.7-solaris-2.10-sun4u_32-ucs2 py2.5-solaris-2.10-sun4u_64-ucs2 py2.6-solaris-2.10-sun4u_64-ucs2 py2.7-solaris-2.10-sun4u_64-ucs2 +;ctypes = diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 eggs.ini --- a/eggs.ini +++ b/eggs.ini @@ -21,7 +21,7 @@ PyRods = 3.2.4 numpy = 1.6.0 pbs_python = 4.3.5 -psycopg2 = 2.0.13 +psycopg2 = 2.5.1 pycrypto = 2.5 pysam = 0.4.2 pysqlite = 2.5.6 @@ -38,7 +38,7 @@ boto = 2.5.2 decorator = 3.1.2 docutils = 0.7 -drmaa = 0.4b3 +drmaa = 0.6 elementtree = 1.2.6_20050316 Fabric = 1.7.0 GeneTrack = 2.0.0_beta_1 @@ -72,7 +72,7 @@ ; extra version information [tags] -psycopg2 = _8.4.2_static +psycopg2 = _9.2.4_static pysqlite = _3.6.17_static MySQL_python = _5.1.41_static bx_python = _7b95ff194725 @@ -83,7 +83,7 @@ ; the wiki page above [source] MySQL_python = mysql-5.1.41 -psycopg2 = postgresql-8.4.2 +psycopg2 = postgresql-9.2.4 pysqlite = sqlite-amalgamation-3_6_17 [dependencies] diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 lib/tool_shed/galaxy_install/repository_util.py --- a/lib/tool_shed/galaxy_install/repository_util.py +++ b/lib/tool_shed/galaxy_install/repository_util.py @@ -100,19 +100,14 @@ continue # rd_key is something like: 'http://localhost:9009__ESEP__package_rdkit_2012_12__ESEP__test__ESEP__d635ff...' # rd_val is something like: [['http://localhost:9009', 'package_numpy_1_7', 'test', 'cddd64ecd985', 'True']] - try: - tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ - container_util.get_components_from_key( rd_key ) - except: - tool_shed, name, owner, changeset_revision = container_util.get_components_from_key( rd_val ) + repository_components_tuple = container_util.get_components_from_key( rd_key ) + components_list = suc.extract_components_from_tuple( repository_components_tuple ) + tool_shed, name, owner, changeset_revision = components_list[ 0:4 ] installed_repository = suc.get_tool_shed_repository_by_shed_name_owner_changeset_revision( trans.app, tool_shed, name, owner, changeset_revision ) if installed_repository not in installed_repositories: installed_repositories.append( installed_repository ) for rd_val in rd_vals: - try: - tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = rd_val - except: - tool_shed, name, owner, changeset_revision = rd_val + tool_shed, name, owner, changeset_revision = rd_val[ 0:4 ] installed_repository = suc.get_tool_shed_repository_by_shed_name_owner_changeset_revision( trans.app, tool_shed, name, owner, changeset_revision ) if installed_repository not in installed_repositories: installed_repositories.append( installed_repository ) @@ -631,13 +626,10 @@ # Change the folder id so it won't confict with others being merged. old_container_repository_dependencies_folder.id = folder_id folder_id += 1 + repository_components_tuple = container_util.get_components_from_key( old_container_repository_dependencies_folder.key ) + components_list = suc.extract_components_from_tuple( repository_components_tuple ) + name = components_list[ 1 ] # Generate the label by retrieving the repository name. - try: - toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ - container_util.get_components_from_key( old_container_repository_dependencies_folder.key ) - except ValueError: - # For backward compatibility to the 12/20/12 Galaxy release. - toolshed, name, owner, changeset_revision = container_util.get_components_from_key( old_container_repository_dependencies_folder.key ) old_container_repository_dependencies_folder.label = str( name ) repository_dependencies_folder.folders.append( old_container_repository_dependencies_folder ) # Merge tool_dependencies. diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 lib/tool_shed/util/common_install_util.py --- a/lib/tool_shed/util/common_install_util.py +++ b/lib/tool_shed/util/common_install_util.py @@ -352,19 +352,20 @@ for key, val in repository_dependencies.items(): if key in [ 'root_key', 'description' ]: continue - try: - toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ - container_util.get_components_from_key( key ) - components_list = [ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td ] - except ValueError: - # For backward compatibility to the 12/20/12 Galaxy release, default prior_installation_required and only_if_compiling_contained_td - # to False in the caller. - toolshed, name, owner, changeset_revision = container_util.get_components_from_key( key ) - components_list = [ toolshed, name, owner, changeset_revision ] - only_if_compiling_contained_td = 'False' + repository_components_tuple = container_util.get_components_from_key( key ) + components_list = suc.extract_components_from_tuple( repository_components_tuple ) # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since # in this case, the repository dependency is really a dependency of the dependent repository's contained tool dependency, and only if # that tool dependency requires compilation. + # For backward compatibility to the 12/20/12 Galaxy release. + prior_installation_required = 'False' + only_if_compiling_contained_td = 'False' + if len( components_list ) == 4: + prior_installation_required = 'False' + only_if_compiling_contained_td = 'False' + elif len( components_list ) == 5: + prior_installation_required = components_list[ 4 ] + only_if_compiling_contained_td = 'False' if not util.asbool( only_if_compiling_contained_td ): if components_list not in required_repository_tups: required_repository_tups.append( components_list ) diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 lib/tool_shed/util/container_util.py --- a/lib/tool_shed/util/container_util.py +++ b/lib/tool_shed/util/container_util.py @@ -855,7 +855,7 @@ folder_id, data_managers_root_folder = build_invalid_data_managers_folder( trans, folder_id, data_managers, error_messages, label="Invalid Data Managers" ) containers_dict[ 'invalid_data_managers' ] = data_managers_root_folder except Exception, e: - log.debug( "Exception in build_repository_containers_for_tool_shed: %s" % str( e ) ) + log.exception( "Exception in build_repository_containers_for_tool_shed: %s" % str( e ) ) finally: lock.release() return containers_dict @@ -1325,29 +1325,31 @@ repository_name = items[ 1 ] repository_owner = items[ 2 ] changeset_revision = items[ 3 ] - if len( items ) >= 5: - try: - prior_installation_required = items[ 4 ] - except: - prior_installation_required = 'False' - try: - only_if_compiling_contained_td = items[ 5 ] - except: - only_if_compiling_contained_td = 'False' + if len( items ) == 5: + prior_installation_required = items[ 4 ] + return toolshed_base_url, repository_name, repository_owner, changeset_revision, prior_installation_required + elif len( items ) == 6: + prior_installation_required = items[ 4 ] + only_if_compiling_contained_td = items[ 5 ] return toolshed_base_url, repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td else: # For backward compatibility to the 12/20/12 Galaxy release we have to return the following, and callers must handle exceptions. return toolshed_base_url, repository_name, repository_owner, changeset_revision def handle_repository_dependencies_container_entry( trans, repository_dependencies_folder, rd_key, rd_value, folder_id, repository_dependency_id, folder_keys ): - try: - toolshed, repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ - get_components_from_key( rd_key ) - except ValueError: - # For backward compatibility to the 12/20/12 Galaxy release, default prior_installation_required and only_if_compiling_contained_td to 'False'. - toolshed, repository_name, repository_owner, changeset_revision = get_components_from_key( rd_key ) + repository_components_tuple = get_components_from_key( rd_key ) + components_list = suc.extract_components_from_tuple( repository_components_tuple ) + toolshed, repository_name, repository_owner, changeset_revision = components_list[ 0:4 ] + # For backward compatibility to the 12/20/12 Galaxy release. + if len( components_list ) == 4: prior_installation_required = 'False' only_if_compiling_contained_td = 'False' + elif len( components_list ) == 5: + prior_installation_required = components_list[ 4 ] + only_if_compiling_contained_td = 'False' + elif len( components_list ) == 6: + prior_installation_required = components_list[ 4 ] + only_if_compiling_contained_td = components_list[ 5 ] folder = get_folder( repository_dependencies_folder, rd_key ) label = generate_repository_dependencies_folder_label_from_key( repository_name, repository_owner, @@ -1416,14 +1418,19 @@ return False def key_is_current_repositorys_key( repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, key ): - try: - toolshed_base_url, key_name, key_owner, key_changeset_revision, key_prior_installation_required, key_only_if_compiling_contained_td = \ - get_components_from_key( key ) - except ValueError: - # For backward compatibility to the 12/20/12 Galaxy release, default key_prior_installation_required to False. - toolshed_base_url, key_name, key_owner, key_changeset_revision = get_components_from_key( key ) + repository_components_tuple = get_components_from_key( key ) + components_list = suc.extract_components_from_tuple( repository_components_tuple ) + toolshed, key_name, key_owner, key_changeset_revision = components_list[ 0:4 ] + # For backward compatibility to the 12/20/12 Galaxy release. + if len( components_list ) == 4: key_prior_installation_required = 'False' key_only_if_compiling_contained_td = 'False' + elif len( components_list ) == 5: + key_prior_installation_required = components_list[ 4 ] + key_only_if_compiling_contained_td = 'False' + elif len( components_list ) == 6: + key_prior_installation_required = components_list[ 4 ] + key_only_if_compiling_contained_td = components_list[ 5 ] if repository_name == key_name and \ repository_owner == key_owner and \ changeset_revision == key_changeset_revision and \ diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 lib/tool_shed/util/repository_dependency_util.py --- a/lib/tool_shed/util/repository_dependency_util.py +++ b/lib/tool_shed/util/repository_dependency_util.py @@ -36,12 +36,9 @@ if key in [ 'root_key', 'description' ]: continue d_repository = None - try: - d_toolshed, d_name, d_owner, d_changeset_revision, d_prior_installation_required, d_only_if_compiling_contained_td = \ - container_util.get_components_from_key( key ) - except ValueError: - # For backward compatibility to the 12/20/12 Galaxy release. - d_toolshed, d_name, d_owner, d_changeset_revision = container_util.get_components_from_key( key ) + repository_components_tuple = container_util.get_components_from_key( key ) + components_list = suc.extract_components_from_tuple( repository_components_tuple ) + d_toolshed, d_name, d_owner, d_changeset_revision = components_list[ 0:4 ] for tsr in tool_shed_repositories: # Get the the tool_shed_repository defined by name, owner and changeset_revision. This is the repository that will be # dependent upon each of the tool shed repositories contained in val. We'll need to check tool_shed_repository.tool_shed @@ -437,22 +434,22 @@ # We have the updated changset revision. updated_key_rd_dicts.append( new_key_rd_dict ) else: - try: - toolshed, repository_name, repository_owner, repository_changeset_revision, prior_installation_required, rd_only_if_compiling_contained_td = \ - container_util.get_components_from_key( key ) - except ValueError: - # For backward compatibility to the 12/20/12 Galaxy release. - toolshed, repository_name, repository_owner, repository_changeset_revision = container_util.get_components_from_key( key ) + repository_components_tuple = container_util.get_components_from_key( key ) + components_list = suc.extract_components_from_tuple( repository_components_tuple ) + toolshed, repository_name, repository_owner, repository_changeset_revision = components_list[ 0:4 ] + # For backward compatibility to the 12/20/12 Galaxy release. + if len( components_list ) == 4: + prior_installation_required = 'False' + rd_only_if_compiling_contained_td = 'False' + elif len( components_list ) == 5: + rd_only_if_compiling_contained_td = 'False' message = "The revision %s defined for repository %s owned by %s is invalid, so repository dependencies defined for repository %s will be ignored." % \ ( str( rd_changeset_revision ), str( rd_name ), str( rd_owner ), str( repository_name ) ) log.debug( message ) else: - try: - toolshed, repository_name, repository_owner, repository_changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ - container_util.get_components_from_key( key ) - except ValueError: - # For backward compatibility to the 12/20/12 Galaxy release. - toolshed, repository_name, repository_owner, repository_changeset_revision = container_util.get_components_from_key( key ) + repository_components_tuple = container_util.get_components_from_key( key ) + components_list = suc.extract_components_from_tuple( repository_components_tuple ) + toolshed, repository_name, repository_owner, repository_changeset_revision = components_list[ 0:4 ] message = "The revision %s defined for repository %s owned by %s is invalid, so repository dependencies defined for repository %s will be ignored." % \ ( str( rd_changeset_revision ), str( rd_name ), str( rd_owner ), str( repository_name ) ) log.debug( message ) diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 lib/tool_shed/util/shed_util_common.py --- a/lib/tool_shed/util/shed_util_common.py +++ b/lib/tool_shed/util/shed_util_common.py @@ -307,6 +307,21 @@ sa_session.flush() return tool_shed_repository +def extract_components_from_tuple( repository_components_tuple ): + '''Extract the repository components from the provided tuple in a backward-compatible manner.''' + toolshed = repository_components_tuple[ 0 ] + name = repository_components_tuple[ 1 ] + owner = repository_components_tuple[ 2 ] + changeset_revision = repository_components_tuple[ 3 ] + components_list = [ toolshed, name, owner, changeset_revision ] + if len( repository_components_tuple ) == 5: + toolshed, name, owner, changeset_revision, prior_installation_required = repository_components_tuple + components_list = [ toolshed, name, owner, changeset_revision, prior_installation_required ] + elif len( repository_components_tuple ) == 6: + toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = repository_components_tuple + components_list = [ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td ] + return components_list + def generate_clone_url_for_installed_repository( app, repository ): """Generate the URL for cloning a repository that has been installed into a Galaxy instance.""" tool_shed_url = get_url_from_tool_shed( app, repository.tool_shed ) diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/galaxy.upload.js --- a/static/scripts/galaxy.upload.js +++ b/static/scripts/galaxy.upload.js @@ -17,6 +17,34 @@ // upload mod uploadbox: null, + // extension types + select_extension : { + '' : 'Auto-detect', + 'bed' : 'bed', + 'ab1' : 'ab1' + }, + + // states + state : { + init : 'fa-icon-trash', + done : 'fa-icon-caret-down' + }, + + // counter + counter : { + // stats + announce : 0, + success : 0, + error : 0, + running : 0, + + // reset stats + reset : function() + { + this.announce = this.success = this.error = this.running = 0; + } + }, + // initialize initialize : function() { @@ -58,21 +86,18 @@ event_mouseleave : function (e) { }, - + // start event_announce : function(index, file, message) { - // hide info - this.uploadbox.info().hide(); - // make id var id = '#upload-' + index; - + // add upload item - $(this.el).append(this.template_file(id)); + $(this.el).append(this.template_file(id, this.select_extension)); // scroll to bottom - $(this.el).scrollTop($(this.el).prop('scrollHeight')); + //$(this.el).scrollTop($(this.el).prop('scrollHeight')); // access upload item var it = this.get_upload_item(index); @@ -84,59 +109,27 @@ it.find('.title').html(file.name); // configure select field - it.find('#extension').select2( - { - placeholder: 'Auto-detect', - width: 'copy', - ajax: { - url: "http://www.weighttraining.com/sm/search", - dataType: 'jsonp', - quietMillis: 100, - data: function(term, page) - { - return { - types: ["exercise"], - limit: -1, - term: term - }; - }, - results: function(data, page) - { - return { results: data.results.exercise } - } - }, - formatResult: function(exercise) - { - return "<div class='select2-user-result'>" + exercise.term + "</div>"; - }, - formatSelection: function(exercise) - { - return exercise.term; - }, - initSelection : function (element, callback) - { - var elementText = $(element).attr('data-init-text'); - callback({"term":elementText}); - } - }); + //it.find('#extension').select2(); // add functionality to remove button var self = this; - it.find('.remove').on('click', function() { self.event_remove (index) }); + it.find('.symbol').on('click', function() { self.event_remove (index) }); // initialize progress this.event_progress(index, file, 0); - // update button status - this.modal.enable('Upload'); - this.modal.enable('Reset'); + // update counter + this.counter.announce++; + + // update screen + this.update_screen(); }, // start event_initialize : function(index, file, message) { // update on screen counter - this.button_show.number(message); + this.button_show.number(this.counter.announce); // get element var it = this.get_upload_item(index); @@ -168,16 +161,9 @@ it.find('.info').html(percentage + '% of ' + this.size_to_string (file.size)); }, - // end + // success event_success : function(index, file, message) - { - // get element - var it = this.get_upload_item(index); - - // update progress frame - it.addClass('panel-success'); - it.removeClass('panel-default'); - + { // update galaxy history Galaxy.currHistoryPanel.refresh(); @@ -186,11 +172,46 @@ // update on screen counter this.button_show.number(''); + + // update counter + this.counter.announce--; + this.counter.success++; + + // update on screen info + this.update_screen(); + + // get element + var it = this.get_upload_item(index); + + // update progress frame + it.addClass('panel-success'); + it.removeClass('panel-default'); + + // update icon + var sy = it.find('.symbol'); + sy.removeClass('fa-icon-spin'); + sy.removeClass('fa-icon-spinner'); + + // set status + sy.addClass(this.state.done); }, - // end + // error event_error : function(index, file, message) { + // make sure progress is shown correctly + this.event_progress(index, file, 0); + + // update on screen counter + this.button_show.number(''); + + // update counter + this.counter.announce--; + this.counter.error++; + + // update on screen info + this.update_screen(); + // get element var it = this.get_upload_item(index); @@ -204,29 +225,41 @@ // write error message it.find('.error').html('<strong>Failed:</strong> ' + message); - // make sure progress is shown correctly - this.event_progress(index, file, 0); + // update icon + var sy = it.find('.symbol'); + sy.removeClass('fa-icon-spin'); + sy.removeClass('fa-icon-spinner'); - // update on screen counter - this.button_show.number(''); + // set status + sy.addClass(this.state.done); }, // start upload process event_upload : function() { + // check + if (this.counter.announce == 0 || this.counter.running > 0) + return; + + // switch icons for new uploads + var self = this; + $(this.el).find('.symbol').each(function() + { + if($(this).hasClass(self.state.init)) + { + $(this).removeClass(self.state.init); + $(this).addClass('fa-icon-spinner'); + $(this).addClass('fa-icon-spin'); + } + }); + // hide configuration $(this.el).find('.panel-body').hide(); - // switch icon - $(this.el).find('.remove').each(function() - { - $(this).removeClass('fa-icon-trash'); - $(this).addClass('fa-icon-caret-down'); - }); - - // update button status - this.modal.disable('Upload'); - + // update running + this.counter.running = this.counter.announce; + this.update_screen(); + // configure url var current_history = Galaxy.currHistoryPanel.model.get('id'); this.uploadbox.configure({url : galaxy_config.root + "api/histories/" + current_history + "/contents"}); @@ -235,62 +268,62 @@ this.uploadbox.upload(); }, + // queue is done + event_complete: function() + { + // update running + this.counter.running = 0; + this.update_screen(); + }, + // remove all event_reset : function() { - // remove from screen - var panels = $(this.el).find('.panel'); - var self = this; - panels.fadeOut({complete: function() + // make sure queue is not running + if (this.counter.running == 0) { - // remove panels - panels.remove(); - + // remove from screen + var panels = $(this.el).find('.panel'); + panels.fadeOut({complete: function() { panels.remove(); }}); + + // reset counter + this.counter.reset(); + // show on screen info - self.uploadbox.info().fadeIn(); - }}); - - // update button status - this.modal.disable('Upload'); - this.modal.disable('Reset'); - - // remove from queue - this.uploadbox.reset(); + this.update_screen(); + + // remove from queue + this.uploadbox.reset(); + } }, // remove item from upload list event_remove : function(index) { - // remove - var self = this; + // get item var it = this.get_upload_item(index); - - // fade out and update button status - it.fadeOut({complete: function() + var sy = it.find('.symbol'); + + // only remove from queue if not in processing line + if (sy.hasClass(this.state.init) || sy.hasClass(this.state.done)) { - // remove from screen + // reduce counter + if (it.hasClass('panel-default')) + this.counter.announce--; + else if (it.hasClass('panel-success')) + this.counter.success--; + else if (it.hasClass('panel-danger')) + this.counter.error--; + + // show on screen info + this.update_screen(); + + // remove from queue + this.uploadbox.remove(index); + + // remove element it.remove(); - - // remove from queue - self.uploadbox.remove(index); - - // update reset button - if ($(self.el).find('.panel').length > 0) - self.modal.enable('Reset'); - else { - // disable reset button - self.modal.disable('Reset'); - - // show on screen info - self.uploadbox.info().fadeIn(); - } - - // update upload button - if (self.uploadbox.length() > 0) - self.modal.enable('Upload'); - else - self.modal.disable('Upload'); - }}); + } }, // show/hide upload frame @@ -330,11 +363,11 @@ success : function(index, file, message) { self.event_success(index, file, message) }, progress : function(index, file, message) { self.event_progress(index, file, message) }, error : function(index, file, message) { self.event_error(index, file, message) }, + complete : function() { self.event_complete() }, }); - // update button status - this.modal.disable('Upload'); - this.modal.disable('Reset'); + // setup info + this.update_screen(); } // show modal @@ -362,34 +395,93 @@ return "<strong>" + (Math.round(size) / 10) + "</strong> " + unit; }, + // set screen + update_screen: function () + { + /* + update on screen info + */ + + // check default message + if(this.counter.announce == 0) + { + if (this.uploadbox.compatible) + message = 'Drag&drop files into this box or click \'Select\' to select files!'; + else + message = 'Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+.' + } else { + if (this.counter.running == 0) + message = 'You added ' + this.counter.announce + ' file(s) to the queue. Add more files or click "Upload" to proceed.'; + else + message = 'Please wait...' + this.counter.announce + ' out of ' + this.counter.running + ' remaining.'; + } + + // set html content + $('#upload-info').html(message); + + /* + update button status + */ + + // update reset button + if (this.counter.running == 0 && this.counter.announce + this.counter.success + this.counter.error > 0) + this.modal.enable('Reset'); + else + this.modal.disable('Reset'); + + // update upload button + if (this.counter.running == 0 && this.counter.announce > 0) + this.modal.enable('Upload'); + else + this.modal.disable('Upload'); + + // select upload button + if (this.counter.running == 0) + this.modal.enable('Select'); + else + this.modal.disable('Select'); + }, + // load html template template: function(id) { - return '<div id="' + id + '" class="upload-box"></div>'; + return '<div id="' + id + '" class="upload-box"></div><h6 id="upload-info" class="upload-info"></h6>'; }, // load html template - template_file: function(id) + template_file: function(id, select_extension) { - return '<div id="' + id.substr(1) + '" class="panel panel-default">' + - '<div class="panel-heading">' + - '<h5 class="title"></h5>' + - '<h5 class="info"></h5>' + - '<div class="remove fa-icon-trash"></div>' + - '</div>' + - '<div class="panel-body">' + - '<div class="menu">' + - //'<input id="extension" type="hidden" width="10px"/> ' + - '<span><input id="space_to_tabs" type="checkbox">Convert spaces to tabs</input></span>' + + // start template + var tmpl = '<div id="' + id.substr(1) + '" class="panel panel-default">' + + '<div class="panel-heading">' + + '<h5 class="title"></h5>' + + '<h5 class="info"></h5>' + + '<div class="symbol ' + this.state.init + '"></div>' + '</div>' + - '</div>' + - '<div class="panel-footer">' + - '<div class="progress">' + - '<div class="progress-bar progress-bar-success"></div>' + + '<div class="panel-body">' + + '<div class="menu">' + + 'Select file type: ' + + '<select id="extension">'; + + // add file types to selection + for (key in select_extension) + tmpl += '<option value="' + key + '">' + select_extension[key] + '</option>'; + + // continue template + tmpl += '</select>, ' + + '<span>Convert space to tabs: <input id="space_to_tabs" type="checkbox"></input></span>' + + '</div>' + '</div>' + - '<h6 class="error"></h6>' + - '</div>' + - '</div>'; + '<div class="panel-footer">' + + '<div class="progress">' + + '<div class="progress-bar progress-bar-success"></div>' + + '</div>' + + '<h6 class="error"></h6>' + + '</div>' + + '</div>'; + + // return html string + return tmpl; } }); diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/libs/jquery/select2.js --- a/static/scripts/libs/jquery/select2.js +++ b/static/scripts/libs/jquery/select2.js @@ -1,7 +1,7 @@ /* Copyright 2012 Igor Vaynberg -Version: 3.4.2 Timestamp: Mon Aug 12 15:04:12 PDT 2013 +Version: 3.4.3 Timestamp: Tue Sep 17 06:47:14 PDT 2013 This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU General Public License version 2 (the "GPL License"). You may choose either license to govern your @@ -688,14 +688,18 @@ this.opts.element .data("select2", this) .attr("tabindex", "-1") - .before(this.container); + .before(this.container) + .on("click.select2", killEvent); // do not leak click events + this.container.data("select2", this); this.dropdown = this.container.find(".select2-drop"); + + syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); + this.dropdown.addClass(evaluate(opts.dropdownCssClass)); this.dropdown.data("select2", this); - - syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); + this.dropdown.on("click", killEvent); this.results = results = this.container.find(resultsSelector); this.search = search = this.container.find("input.select2-input"); @@ -707,6 +711,8 @@ // initialize the container this.initContainer(); + this.container.on("click", killEvent); + installFilteredMouseMove(this.results); this.dropdown.on("mousemove-filtered touchstart touchmove touchend", resultsSelector, this.bind(this.highlightUnderEvent)); @@ -968,10 +974,11 @@ opts.initSelection = function (element, callback) { var data = []; $(splitVal(element.val(), opts.separator)).each(function () { - var id = this, text = this, tags=opts.tags; + var obj = { id: this, text: this }, + tags = opts.tags; if ($.isFunction(tags)) tags=tags(); - $(tags).each(function() { if (equal(this.id, id)) { text = this.text; return false; } }); - data.push({id: id, text: text}); + $(tags).each(function() { if (equal(this.id, obj.id)) { obj = this; return false; } }); + data.push(obj); }); callback(data); @@ -1320,7 +1327,7 @@ $("#select2-drop-mask").hide(); this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id this.dropdown.hide(); - this.container.removeClass("select2-dropdown-open"); + this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"); this.results.empty(); @@ -1395,7 +1402,7 @@ // abstract findHighlightableChoices: function() { - return this.results.find(".select2-result-selectable:not(.select2-selected):not(.select2-disabled)"); + return this.results.find(".select2-result-selectable:not(.select2-disabled)"); }, // abstract @@ -1926,10 +1933,7 @@ killEvent(e); return; case KEY.TAB: - // if selectOnBlur == true, select the currently highlighted option - if (this.opts.selectOnBlur) { - this.selectHighlighted({noFocus: true}); - } + this.selectHighlighted({noFocus: true}); return; case KEY.ESC: this.cancel(e); @@ -2046,6 +2050,11 @@ clear: function(triggerChange) { var data=this.selection.data("select2-data"); if (data) { // guard against queued quick consecutive clicks + var evt = $.Event("select2-clearing"); + this.opts.element.trigger(evt); + if (evt.isDefaultPrevented()) { + return; + } var placeholderOption = this.getPlaceholderOption(); this.opts.element.val(placeholderOption ? placeholderOption.val() : ""); this.selection.find(".select2-chosen").empty(); @@ -2083,7 +2092,7 @@ isPlaceholderOptionSelected: function() { var placeholderOption; - if (!this.opts.placeholder) return false; // no placeholder specified so no option should be considered + if (!this.getPlaceholder()) return false; // no placeholder specified so no option should be considered return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.is(':selected')) || (this.opts.element.val() === "") || (this.opts.element.val() === undefined) @@ -2216,7 +2225,7 @@ this.close(); if (!options || !options.noFocus) - this.selection.focus(); + this.focusser.focus(); if (!equal(old, this.id(data))) { this.triggerChange({added:data,removed:oldData}); } }, @@ -2442,7 +2451,7 @@ this.selection = selection = this.container.find(selector); var _this = this; - this.selection.on("click", ".select2-search-choice", function (e) { + this.selection.on("click", ".select2-search-choice:not(.select2-locked)", function (e) { //killEvent(e); _this.search[0].focus(); _this.selectChoice($(this)); @@ -2521,10 +2530,7 @@ killEvent(e); return; case KEY.TAB: - // if selectOnBlur == true, select the currently highlighted option - if (this.opts.selectOnBlur) { - this.selectHighlighted({noFocus:true}); - } + this.selectHighlighted({noFocus:true}); this.close(); return; case KEY.ESC: @@ -2842,9 +2848,7 @@ return; } - index = indexOf(this.id(data), val); - - if (index >= 0) { + while((index = indexOf(this.id(data), val)) >= 0) { val.splice(index, 1); this.setVal(val); if (this.select) this.postprocessResults(); @@ -2925,7 +2929,7 @@ searchWidth = minimumWidth; } - this.search.width(searchWidth); + this.search.width(Math.floor(searchWidth)); }, // multi diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/mvc/dataset/hda-base.js --- a/static/scripts/mvc/dataset/hda-base.js +++ b/static/scripts/mvc/dataset/hda-base.js @@ -82,6 +82,10 @@ this.$el.attr( 'id', 'historyItemContainer-' + id ); + //HACK: hover exit doesn't seem to be called on prev. tooltips when RE-rendering - so: no tooltip hide + // handle that here by removing previous view's tooltips + this.$el.find("[title]").tooltip( "destroy" ); + /** web controller urls for functions relating to this hda. * These are rendered from urlTemplates using the model data. */ this.urls = this._renderUrls( this.urlTemplates, this.model.toJSON() ); @@ -247,7 +251,7 @@ var self = this; displayBtnData.on_click = function(){ Galaxy.frame_manager.frame_new({ - title : "Data Viewer", + title : "Data Viewer: " + self.model.get('name'), type : "url", location: "center", content : self.urls.display diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/mvc/dataset/hda-edit.js --- a/static/scripts/mvc/dataset/hda-edit.js +++ b/static/scripts/mvc/dataset/hda-edit.js @@ -166,6 +166,7 @@ success: function() { // FIXME: setting model attribute causes re-rendering, which is unnecessary. //self.$el.remove(); + self.model.set({ deleted: true }); } }); diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/packed/galaxy.base.js --- a/static/scripts/packed/galaxy.base.js +++ b/static/scripts/packed/galaxy.base.js @@ -1,1 +1,1 @@ -(function(){var b=0;var c=["ms","moz","webkit","o"];for(var a=0;a<c.length&&!window.requestAnimationFrame;++a){window.requestAnimationFrame=window[c[a]+"RequestAnimationFrame"];window.cancelRequestAnimationFrame=window[c[a]+"CancelRequestAnimationFrame"]}if(!window.requestAnimationFrame){window.requestAnimationFrame=function(h,e){var d=new Date().getTime();var f=Math.max(0,16-(d-b));var g=window.setTimeout(function(){h(d+f)},f);b=d+f;return g}}if(!window.cancelAnimationFrame){window.cancelAnimationFrame=function(d){clearTimeout(d)}}}());if(!Array.indexOf){Array.prototype.indexOf=function(c){for(var b=0,a=this.length;b<a;b++){if(this[b]==c){return b}}return -1}}function obj_length(c){if(c.length!==undefined){return c.length}var b=0;for(var a in c){b++}return b}$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function make_popupmenu(b,c){var a=(b.data("menu_options"));b.data("menu_options",c);if(a){return}b.bind("click.show_popup",function(d){$(".popmenu-wrapper").remove();setTimeout(function(){var g=$("<ul class='dropdown-menu' id='"+b.attr("id")+"-menu'></ul>");var f=b.data("menu_options");if(obj_length(f)<=0){$("<li>No Options.</li>").appendTo(g)}$.each(f,function(j,i){if(i){g.append($("<li></li>").append($("<a href='#'></a>").html(j).click(i)))}else{g.append($("<li></li>").addClass("head").append($("<a href='#'></a>").html(j)))}});var h=$("<div class='popmenu-wrapper' style='position: absolute;left: 0; top: -1000;'></div>").append(g).appendTo("body");var e=d.pageX-h.width()/2;e=Math.min(e,$(document).scrollLeft()+$(window).width()-$(h).width()-5);e=Math.max(e,$(document).scrollLeft()+5);h.css({top:d.pageY,left:e})},10);setTimeout(function(){var f=function(h){$(h).bind("click.close_popup",function(){$(".popmenu-wrapper").remove();h.unbind("click.close_popup")})};f($(window.document));f($(window.top.document));for(var e=window.top.frames.length;e--;){var g=$(window.top.frames[e].document);f(g)}},50);return false})}function make_popup_menus(a){a=a||document;$(a).find("div[popupmenu]").each(function(){var b={};var d=$(this);d.find("a").each(function(){var g=$(this),i=g.get(0),e=i.getAttribute("confirm"),f=i.getAttribute("href"),h=i.getAttribute("target");if(!f){b[g.text()]=null}else{b[g.text()]=function(){if(!e||confirm(e)){var k;if(h==="_parent"){window.parent.location=f}else{if(h==="_top"){window.top.location=f}else{if(h==="demo"){if(k===undefined||k.closed){k=window.open(f,h);k.creator=self}}else{var j=["galaxy_main"];if((h&&(h in window)&&(j.indexOf(h)!==-1))){window[h].location=f}else{window.location=f}}}}}}}});var c=$(a).find("#"+d.attr("popupmenu"));c.find("a").bind("click",function(f){f.stopPropagation();return true});make_popupmenu(c,b);c.addClass("popup");d.remove()})}function naturalSort(j,h){var p=/(-?[0-9\.]+)/g,k=j.toString().toLowerCase()||"",g=h.toString().toLowerCase()||"",l=String.fromCharCode(0),n=k.replace(p,l+"$1"+l).split(l),e=g.replace(p,l+"$1"+l).split(l),d=(new Date(k)).getTime(),o=d?(new Date(g)).getTime():null;if(o){if(d<o){return -1}else{if(d>o){return 1}}}var m,f;for(var i=0,c=Math.max(n.length,e.length);i<c;i++){m=parseFloat(n[i])||n[i];f=parseFloat(e[i])||e[i];if(m<f){return -1}else{if(m>f){return 1}}}return 0}$.fn.refresh_select2=function(){var b=$(this);var a={width:"resolve",closeOnSelect:!b.is("[MULTIPLE]")};return b.select2(a)};function replace_big_select_inputs(a,c,b){if(!jQuery.fn.select2){return}if(a===undefined){a=20}if(c===undefined){c=3000}b=b||$("select");b.each(function(){var e=$(this);var d=e.find("option").length;if((d<a)||(d>c)){return}if(e.hasClass("no-autocomplete")){return}e.refresh_select2()})}$.fn.make_text_editable=function(g){var d=("num_cols" in g?g.num_cols:30),c=("num_rows" in g?g.num_rows:4),e=("use_textarea" in g?g.use_textarea:false),b=("on_finish" in g?g.on_finish:null),f=("help_text" in g?g.help_text:null);var a=$(this);a.addClass("editable-text").click(function(l){if($(this).children(":input").length>0){return}a.removeClass("editable-text");var i=function(m){a.find(":input").remove();if(m!==""){a.text(m)}else{a.html("<br>")}a.addClass("editable-text");if(b){b(m)}};var h=a.text(),k,j;if(e){k=$("<textarea/>").attr({rows:c,cols:d}).text($.trim(h)).keyup(function(m){if(m.keyCode===27){i(h)}});j=$("<button/>").text("Done").click(function(){i(k.val());return false})}else{k=$("<input type='text'/>").attr({value:$.trim(h),size:d}).blur(function(){i(h)}).keyup(function(m){if(m.keyCode===27){$(this).trigger("blur")}else{if(m.keyCode===13){i($(this).val())}}})}a.text("");a.append(k);if(j){a.append(j)}k.focus();k.select();l.stopPropagation()});if(f){a.attr("title",f).tooltip()}return a};function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).click(function(){if($("#renaming-active").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text($.trim(k))}else{j=$("<input type='text'></input>").attr({value:$.trim(k),size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){if(o!==""){l.text(o)}else{l.html("<em>None</em>")}if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(d,a,c){var b=function(){try{var e=$.jStorage.get("history_expand_state");if(e){for(var g in e){$("#"+g+" div.historyItemBody").show()}}}catch(f){$.jStorage.deleteKey("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}d.each(function(){var j=this.id,h=$(this).children("div.historyItemBody"),i=h.find("pre.peek");$(this).find(".historyItemTitleBar > .historyItemTitle").wrap("<a href='javascript:void(0);'></a>").click(function(){var k;if(h.is(":visible")){if($.browser.mozilla){i.css("overflow","hidden")}h.slideUp("fast");if(!c){k=$.jStorage.get("history_expand_state");if(k){delete k[j];$.jStorage.set("history_expand_state",k)}}}else{h.slideDown("fast",function(){if($.browser.mozilla){i.css("overflow","auto")}});if(!c){k=$.jStorage.get("history_expand_state");if(!k){k={}}k[j]=true;$.jStorage.set("history_expand_state",k)}}return false})});$("#top-links > a.toggle").click(function(){var h=$.jStorage.get("history_expand_state");if(!h){h={}}$("div.historyItemBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(h){delete h[$(this).parent().attr("id")]}});$.jStorage.set("history_expand_state",h)}).show()};b()}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}function reset_tool_search(a){var c=$("#galaxy_tools").contents();if(c.length===0){c=$(document)}$(this).removeClass("search_active");c.find(".toolTitle").removeClass("search_match");c.find(".toolSectionBody").hide();c.find(".toolTitle").show();c.find(".toolPanelLabel").show();c.find(".toolSectionWrapper").each(function(){if($(this).attr("id")!=="recently_used_wrapper"){$(this).show()}else{if($(this).hasClass("user_pref_visible")){$(this).show()}}});c.find("#search-no-results").hide();c.find("#search-spinner").hide();if(a){var b=c.find("#tool-search-query");b.val("search tools")}}var GalaxyAsync=function(a){this.url_dict={};this.log_action=(a===undefined?false:a)};GalaxyAsync.prototype.set_func_url=function(a,b){this.url_dict[a]=b};GalaxyAsync.prototype.set_user_pref=function(a,b){var c=this.url_dict[arguments.callee];if(c===undefined){return false}$.ajax({url:c,data:{pref_name:a,pref_value:b},error:function(){return false},success:function(){return true}})};GalaxyAsync.prototype.log_user_action=function(c,b,d){if(!this.log_action){return}var a=this.url_dict[arguments.callee];if(a===undefined){return false}$.ajax({url:a,data:{action:c,context:b,params:d},error:function(){return false},success:function(){return true}})};$(document).ready(function(){$("select[refresh_on_change='true']").change(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");$(document).trigger("convert_to_values");a.get(0).form.submit()});$(":checkbox[refresh_on_change='true']").click(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");a.get(0).form.submit()});$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tooltip){$(".unified-panel-header [title]").tooltip({placement:"bottom"});$("[title]").tooltip({placement:"top"})}make_popup_menus();replace_big_select_inputs(20,1500);$("a").click(function(){var b=$(this);var c=(parent.frames&&parent.frames.galaxy_main);if((b.attr("target")=="galaxy_main")&&(!c)){var a=b.attr("href");if(a.indexOf("?")==-1){a+="?"}else{a+="&"}a+="use_panels=True";b.attr("href",a);b.attr("target","_self")}return b})}); \ No newline at end of file +(function(){var b=0;var c=["ms","moz","webkit","o"];for(var a=0;a<c.length&&!window.requestAnimationFrame;++a){window.requestAnimationFrame=window[c[a]+"RequestAnimationFrame"];window.cancelRequestAnimationFrame=window[c[a]+"CancelRequestAnimationFrame"]}if(!window.requestAnimationFrame){window.requestAnimationFrame=function(h,e){var d=new Date().getTime();var f=Math.max(0,16-(d-b));var g=window.setTimeout(function(){h(d+f)},f);b=d+f;return g}}if(!window.cancelAnimationFrame){window.cancelAnimationFrame=function(d){clearTimeout(d)}}}());if(!Array.indexOf){Array.prototype.indexOf=function(c){for(var b=0,a=this.length;b<a;b++){if(this[b]==c){return b}}return -1}}function obj_length(c){if(c.length!==undefined){return c.length}var b=0;for(var a in c){b++}return b}$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function make_popupmenu(b,c){var a=(b.data("menu_options"));b.data("menu_options",c);if(a){return}b.bind("click.show_popup",function(d){$(".popmenu-wrapper").remove();setTimeout(function(){var g=$("<ul class='dropdown-menu' id='"+b.attr("id")+"-menu'></ul>");var f=b.data("menu_options");if(obj_length(f)<=0){$("<li>No Options.</li>").appendTo(g)}$.each(f,function(j,i){if(i){var l=i.action||i;g.append($("<li></li>").append($("<a>").attr("href",i.url).html(j).click(l)))}else{g.append($("<li></li>").addClass("head").append($("<a href='#'></a>").html(j)))}});var h=$("<div class='popmenu-wrapper' style='position: absolute;left: 0; top: -1000;'></div>").append(g).appendTo("body");var e=d.pageX-h.width()/2;e=Math.min(e,$(document).scrollLeft()+$(window).width()-$(h).width()-5);e=Math.max(e,$(document).scrollLeft()+5);h.css({top:d.pageY,left:e})},10);setTimeout(function(){var f=function(h){$(h).bind("click.close_popup",function(){$(".popmenu-wrapper").remove();h.unbind("click.close_popup")})};f($(window.document));f($(window.top.document));for(var e=window.top.frames.length;e--;){var g=$(window.top.frames[e].document);f(g)}},50);return false})}function make_popup_menus(a){a=a||document;$(a).find("div[popupmenu]").each(function(){var b={};var d=$(this);d.find("a").each(function(){var g=$(this),i=g.get(0),e=i.getAttribute("confirm"),f=i.getAttribute("href"),h=i.getAttribute("target");if(!f){b[g.text()]=null}else{b[g.text()]={url:f,action:function(){if(!e||confirm(e)){var j;if(h==="demo"){if(j===undefined||j.closed){j=window.open(f,h);j.creator=self}}else{g.trigger("click")}}}}}});var c=$(a).find("#"+d.attr("popupmenu"));c.find("a").bind("click",function(f){f.stopPropagation();return true});make_popupmenu(c,b);c.addClass("popup");d.remove()})}function naturalSort(j,h){var p=/(-?[0-9\.]+)/g,k=j.toString().toLowerCase()||"",g=h.toString().toLowerCase()||"",l=String.fromCharCode(0),n=k.replace(p,l+"$1"+l).split(l),e=g.replace(p,l+"$1"+l).split(l),d=(new Date(k)).getTime(),o=d?(new Date(g)).getTime():null;if(o){if(d<o){return -1}else{if(d>o){return 1}}}var m,f;for(var i=0,c=Math.max(n.length,e.length);i<c;i++){m=parseFloat(n[i])||n[i];f=parseFloat(e[i])||e[i];if(m<f){return -1}else{if(m>f){return 1}}}return 0}$.fn.refresh_select2=function(){var b=$(this);var a={width:"resolve",closeOnSelect:!b.is("[MULTIPLE]")};return b.select2(a)};function replace_big_select_inputs(a,c,b){if(!jQuery.fn.select2){return}if(a===undefined){a=20}if(c===undefined){c=3000}b=b||$("select");b.each(function(){var e=$(this);var d=e.find("option").length;if((d<a)||(d>c)){return}if(e.hasClass("no-autocomplete")){return}e.refresh_select2()})}$.fn.make_text_editable=function(g){var d=("num_cols" in g?g.num_cols:30),c=("num_rows" in g?g.num_rows:4),e=("use_textarea" in g?g.use_textarea:false),b=("on_finish" in g?g.on_finish:null),f=("help_text" in g?g.help_text:null);var a=$(this);a.addClass("editable-text").click(function(l){if($(this).children(":input").length>0){return}a.removeClass("editable-text");var i=function(m){a.find(":input").remove();if(m!==""){a.text(m)}else{a.html("<br>")}a.addClass("editable-text");if(b){b(m)}};var h=a.text(),k,j;if(e){k=$("<textarea/>").attr({rows:c,cols:d}).text($.trim(h)).keyup(function(m){if(m.keyCode===27){i(h)}});j=$("<button/>").text("Done").click(function(){i(k.val());return false})}else{k=$("<input type='text'/>").attr({value:$.trim(h),size:d}).blur(function(){i(h)}).keyup(function(m){if(m.keyCode===27){$(this).trigger("blur")}else{if(m.keyCode===13){i($(this).val())}}})}a.text("");a.append(k);if(j){a.append(j)}k.focus();k.select();l.stopPropagation()});if(f){a.attr("title",f).tooltip()}return a};function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).click(function(){if($("#renaming-active").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text($.trim(k))}else{j=$("<input type='text'></input>").attr({value:$.trim(k),size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){if(o!==""){l.text(o)}else{l.html("<em>None</em>")}if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(d,a,c){var b=function(){try{var e=$.jStorage.get("history_expand_state");if(e){for(var g in e){$("#"+g+" div.historyItemBody").show()}}}catch(f){$.jStorage.deleteKey("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}d.each(function(){var j=this.id,h=$(this).children("div.historyItemBody"),i=h.find("pre.peek");$(this).find(".historyItemTitleBar > .historyItemTitle").wrap("<a href='javascript:void(0);'></a>").click(function(){var k;if(h.is(":visible")){if($.browser.mozilla){i.css("overflow","hidden")}h.slideUp("fast");if(!c){k=$.jStorage.get("history_expand_state");if(k){delete k[j];$.jStorage.set("history_expand_state",k)}}}else{h.slideDown("fast",function(){if($.browser.mozilla){i.css("overflow","auto")}});if(!c){k=$.jStorage.get("history_expand_state");if(!k){k={}}k[j]=true;$.jStorage.set("history_expand_state",k)}}return false})});$("#top-links > a.toggle").click(function(){var h=$.jStorage.get("history_expand_state");if(!h){h={}}$("div.historyItemBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(h){delete h[$(this).parent().attr("id")]}});$.jStorage.set("history_expand_state",h)}).show()};b()}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}function reset_tool_search(a){var c=$("#galaxy_tools").contents();if(c.length===0){c=$(document)}$(this).removeClass("search_active");c.find(".toolTitle").removeClass("search_match");c.find(".toolSectionBody").hide();c.find(".toolTitle").show();c.find(".toolPanelLabel").show();c.find(".toolSectionWrapper").each(function(){if($(this).attr("id")!=="recently_used_wrapper"){$(this).show()}else{if($(this).hasClass("user_pref_visible")){$(this).show()}}});c.find("#search-no-results").hide();c.find("#search-spinner").hide();if(a){var b=c.find("#tool-search-query");b.val("search tools")}}var GalaxyAsync=function(a){this.url_dict={};this.log_action=(a===undefined?false:a)};GalaxyAsync.prototype.set_func_url=function(a,b){this.url_dict[a]=b};GalaxyAsync.prototype.set_user_pref=function(a,b){var c=this.url_dict[arguments.callee];if(c===undefined){return false}$.ajax({url:c,data:{pref_name:a,pref_value:b},error:function(){return false},success:function(){return true}})};GalaxyAsync.prototype.log_user_action=function(c,b,d){if(!this.log_action){return}var a=this.url_dict[arguments.callee];if(a===undefined){return false}$.ajax({url:a,data:{action:c,context:b,params:d},error:function(){return false},success:function(){return true}})};$(document).ready(function(){$("select[refresh_on_change='true']").change(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");$(document).trigger("convert_to_values");a.get(0).form.submit()});$(":checkbox[refresh_on_change='true']").click(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");a.get(0).form.submit()});$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tooltip){$(".unified-panel-header [title]").tooltip({placement:"bottom"});$("[title]").tooltip({placement:"top"})}make_popup_menus();replace_big_select_inputs(20,1500);$("a").click(function(){var b=$(this);var c=(parent.frames&&parent.frames.galaxy_main);if((b.attr("target")=="galaxy_main")&&(!c)){var a=b.attr("href");if(a.indexOf("?")==-1){a+="?"}else{a+="&"}a+="use_panels=True";b.attr("href",a);b.attr("target","_self")}return b})}); \ No newline at end of file diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/packed/galaxy.modal.js --- a/static/scripts/packed/galaxy.modal.js +++ b/static/scripts/packed/galaxy.modal.js @@ -1,1 +1,1 @@ -define(["libs/backbone/backbone-relational"],function(){var a=Backbone.View.extend({el_main:"#everything",options:{title:"galaxy-modal",body:"No content available."},initialize:function(b){if(b){this.create(b);$(this.el).hide()}},show:function(b){if(b){this.create(b)}this.$el.fadeIn("fast")},hide:function(){this.$el.fadeOut("fast")},create:function(c){this.$el.remove();if(!c){c=this.options}else{c=_.defaults(c,this.options)}this.setElement(this.template(c.title,c.body));$(this.el_main).append($(this.el));var d=(this.$el).find(".buttons");var b=this;if(c.buttons){$.each(c.buttons,function(e,f){d.append($("<button></button>").text(e).click(f)).append(" ")})}else{d.append($("<button></button>").text("Close").click(function(){b.hide()})).append(" ")}},template:function(c,b){return'<div class="modal in"><div class="modal-backdrop in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><span><h3 class="title">'+c+'</h3></span></div><div class="modal-body style="min-width: 540px; max-height: 445px;">'+b+'</div><div class="modal-footer"><div class="buttons" style="float: right;"></div></div></div</div></div>'}});return{GalaxyModal:a}}); \ No newline at end of file +define(["libs/backbone/backbone-relational"],function(){var a=Backbone.View.extend({el_main:"#everything",options:{title:"galaxy-modal",body:"No content available."},initialize:function(b){if(b){this.create(b);$(this.el).hide()}},show:function(b){if(b){this.create(b)}this.$el.fadeIn("fast")},hide:function(){this.$el.fadeOut("fast")},create:function(c){this.$el.remove();if(!c){c=this.options}else{c=_.defaults(c,this.options)}this.setElement(this.template(c.title,c.body));$(this.el_main).append($(this.el));var d=(this.$el).find(".buttons");var b=this;if(c.buttons){$.each(c.buttons,function(e,f){d.append($('<button id="'+String(e).toLowerCase()+'"></button>').text(e).click(f)).append(" ")})}else{d.append($("<button></button>").text("Close").click(function(){b.hide()})).append(" ")}},enable:function(b){$(this.el).find("#"+String(b).toLowerCase()).prop("disabled",false)},disable:function(b){$(this.el).find("#"+String(b).toLowerCase()).prop("disabled",true)},template:function(c,b){return'<div class="modal in"><div class="modal-backdrop in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><span><h3 class="title">'+c+'</h3></span></div><div class="modal-body style="min-width: 540px; max-height: 445px;">'+b+'</div><div class="modal-footer"><div class="buttons" style="float: right;"></div></div></div</div></div>'}});return{GalaxyModal:a}}); \ No newline at end of file diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/packed/galaxy.panels.js --- a/static/scripts/packed/galaxy.panels.js +++ b/static/scripts/packed/galaxy.panels.js @@ -1,1 +1,1 @@ -!function(c,d){var e=function(){if(d("#DD-helper").length==0){d("<div id='DD-helper'/>").appendTo("body").hide()}};var b=150,h=800;var k=function(n){this.$panel=n.panel;this.$center=n.center;this.$drag=n.drag;this.$toggle=n.toggle;this.left=!n.right;this.hidden=false;this.hidden_by_tool=false;this.saved_size=null;this.init()};d.extend(k.prototype,{resize:function(n){this.$panel.css("width",n);if(this.left){this.$center.css("left",n)}else{this.$center.css("right",n)}if(document.recalc){document.recalc()}},do_toggle:function(){var n=this;if(this.hidden){this.$toggle.removeClass("hidden");if(this.left){this.$panel.css("left",-this.saved_size).show().animate({left:0},"fast",function(){n.resize(n.saved_size)})}else{this.$panel.css("right",-this.saved_size).show().animate({right:0},"fast",function(){n.resize(n.saved_size)})}n.hidden=false}else{n.saved_size=this.$panel.width();if(document.recalc){document.recalc()}if(this.left){this.$panel.animate({left:-this.saved_size},"fast")}else{this.$panel.animate({right:-this.saved_size},"fast")}if(this.left){this.$center.css("left",0)}else{this.$center.css("right",0)}n.hidden=true;n.$toggle.addClass("hidden")}this.hidden_by_tool=false},handle_minwidth_hint:function(n){var o=this.$center.width()-(this.hidden?this.saved_size:0);if(o<n){if(!this.hidden){this.do_toggle();this.hidden_by_tool=true}}else{if(this.hidden_by_tool){this.do_toggle();this.hidden_by_tool=false}}},force_panel:function(n){if((this.hidden&&n=="show")||(!this.hidden&&n=="hide")){this.do_toggle()}},init:function(){var n=this;this.$toggle.remove().appendTo("body");this.$drag.on("dragstart",function(o,p){d("#DD-helper").show();p.width=n.$panel.width()}).on("dragend",function(){d("#DD-helper").hide()}).on("drag",function(p,q){var o;if(n.left){o=q.width+q.deltaX}else{o=q.width-q.deltaX}o=Math.min(h,Math.max(b,o));n.resize(o)});n.$toggle.on("click",function(){n.do_toggle()})}});var f=function(n){this.$overlay=n.overlay;this.$dialog=n.dialog;this.$header=this.$dialog.find(".modal-header");this.$body=this.$dialog.find(".modal-body");this.$footer=this.$dialog.find(".modal-footer");this.$backdrop=n.backdrop};d.extend(f.prototype,{setContent:function(p){if(p.title){this.$header.find(".title").html(p.title);this.$header.show()}else{this.$header.hide()}this.$footer.hide();var o=this.$footer.find(".buttons").html("");if(p.buttons){d.each(p.buttons,function(r,s){o.append(d("<button></button> ").text(r).click(s)).append(" ")});this.$footer.show()}var q=this.$footer.find(".extra_buttons").html("");if(p.extra_buttons){d.each(p.extra_buttons,function(r,s){q.append(d("<button></button>").text(r).click(s)).append(" ")});this.$footer.show()}var n=p.body;if(n=="progress"){n=d("<div class='progress progress-striped active'><div class='bar' style='width: 100%'></div></div>")}this.$body.html(n)},show:function(n,o){if(!this.$dialog.is(":visible")){if(n.backdrop){this.$backdrop.addClass("in")}else{this.$backdrop.removeClass("in")}this.$overlay.show();this.$dialog.show();this.$overlay.addClass("in");this.$body.css("min-width",this.$body.width());this.$body.css("max-height",d(window).height()-2*this.$dialog.offset().top-this.$footer.outerHeight()-this.$header.outerHeight())}if(o){o()}},hide:function(){var n=this;n.$dialog.fadeOut(function(){n.$overlay.hide();n.$backdrop.removeClass("in");n.$body.children().remove();n.$body.css("min-width",undefined)})}});var m;d(function(){m=new f({overlay:d("#top-modal"),dialog:d("#top-modal-dialog"),backdrop:d("#top-modal-backdrop")})});function a(){m.hide()}function l(r,n,p,o,q){m.setContent({title:r,body:n,buttons:p,extra_buttons:o});m.show({backdrop:true},q)}function g(r,n,p,o,q){m.setContent({title:r,body:n,buttons:p,extra_buttons:o});m.show({backdrop:false},q)}function j(p){var q=p.width||"600";var o=p.height||"400";var n=p.scroll||"auto";d("#overlay-background").bind("click.overlay",function(){a();d("#overlay-background").unbind("click.overlay")});l(null,d("<div style='margin: -5px;'><img id='close_button' style='position:absolute;right:-17px;top:-15px;src='"+galaxy_config.root+"static/images/closebox.png'><iframe style='margin: 0; padding: 0;' src='"+p.url+"' width='"+q+"' height='"+o+"' scrolling='"+n+"' frameborder='0'></iframe></div>"));d("#close_button").bind("click",function(){a()})}function i(n,o){if(n){d(".loggedin-only").show();d(".loggedout-only").hide();d("#user-email").text(n);if(o){d(".admin-only").show()}}else{d(".loggedin-only").hide();d(".loggedout-only").show();d(".admin-only").hide()}}d(function(){var n=d("#masthead ul.nav > li.dropdown > .dropdown-menu");d("body").on("click.nav_popups",function(p){n.hide();d("#DD-helper").hide();if(d(p.target).closest("#masthead ul.nav > li.dropdown > .dropdown-menu").length){return}var o=d(p.target).closest("#masthead ul.nav > li.dropdown");if(o.length){d("#DD-helper").show();o.children(".dropdown-menu").show();p.preventDefault()}})});c.ensure_dd_helper=e;c.Panel=k;c.Modal=f;c.hide_modal=a;c.show_modal=l;c.show_message=g;c.show_in_overlay=j;c.user_changed=i}(window,window.jQuery); \ No newline at end of file +!function(c,d){var e=function(){if(d("#DD-helper").length==0){d("<div id='DD-helper'/>").appendTo("body").hide()}};var b=150,h=800;var k=function(n){this.$panel=n.panel;this.$center=n.center;this.$drag=n.drag;this.$toggle=n.toggle;this.left=!n.right;this.hidden=false;this.hidden_by_tool=false;this.saved_size=null;this.init()};d.extend(k.prototype,{resize:function(n){this.$panel.css("width",n);if(this.left){this.$center.css("left",n)}else{this.$center.css("right",n)}if(document.recalc){document.recalc()}},do_toggle:function(){var n=this;if(this.hidden){this.$toggle.removeClass("hidden");if(this.left){this.$panel.css("left",-this.saved_size).show().animate({left:0},"fast",function(){n.resize(n.saved_size)})}else{this.$panel.css("right",-this.saved_size).show().animate({right:0},"fast",function(){n.resize(n.saved_size)})}n.hidden=false}else{n.saved_size=this.$panel.width();if(document.recalc){document.recalc()}if(this.left){this.$panel.animate({left:-this.saved_size},"fast")}else{this.$panel.animate({right:-this.saved_size},"fast")}if(this.left){this.$center.css("left",0)}else{this.$center.css("right",0)}n.hidden=true;n.$toggle.addClass("hidden")}this.hidden_by_tool=false},handle_minwidth_hint:function(n){var o=this.$center.width()-(this.hidden?this.saved_size:0);if(o<n){if(!this.hidden){this.do_toggle();this.hidden_by_tool=true}}else{if(this.hidden_by_tool){this.do_toggle();this.hidden_by_tool=false}}},force_panel:function(n){if((this.hidden&&n=="show")||(!this.hidden&&n=="hide")){this.do_toggle()}},init:function(){var n=this;this.$toggle.remove().appendTo("body");this.$drag.on("dragstart",function(o,p){d("#DD-helper").show();p.width=n.$panel.width()}).on("dragend",function(){d("#DD-helper").hide()}).on("drag",function(p,q){var o;if(n.left){o=q.width+q.deltaX}else{o=q.width-q.deltaX}o=Math.min(h,Math.max(b,o));n.resize(o)});n.$toggle.on("click",function(){n.do_toggle()})}});var f=function(n){this.$overlay=n.overlay;this.$dialog=n.dialog;this.$header=this.$dialog.find(".modal-header");this.$body=this.$dialog.find(".modal-body");this.$footer=this.$dialog.find(".modal-footer");this.$backdrop=n.backdrop};d.extend(f.prototype,{setContent:function(p){if(p.title){this.$header.find(".title").html(p.title);this.$header.show()}else{this.$header.hide()}this.$footer.hide();var o=this.$footer.find(".buttons").html("");if(p.buttons){d.each(p.buttons,function(r,s){o.append(d("<button></button> ").text(r).click(s)).append(" ")});this.$footer.show()}var q=this.$footer.find(".extra_buttons").html("");if(p.extra_buttons){d.each(p.extra_buttons,function(r,s){q.append(d("<button></button>").text(r).click(s)).append(" ")});this.$footer.show()}var n=p.body;if(n=="progress"){n=d("<div class='progress progress-striped active'><div class='bar' style='width: 100%'></div></div>")}this.$body.html(n)},show:function(n,o){if(!this.$dialog.is(":visible")){if(n.backdrop){this.$backdrop.addClass("in")}else{this.$backdrop.removeClass("in")}this.$overlay.show();this.$dialog.show();this.$overlay.addClass("in");this.$body.css("min-width",this.$body.width());this.$body.css("max-height",d(window).height()-this.$footer.outerHeight()-this.$header.outerHeight()-parseInt(this.$dialog.css("padding-top"),10)-parseInt(this.$dialog.css("padding-bottom"),10))}if(o){o()}},hide:function(){var n=this;n.$dialog.fadeOut(function(){n.$overlay.hide();n.$backdrop.removeClass("in");n.$body.children().remove();n.$body.css("min-width",undefined)})}});var m;d(function(){m=new f({overlay:d("#top-modal"),dialog:d("#top-modal-dialog"),backdrop:d("#top-modal-backdrop")})});function a(){m.hide()}function l(r,n,p,o,q){m.setContent({title:r,body:n,buttons:p,extra_buttons:o});m.show({backdrop:true},q)}function g(r,n,p,o,q){m.setContent({title:r,body:n,buttons:p,extra_buttons:o});m.show({backdrop:false},q)}function j(p){var q=p.width||"600";var o=p.height||"400";var n=p.scroll||"auto";d("#overlay-background").bind("click.overlay",function(){a();d("#overlay-background").unbind("click.overlay")});l(null,d("<div style='margin: -5px;'><img id='close_button' style='position:absolute;right:-17px;top:-15px;src='"+galaxy_config.root+"static/images/closebox.png'><iframe style='margin: 0; padding: 0;' src='"+p.url+"' width='"+q+"' height='"+o+"' scrolling='"+n+"' frameborder='0'></iframe></div>"));d("#close_button").bind("click",function(){a()})}function i(n,o){if(n){d(".loggedin-only").show();d(".loggedout-only").hide();d("#user-email").text(n);if(o){d(".admin-only").show()}}else{d(".loggedin-only").hide();d(".loggedout-only").show();d(".admin-only").hide()}}d(function(){var n=d("#masthead ul.nav > li.dropdown > .dropdown-menu");d("body").on("click.nav_popups",function(p){n.hide();d("#DD-helper").hide();if(d(p.target).closest("#masthead ul.nav > li.dropdown > .dropdown-menu").length){return}var o=d(p.target).closest("#masthead ul.nav > li.dropdown");if(o.length){d("#DD-helper").show();o.children(".dropdown-menu").show();p.preventDefault()}})});c.ensure_dd_helper=e;c.Panel=k;c.Modal=f;c.hide_modal=a;c.show_modal=l;c.show_message=g;c.show_in_overlay=j;c.user_changed=i}(window,window.jQuery); \ No newline at end of file diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/packed/galaxy.upload.js --- a/static/scripts/packed/galaxy.upload.js +++ b/static/scripts/packed/galaxy.upload.js @@ -1,1 +1,1 @@ -define(["galaxy.modal","galaxy.master","utils/galaxy.uploadbox","libs/backbone/backbone-relational"],function(b,c){var a=Backbone.View.extend({modal:null,button_show:null,file_counter:0,initialize:function(){var d=this;this.button_show=new c.GalaxyMasterIcon({icon:"fa-icon-upload",tooltip:"Upload Files",on_click:function(f){d.event_show(f)},with_number:true});Galaxy.master.prepend(this.button_show)},events:{mouseover:"event_mouseover",mouseleave:"event_mouseleave"},event_mouseover:function(d){$("#galaxy-upload-box").addClass("highlight")},event_mouseleave:function(d){$("#galaxy-upload-box").removeClass("highlight")},event_start:function(d,e,f){var g="#galaxy-upload-file-"+d;$("#galaxy-upload-box").append(this.template_file(g));$("#galaxy-upload-file-"+d).find(".title").html(e.name);this.event_progress(d,e,0);this.file_counter++;this.refresh()},event_progress:function(e,f,h){var g=$("#galaxy-upload-file-"+e);var d=parseInt(h);g.find(".progress").css({width:d+"%"});g.find(".info").html(d+"% of "+this.size_to_string(f.size))},event_success:function(d,e,f){Galaxy.currHistoryPanel.refresh();this.file_counter--;this.refresh()},event_error:function(d,e,g){var f=$("#galaxy-upload-file-"+d);f.find(".progress-frame").addClass("failed");f.find(".error").html("<strong>Failed:</strong> "+g);this.event_progress(d,e,0);this.file_counter--;this.refresh()},event_show:function(g){g.preventDefault();if(!Galaxy.currHistoryPanel){var f=this;window.setTimeout(function(){f.event_show(g)},200);return}if(!this.modal){var f=this;this.modal=new b.GalaxyModal({title:"Upload files from your local drive",body:this.template(),buttons:{Close:function(){f.modal.hide()}}});var d=Galaxy.currHistoryPanel.model.get("id");var f=this;$("#galaxy-upload-box").uploadbox({url:galaxy_config.root+"api/histories/"+d+"/contents",dragover:f.event_mouseover,dragleave:f.event_mouseleave,start:function(e,h,i){f.event_start(e,h,i)},success:function(e,h,i){f.event_success(e,h,i)},progress:function(e,h,i){f.event_progress(e,h,i)},error:function(e,h,i){f.event_error(e,h,i)},data:{source:"upload"}});this.setElement("#galaxy-upload-box")}this.modal.show()},refresh:function(){if(this.file_counter>0){this.button_show.number(this.file_counter)}else{this.button_show.number("")}},size_to_string:function(d){var e="";if(d>=100000000000){d=d/100000000000;e="TB"}else{if(d>=100000000){d=d/100000000;e="GB"}else{if(d>=100000){d=d/100000;e="MB"}else{if(d>=100){d=d/100;e="KB"}else{d=d*10;e="b"}}}}return"<strong>"+(Math.round(d)/10)+"</strong> "+e},template:function(){return'<form id="galaxy-upload-box" class="galaxy-upload-box"></form>'},template_file:function(d){return'<div id="'+d.substr(1)+'" class="file corner-soft shadow"><div class="title"></div><div class="error"></div><div class="progress-frame corner-soft"><div class="progress"></div></div><div class="info"></div></div>'}});return{GalaxyUpload:a}}); \ No newline at end of file +define(["galaxy.modal","galaxy.master","utils/galaxy.uploadbox","libs/backbone/backbone-relational"],function(b,c){var a=Backbone.View.extend({modal:null,button_show:null,uploadbox:null,select_extension:{"":"Auto-detect",bed:"bed",ab1:"ab1"},counter:{announce:0,success:0,error:0,running:0,reset:function(){this.announce=this.success=this.error=this.running=0}},initialize:function(){if(!Galaxy.currHistoryPanel){var d=this;window.setTimeout(function(){d.initialize()},500);return}var d=this;this.button_show=new c.GalaxyMasterIcon({icon:"fa-icon-upload",tooltip:"Upload Files",on_click:function(f){d.event_show(f)},with_number:true});Galaxy.master.prepend(this.button_show)},events:{mouseover:"event_mouseover",mouseleave:"event_mouseleave"},event_mouseover:function(d){},event_mouseleave:function(d){},event_announce:function(e,f,h){var i="#upload-"+e;$(this.el).append(this.template_file(i,this.select_extension));var g=this.get_upload_item(e);g.fadeIn();g.find(".title").html(f.name);var d=this;g.find(".remove").on("click",function(){d.event_remove(e)});this.event_progress(e,f,0);this.counter.announce++;this.update_screen()},event_initialize:function(d,e,g){this.button_show.number(this.counter.announce);var f=this.get_upload_item(d);var h={source:"upload",space_to_tabs:f.find("#space_to_tabs").is(":checked"),extension:f.find("#extension").val()};return h},event_progress:function(e,f,h){var g=this.get_upload_item(e);var d=parseInt(h);g.find(".progress-bar").css({width:d+"%"});g.find(".info").html(d+"% of "+this.size_to_string(f.size))},event_success:function(d,e,g){var f=this.get_upload_item(d);f.addClass("panel-success");f.removeClass("panel-default");Galaxy.currHistoryPanel.refresh();this.event_progress(d,e,100);this.button_show.number("");this.counter.announce--;this.counter.success++;this.update_screen()},event_error:function(d,e,g){var f=this.get_upload_item(d);f.addClass("panel-danger");f.removeClass("panel-default");f.find(".progress").remove();f.find(".error").html("<strong>Failed:</strong> "+g);this.event_progress(d,e,0);this.button_show.number("");this.counter.announce--;this.counter.error++;this.update_screen()},event_upload:function(){if(this.counter.announce==0||this.counter.running>0){return}this.counter.running=this.counter.announce;this.update_screen();$(this.el).find(".panel-body").hide();$(this.el).find(".remove").each(function(){$(this).removeClass("fa-icon-trash");$(this).addClass("fa-icon-caret-down")});var d=Galaxy.currHistoryPanel.model.get("id");this.uploadbox.configure({url:galaxy_config.root+"api/histories/"+d+"/contents"});this.uploadbox.upload()},event_complete:function(){this.counter.running=0;this.update_screen()},event_reset:function(){if(this.counter.running==0){var d=$(this.el).find(".panel");d.fadeOut({complete:function(){d.remove()}});this.counter.reset();this.update_screen();this.uploadbox.reset()}},event_remove:function(d){if(this.counter.running==0){var e=this.get_upload_item(d);if(e.hasClass("panel-default")){this.counter.announce--}else{if(e.hasClass("panel-success")){this.counter.success--}else{if(e.hasClass("panel-danger")){this.counter.error--}}}this.update_screen();this.uploadbox.remove(d);e.remove()}},event_show:function(f){f.preventDefault();if(!this.modal){var d=this;this.modal=new b.GalaxyModal({title:"Upload files from your local drive",body:this.template("upload-box"),buttons:{Select:function(){d.uploadbox.select()},Upload:function(){d.event_upload()},Reset:function(){d.event_reset()},Close:function(){d.modal.hide()}}});this.setElement("#upload-box");var d=this;this.uploadbox=this.$el.uploadbox({dragover:d.event_mouseover,dragleave:d.event_mouseleave,announce:function(e,g,h){d.event_announce(e,g,h)},initialize:function(e,g,h){return d.event_initialize(e,g,h)},success:function(e,g,h){d.event_success(e,g,h)},progress:function(e,g,h){d.event_progress(e,g,h)},error:function(e,g,h){d.event_error(e,g,h)},complete:function(){d.event_complete()},});this.update_screen()}this.modal.show()},get_upload_item:function(d){return $(this.el).find("#upload-"+d)},size_to_string:function(d){var e="";if(d>=100000000000){d=d/100000000000;e="TB"}else{if(d>=100000000){d=d/100000000;e="GB"}else{if(d>=100000){d=d/100000;e="MB"}else{if(d>=100){d=d/100;e="KB"}else{d=d*10;e="b"}}}}return"<strong>"+(Math.round(d)/10)+"</strong> "+e},update_screen:function(){if(this.counter.announce==0){if(this.uploadbox.compatible){message="Drag&drop files into this box or click 'Select' to select files!"}else{message="Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."}}else{if(this.counter.running==0){message="You added "+this.counter.announce+' file(s) to the queue. Add more files or click "Upload" to proceed.'}else{message="Please wait..."+this.counter.announce+" out of "+this.counter.running+" remaining."}}$("#upload-info").html(message);if(this.counter.running==0&&this.counter.announce+this.counter.success+this.counter.error>0){this.modal.enable("Reset")}else{this.modal.disable("Reset")}if(this.counter.running==0&&this.counter.announce>0){this.modal.enable("Upload")}else{this.modal.disable("Upload")}if(this.counter.running==0){this.modal.enable("Select")}else{this.modal.disable("Select")}},template:function(d){return'<div id="'+d+'" class="upload-box"></div><h6 id="upload-info" class="upload-info"></h6>'},template_file:function(f,e){var d='<div id="'+f.substr(1)+'" class="panel panel-default"><div class="panel-heading"><h5 class="title"></h5><h5 class="info"></h5><div class="remove fa-icon-trash"></div></div><div class="panel-body"><div class="menu">Select file type: <select id="extension">';for(key in e){d+='<option value="'+key+'">'+e[key]+"</option>"}d+='</select>, <span>Convert space to tabs: <input id="space_to_tabs" type="checkbox"></input></span></div></div><div class="panel-footer"><div class="progress"><div class="progress-bar progress-bar-success"></div></div><h6 class="error"></h6></div></div>';return d}});return{GalaxyUpload:a}}); \ No newline at end of file diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/packed/libs/jquery/select2.js --- a/static/scripts/packed/libs/jquery/select2.js +++ b/static/scripts/packed/libs/jquery/select2.js @@ -1,1 +1,1 @@ -(function(a){if(typeof a.fn.each2=="undefined"){a.extend(a.fn,{each2:function(f){var d=a([0]),e=-1,b=this.length;while(++e<b&&(d.context=d[0]=this[e])&&f.call(d[0],e,d)!==false){}return this}})}})(jQuery);(function(D,m){if(window.Select2!==m){return}var K,N,x,c,a,p,o={x:0,y:0},v,w,K={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(O){O=O.which?O.which:O;switch(O){case K.LEFT:case K.RIGHT:case K.UP:case K.DOWN:return true}return false},isControl:function(P){var O=P.which;switch(O){case K.SHIFT:case K.CTRL:case K.ALT:return true}if(P.metaKey){return true}return false},isFunctionKey:function(O){O=O.which?O.which:O;return O>=112&&O<=123}},B="<div class='select2-measure-scrollbar'></div>",d={"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z"};v=D(document);a=(function(){var O=1;return function(){return O++}}());function e(R){var P,Q,O,S;if(!R||R.length<1){return R}P="";for(Q=0,O=R.length;Q<O;Q++){S=R.charAt(Q);P+=d[S]||S}return P}function q(Q,R){var P=0,O=R.length;for(;P<O;P=P+1){if(t(Q,R[P])){return P}}return -1}function M(){var O=D(B);O.appendTo("body");var P={width:O.width()-O[0].clientWidth,height:O.height()-O[0].clientHeight};O.remove();return P}function t(P,O){if(P===O){return true}if(P===m||O===m){return false}if(P===null||O===null){return false}if(P.constructor===String){return P+""===O+""}if(O.constructor===String){return O+""===P+""}return false}function i(P,R){var S,Q,O;if(P===null||P.length<1){return[]}S=P.split(R);for(Q=0,O=S.length;Q<O;Q=Q+1){S[Q]=D.trim(S[Q])}return S}function h(O){return O.outerWidth(false)-O.width()}function F(P){var O="keyup-change-value";P.on("keydown",function(){if(D.data(P,O)===m){D.data(P,O,P.val())}});P.on("keyup",function(){var Q=D.data(P,O);if(Q!==m&&P.val()!==Q){D.removeData(P,O);P.trigger("keyup-change")}})}v.on("mousemove",function(O){o.x=O.pageX;o.y=O.pageY});function J(O){O.on("mousemove",function(Q){var P=o;if(P===m||P.x!==Q.pageX||P.y!==Q.pageY){D(Q.target).trigger("mousemove-filtered",Q)}})}function k(R,P,O){O=O||m;var Q;return function(){var S=arguments;window.clearTimeout(Q);Q=window.setTimeout(function(){P.apply(O,S)},R)}}function s(Q){var O=false,P;return function(){if(O===false){P=Q();O=true}return P}}function l(O,Q){var P=k(O,function(R){Q.trigger("scroll-debounced",R)});Q.on("scroll",function(R){if(q(R.target,Q.get())>=0){P(R)}})}function I(O){if(O[0]===document.activeElement){return}window.setTimeout(function(){var Q=O[0],R=O.val().length,P;O.focus();if(O.is(":visible")&&Q===document.activeElement){if(Q.setSelectionRange){Q.setSelectionRange(R,R)}else{if(Q.createTextRange){P=Q.createTextRange();P.collapse(false);P.select()}}}},0)}function f(O){O=D(O)[0];var R=0;var P=0;if("selectionStart" in O){R=O.selectionStart;P=O.selectionEnd-R}else{if("selection" in document){O.focus();var Q=document.selection.createRange();P=document.selection.createRange().text.length;Q.moveStart("character",-O.value.length);R=Q.text.length-P}}return{offset:R,length:P}}function A(O){O.preventDefault();O.stopPropagation()}function b(O){O.preventDefault();O.stopImmediatePropagation()}function n(P){if(!p){var O=P[0].currentStyle||window.getComputedStyle(P[0],null);p=D(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:O.fontSize,fontFamily:O.fontFamily,fontStyle:O.fontStyle,fontWeight:O.fontWeight,letterSpacing:O.letterSpacing,textTransform:O.textTransform,whiteSpace:"nowrap"});p.attr("class","select2-sizer");D("body").append(p)}p.text(P.val());return p.width()}function j(P,T,O){var R,S=[],Q;R=P.attr("class");if(R){R=""+R;D(R.split(" ")).each2(function(){if(this.indexOf("select2-")===0){S.push(this)}})}R=T.attr("class");if(R){R=""+R;D(R.split(" ")).each2(function(){if(this.indexOf("select2-")!==0){Q=O(this);if(Q){S.push(this)}}})}P.attr("class",S.join(" "))}function u(T,S,Q,O){var R=e(T.toUpperCase()).indexOf(e(S.toUpperCase())),P=S.length;if(R<0){Q.push(O(T));return}Q.push(O(T.substring(0,R)));Q.push("<span class='select2-match'>");Q.push(O(T.substring(R,R+P)));Q.push("</span>");Q.push(O(T.substring(R+P,T.length)))}function G(O){var P={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(O).replace(/[&<>"'\/\\]/g,function(Q){return P[Q]})}function E(P){var S,Q=null,T=P.quietMillis||100,R=P.url,O=this;return function(U){window.clearTimeout(S);S=window.setTimeout(function(){var X=P.data,W=R,Z=P.transport||D.fn.select2.ajaxDefaults.transport,V={type:P.type||"GET",cache:P.cache||false,jsonpCallback:P.jsonpCallback||m,dataType:P.dataType||"json"},Y=D.extend({},D.fn.select2.ajaxDefaults.params,V);X=X?X.call(O,U.term,U.page,U.context):null;W=(typeof W==="function")?W.call(O,U.term,U.page,U.context):W;if(Q){Q.abort()}if(P.params){if(D.isFunction(P.params)){D.extend(Y,P.params.call(O))}else{D.extend(Y,P.params)}}D.extend(Y,{url:W,dataType:P.dataType,data:X,success:function(ab){var aa=P.results(ab,U.page);U.callback(aa)}});Q=Z.call(O,Y)},T)}}function H(P){var S=P,R,Q,T=function(U){return""+U.text};if(D.isArray(S)){Q=S;S={results:Q}}if(D.isFunction(S)===false){Q=S;S=function(){return Q}}var O=S();if(O.text){T=O.text;if(!D.isFunction(T)){R=O.text;T=function(U){return U[R]}}}return function(W){var V=W.term,U={results:[]},X;if(V===""){W.callback(S());return}X=function(Z,ab){var aa,Y;Z=Z[0];if(Z.children){aa={};for(Y in Z){if(Z.hasOwnProperty(Y)){aa[Y]=Z[Y]}}aa.children=[];D(Z.children).each2(function(ac,ad){X(ad,aa.children)});if(aa.children.length||W.matcher(V,T(aa),Z)){ab.push(aa)}}else{if(W.matcher(V,T(Z),Z)){ab.push(Z)}}};D(S().results).each2(function(Z,Y){X(Y,U.results)});W.callback(U)}}function z(P){var O=D.isFunction(P);return function(S){var R=S.term,Q={results:[]};D(O?P():P).each(function(){var T=this.text!==m,U=T?this.text:this;if(R===""||S.matcher(R,U)){Q.results.push(T?this:{id:this,text:this})}});S.callback(Q)}}function y(O,P){if(D.isFunction(O)){return true}if(!O){return false}throw new Error(P+" must be a function or a falsy value")}function C(O){return D.isFunction(O)?O():O}function r(O){var P=0;D.each(O,function(Q,R){if(R.children){P+=r(R.children)}else{P++}});return P}function g(W,X,U,O){var P=W,Y=false,R,V,S,Q,T;if(!O.createSearchChoice||!O.tokenSeparators||O.tokenSeparators.length<1){return m}while(true){V=-1;for(S=0,Q=O.tokenSeparators.length;S<Q;S++){T=O.tokenSeparators[S];V=W.indexOf(T);if(V>=0){break}}if(V<0){break}R=W.substring(0,V);W=W.substring(V+T.length);if(R.length>0){R=O.createSearchChoice.call(this,R,X);if(R!==m&&R!==null&&O.id(R)!==m&&O.id(R)!==null){Y=false;for(S=0,Q=X.length;S<Q;S++){if(t(O.id(R),O.id(X[S]))){Y=true;break}}if(!Y){U(R)}}}}if(P!==W){return W}}function L(O,P){var Q=function(){};Q.prototype=new O;Q.prototype.constructor=Q;Q.prototype.parent=O.prototype;Q.prototype=D.extend(Q.prototype,P);return Q}N=L(Object,{bind:function(P){var O=this;return function(){P.apply(O,arguments)}},init:function(S){var Q,P,T=".select2-results",R,O;this.opts=S=this.prepareOpts(S);this.id=S.id;if(S.element.data("select2")!==m&&S.element.data("select2")!==null){S.element.data("select2").destroy()}this.container=this.createContainer();this.containerId="s2id_"+(S.element.attr("id")||"autogen"+a());this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1");this.container.attr("id",this.containerId);this.body=s(function(){return S.element.closest("body")});j(this.container,this.opts.element,this.opts.adaptContainerCssClass);this.container.attr("style",S.element.attr("style"));this.container.css(C(S.containerCss));this.container.addClass(C(S.containerCssClass));this.elementTabIndex=this.opts.element.attr("tabindex");this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container);this.container.data("select2",this);this.dropdown=this.container.find(".select2-drop");this.dropdown.addClass(C(S.dropdownCssClass));this.dropdown.data("select2",this);j(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass);this.results=Q=this.container.find(T);this.search=P=this.container.find("input.select2-input");this.queryCount=0;this.resultsPage=0;this.context=null;this.initContainer();J(this.results);this.dropdown.on("mousemove-filtered touchstart touchmove touchend",T,this.bind(this.highlightUnderEvent));l(80,this.results);this.dropdown.on("scroll-debounced",T,this.bind(this.loadMoreIfNeeded));D(this.container).on("change",".select2-input",function(U){U.stopPropagation()});D(this.dropdown).on("change",".select2-input",function(U){U.stopPropagation()});if(D.fn.mousewheel){Q.mousewheel(function(Y,Z,W,V){var X=Q.scrollTop(),U;if(V>0&&X-V<=0){Q.scrollTop(0);A(Y)}else{if(V<0&&Q.get(0).scrollHeight-Q.scrollTop()+V<=Q.height()){Q.scrollTop(Q.get(0).scrollHeight-Q.height());A(Y)}}})}F(P);P.on("keyup-change input paste",this.bind(this.updateResults));P.on("focus",function(){P.addClass("select2-focused")});P.on("blur",function(){P.removeClass("select2-focused")});this.dropdown.on("mouseup",T,this.bind(function(U){if(D(U.target).closest(".select2-result-selectable").length>0){this.highlightUnderEvent(U);this.selectHighlighted(U)}}));this.dropdown.on("click mouseup mousedown",function(U){U.stopPropagation()});if(D.isFunction(this.opts.initSelection)){this.initSelection();this.monitorSource()}if(S.maximumInputLength!==null){this.search.attr("maxlength",S.maximumInputLength)}var R=S.element.prop("disabled");if(R===m){R=false}this.enable(!R);var O=S.element.prop("readonly");if(O===m){O=false}this.readonly(O);w=w||M();this.autofocus=S.element.prop("autofocus");S.element.prop("autofocus",false);if(this.autofocus){this.focus()}this.nextSearchTerm=m},destroy:function(){var P=this.opts.element,O=P.data("select2");this.close();if(this.propertyObserver){delete this.propertyObserver;this.propertyObserver=null}if(O!==m){O.container.remove();O.dropdown.remove();P.removeClass("select2-offscreen").removeData("select2").off(".select2").prop("autofocus",this.autofocus||false);if(this.elementTabIndex){P.attr({tabindex:this.elementTabIndex})}else{P.removeAttr("tabindex")}P.show()}},optionToData:function(O){if(O.is("option")){return{id:O.prop("value"),text:O.text(),element:O.get(),css:O.attr("class"),disabled:O.prop("disabled"),locked:t(O.attr("locked"),"locked")||t(O.data("locked"),true)}}else{if(O.is("optgroup")){return{text:O.attr("label"),children:[],element:O.get(),css:O.attr("class")}}}},prepareOpts:function(T){var R,P,O,S,Q=this;R=T.element;if(R.get(0).tagName.toLowerCase()==="select"){this.select=P=T.element}if(P){D.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in T){throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a <select> element.")}})}T=D.extend({},{populateResults:function(V,X,aa){var Z,Y,U,W,ab=this.opts.id;Z=function(ai,ac,ah){var aj,ae,ao,al,af,an,ad,am,ak,ag;ai=T.sortResults(ai,ac,aa);for(aj=0,ae=ai.length;aj<ae;aj=aj+1){ao=ai[aj];af=(ao.disabled===true);al=(!af)&&(ab(ao)!==m);an=ao.children&&ao.children.length>0;ad=D("<li></li>");ad.addClass("select2-results-dept-"+ah);ad.addClass("select2-result");ad.addClass(al?"select2-result-selectable":"select2-result-unselectable");if(af){ad.addClass("select2-disabled")}if(an){ad.addClass("select2-result-with-children")}ad.addClass(Q.opts.formatResultCssClass(ao));am=D(document.createElement("div"));am.addClass("select2-result-label");ag=T.formatResult(ao,am,aa,Q.opts.escapeMarkup);if(ag!==m){am.html(ag)}ad.append(am);if(an){ak=D("<ul></ul>");ak.addClass("select2-result-sub");Z(ao.children,ak,ah+1);ad.append(ak)}ad.data("select2-data",ao);ac.append(ad)}};Z(X,V,0)}},D.fn.select2.defaults,T);if(typeof(T.id)!=="function"){O=T.id;T.id=function(U){return U[O]}}if(D.isArray(T.element.data("select2Tags"))){if("tags" in T){throw"tags specified as both an attribute 'data-select2-tags' and in options of Select2 "+T.element.attr("id")}T.tags=T.element.data("select2Tags")}if(P){T.query=this.bind(function(Y){var X={results:[],more:false},W=Y.term,V,U,Z;Z=function(aa,ac){var ab;if(aa.is("option")){if(Y.matcher(W,aa.text(),aa)){ac.push(Q.optionToData(aa))}}else{if(aa.is("optgroup")){ab=Q.optionToData(aa);aa.children().each2(function(ad,ae){Z(ae,ab.children)});if(ab.children.length>0){ac.push(ab)}}}};V=R.children();if(this.getPlaceholder()!==m&&V.length>0){U=this.getPlaceholderOption();if(U){V=V.not(U)}}V.each2(function(aa,ab){Z(ab,X.results)});Y.callback(X)});T.id=function(U){return U.id};T.formatResultCssClass=function(U){return U.css}}else{if(!("query" in T)){if("ajax" in T){S=T.element.data("ajax-url");if(S&&S.length>0){T.ajax.url=S}T.query=E.call(T.element,T.ajax)}else{if("data" in T){T.query=H(T.data)}else{if("tags" in T){T.query=z(T.tags);if(T.createSearchChoice===m){T.createSearchChoice=function(U){return{id:D.trim(U),text:D.trim(U)}}}if(T.initSelection===m){T.initSelection=function(U,W){var V=[];D(i(U.val(),T.separator)).each(function(){var Z=this,Y=this,X=T.tags;if(D.isFunction(X)){X=X()}D(X).each(function(){if(t(this.id,Z)){Y=this.text;return false}});V.push({id:Z,text:Y})});W(V)}}}}}}}if(typeof(T.query)!=="function"){throw"query function not defined for Select2 "+T.element.attr("id")}return T},monitorSource:function(){var O=this.opts.element,P;O.on("change.select2",this.bind(function(Q){if(this.opts.element.data("select2-change-triggered")!==true){this.initSelection()}}));P=this.bind(function(){var S,R,Q=this;var T=O.prop("disabled");if(T===m){T=false}this.enable(!T);var R=O.prop("readonly");if(R===m){R=false}this.readonly(R);j(this.container,this.opts.element,this.opts.adaptContainerCssClass);this.container.addClass(C(this.opts.containerCssClass));j(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass);this.dropdown.addClass(C(this.opts.dropdownCssClass))});O.on("propertychange.select2 DOMAttrModified.select2",P);if(this.mutationCallback===m){this.mutationCallback=function(Q){Q.forEach(P)}}if(typeof WebKitMutationObserver!=="undefined"){if(this.propertyObserver){delete this.propertyObserver;this.propertyObserver=null}this.propertyObserver=new WebKitMutationObserver(this.mutationCallback);this.propertyObserver.observe(O.get(0),{attributes:true,subtree:false})}},triggerSelect:function(P){var O=D.Event("select2-selecting",{val:this.id(P),object:P});this.opts.element.trigger(O);return !O.isDefaultPrevented()},triggerChange:function(O){O=O||{};O=D.extend({},O,{type:"change",val:this.val()});this.opts.element.data("select2-change-triggered",true);this.opts.element.trigger(O);this.opts.element.data("select2-change-triggered",false);this.opts.element.click();if(this.opts.blurOnChange){this.opts.element.blur()}},isInterfaceEnabled:function(){return this.enabledInterface===true},enableInterface:function(){var O=this._enabled&&!this._readonly,P=!O;if(O===this.enabledInterface){return false}this.container.toggleClass("select2-container-disabled",P);this.close();this.enabledInterface=O;return true},enable:function(O){if(O===m){O=true}if(this._enabled===O){return}this._enabled=O;this.opts.element.prop("disabled",!O);this.enableInterface()},disable:function(){this.enable(false)},readonly:function(O){if(O===m){O=false}if(this._readonly===O){return false}this._readonly=O;this.opts.element.prop("readonly",O);this.enableInterface();return true},opened:function(){return this.container.hasClass("select2-dropdown-open")},positionDropdown:function(){var Q=this.dropdown,S=this.container.offset(),Z=this.container.outerHeight(false),aa=this.container.outerWidth(false),W=Q.outerHeight(false),P=D(window).scrollLeft()+D(window).width(),ad=D(window).scrollTop()+D(window).height(),R=S.top+Z,ab=S.left,O=R+W<=ad,U=(S.top-W)>=this.body().scrollTop(),X=Q.outerWidth(false),af=ab+X<=P,ae=Q.hasClass("select2-drop-above"),T,ac,V,Y;if(this.opts.dropdownAutoWidth){Y=D(".select2-results",Q)[0];Q.addClass("select2-drop-auto-width");Q.css("width","");X=Q.outerWidth(false)+(Y.scrollHeight===Y.clientHeight?0:w.width);X>aa?aa=X:X=aa;af=ab+X<=P}else{this.container.removeClass("select2-drop-auto-width")}if(this.body().css("position")!=="static"){T=this.body().offset();R-=T.top;ab-=T.left}if(ae){ac=true;if(!U&&O){ac=false}}else{ac=false;if(!O&&U){ac=true}}if(!af){ab=S.left+aa-X}if(ac){R=S.top-W;this.container.addClass("select2-drop-above");Q.addClass("select2-drop-above")}else{this.container.removeClass("select2-drop-above");Q.removeClass("select2-drop-above")}V=D.extend({top:R,left:ab,width:aa},C(this.opts.dropdownCss));Q.css(V)},shouldOpen:function(){var O;if(this.opened()){return false}if(this._enabled===false||this._readonly===true){return false}O=D.Event("select2-opening");this.opts.element.trigger(O);return !O.isDefaultPrevented()},clearDropdownAlignmentPreference:function(){this.container.removeClass("select2-drop-above");this.dropdown.removeClass("select2-drop-above")},open:function(){if(!this.shouldOpen()){return false}this.opening();return true},opening:function(){var U=this.containerId,O="scroll."+U,R="resize."+U,Q="orientationchange."+U,P,T;this.container.addClass("select2-dropdown-open").addClass("select2-container-active");this.clearDropdownAlignmentPreference();if(this.dropdown[0]!==this.body().children().last()[0]){this.dropdown.detach().appendTo(this.body())}P=D("#select2-drop-mask");if(P.length==0){P=D(document.createElement("div"));P.attr("id","select2-drop-mask").attr("class","select2-drop-mask");P.hide();P.appendTo(this.body());P.on("mousedown touchstart click",function(W){var X=D("#select2-drop"),V;if(X.length>0){V=X.data("select2");if(V.opts.selectOnBlur){V.selectHighlighted({noFocus:true})}V.close({focus:false});W.preventDefault();W.stopPropagation()}})}if(this.dropdown.prev()[0]!==P[0]){this.dropdown.before(P)}D("#select2-drop").removeAttr("id");this.dropdown.attr("id","select2-drop");P.show();this.positionDropdown();this.dropdown.show();this.positionDropdown();this.dropdown.addClass("select2-drop-active");var S=this;this.container.parents().add(window).each(function(){D(this).on(R+" "+O+" "+Q,function(V){S.positionDropdown()})})},close:function(){if(!this.opened()){return}var R=this.containerId,O="scroll."+R,Q="resize."+R,P="orientationchange."+R;this.container.parents().add(window).each(function(){D(this).off(O).off(Q).off(P)});this.clearDropdownAlignmentPreference();D("#select2-drop-mask").hide();this.dropdown.removeAttr("id");this.dropdown.hide();this.container.removeClass("select2-dropdown-open");this.results.empty();this.clearSearch();this.search.removeClass("select2-active");this.opts.element.trigger(D.Event("select2-close"))},externalSearch:function(O){this.open();this.search.val(O);this.updateResults(false)},clearSearch:function(){},getMaximumSelectionSize:function(){return C(this.opts.maximumSelectionSize)},ensureHighlightVisible:function(){var R=this.results,Q,O,V,U,S,T,P;O=this.highlight();if(O<0){return}if(O==0){R.scrollTop(0);return}Q=this.findHighlightableChoices().find(".select2-result-label");V=D(Q[O]);U=V.offset().top+V.outerHeight(true);if(O===Q.length-1){P=R.find("li.select2-more-results");if(P.length>0){U=P.offset().top+P.outerHeight(true)}}S=R.offset().top+R.outerHeight(true);if(U>S){R.scrollTop(R.scrollTop()+(U-S))}T=V.offset().top-R.offset().top;if(T<0&&V.css("display")!="none"){R.scrollTop(R.scrollTop()+T)}},findHighlightableChoices:function(){return this.results.find(".select2-result-selectable:not(.select2-selected):not(.select2-disabled)")},moveHighlight:function(R){var Q=this.findHighlightableChoices(),P=this.highlight();while(P>-1&&P<Q.length){P+=R;var O=D(Q[P]);if(O.hasClass("select2-result-selectable")&&!O.hasClass("select2-disabled")&&!O.hasClass("select2-selected")){this.highlight(P);break}}},highlight:function(P){var R=this.findHighlightableChoices(),O,Q;if(arguments.length===0){return q(R.filter(".select2-highlighted")[0],R.get())}if(P>=R.length){P=R.length-1}if(P<0){P=0}this.removeHighlight();O=D(R[P]);O.addClass("select2-highlighted");this.ensureHighlightVisible();Q=O.data("select2-data");if(Q){this.opts.element.trigger({type:"select2-highlight",val:this.id(Q),choice:Q})}},removeHighlight:function(){this.results.find(".select2-highlighted").removeClass("select2-highlighted")},countSelectableResults:function(){return this.findHighlightableChoices().length},highlightUnderEvent:function(P){var O=D(P.target).closest(".select2-result-selectable");if(O.length>0&&!O.is(".select2-highlighted")){var Q=this.findHighlightableChoices();this.highlight(Q.index(O))}else{if(O.length==0){this.removeHighlight()}}},loadMoreIfNeeded:function(){var S=this.results,R=S.find("li.select2-more-results"),V,U=-1,T=this.resultsPage+1,O=this,Q=this.search.val(),P=this.context;if(R.length===0){return}V=R.offset().top-S.offset().top-S.height();if(V<=this.opts.loadMorePadding){R.addClass("select2-active");this.opts.query({element:this.opts.element,term:Q,page:T,context:P,matcher:this.opts.matcher,callback:this.bind(function(W){if(!O.opened()){return}O.opts.populateResults.call(this,S,W.results,{term:Q,page:T,context:P});O.postprocessResults(W,false,false);if(W.more===true){R.detach().appendTo(S).text(O.opts.formatLoadMore(T+1));window.setTimeout(function(){O.loadMoreIfNeeded()},10)}else{R.remove()}O.positionDropdown();O.resultsPage=T;O.context=W.context;this.opts.element.trigger({type:"select2-loaded",items:W})})})}},tokenize:function(){},updateResults:function(W){var aa=this.search,U=this.results,O=this.opts,T,Z=this,X,S=aa.val(),Q=D.data(this.container,"select2-last-term"),Y;if(W!==true&&Q&&t(S,Q)){return}D.data(this.container,"select2-last-term",S);if(W!==true&&(this.showSearchInput===false||!this.opened())){return}function V(){aa.removeClass("select2-active");Z.positionDropdown()}function P(ab){U.html(ab);V()}Y=++this.queryCount;var R=this.getMaximumSelectionSize();if(R>=1){T=this.data();if(D.isArray(T)&&T.length>=R&&y(O.formatSelectionTooBig,"formatSelectionTooBig")){P("<li class='select2-selection-limit'>"+O.formatSelectionTooBig(R)+"</li>");return}}if(aa.val().length<O.minimumInputLength){if(y(O.formatInputTooShort,"formatInputTooShort")){P("<li class='select2-no-results'>"+O.formatInputTooShort(aa.val(),O.minimumInputLength)+"</li>")}else{P("")}if(W&&this.showSearch){this.showSearch(true)}return}if(O.maximumInputLength&&aa.val().length>O.maximumInputLength){if(y(O.formatInputTooLong,"formatInputTooLong")){P("<li class='select2-no-results'>"+O.formatInputTooLong(aa.val(),O.maximumInputLength)+"</li>")}else{P("")}return}if(O.formatSearching&&this.findHighlightableChoices().length===0){P("<li class='select2-searching'>"+O.formatSearching()+"</li>")}aa.addClass("select2-active");this.removeHighlight();X=this.tokenize();if(X!=m&&X!=null){aa.val(X)}this.resultsPage=1;O.query({element:O.element,term:aa.val(),page:this.resultsPage,context:null,matcher:O.matcher,callback:this.bind(function(ac){var ab;if(Y!=this.queryCount){return}if(!this.opened()){this.search.removeClass("select2-active");return}this.context=(ac.context===m)?null:ac.context;if(this.opts.createSearchChoice&&aa.val()!==""){ab=this.opts.createSearchChoice.call(Z,aa.val(),ac.results);if(ab!==m&&ab!==null&&Z.id(ab)!==m&&Z.id(ab)!==null){if(D(ac.results).filter(function(){return t(Z.id(this),Z.id(ab))}).length===0){ac.results.unshift(ab)}}}if(ac.results.length===0&&y(O.formatNoMatches,"formatNoMatches")){P("<li class='select2-no-results'>"+O.formatNoMatches(aa.val())+"</li>");return}U.empty();Z.opts.populateResults.call(this,U,ac.results,{term:aa.val(),page:this.resultsPage,context:null});if(ac.more===true&&y(O.formatLoadMore,"formatLoadMore")){U.append("<li class='select2-more-results'>"+Z.opts.escapeMarkup(O.formatLoadMore(this.resultsPage))+"</li>");window.setTimeout(function(){Z.loadMoreIfNeeded()},10)}this.postprocessResults(ac,W);V();this.opts.element.trigger({type:"select2-loaded",items:ac})})})},cancel:function(){this.close()},blur:function(){if(this.opts.selectOnBlur){this.selectHighlighted({noFocus:true})}this.close();this.container.removeClass("select2-container-active");if(this.search[0]===document.activeElement){this.search.blur()}this.clearSearch();this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus")},focusSearch:function(){I(this.search)},selectHighlighted:function(P){var O=this.highlight(),Q=this.results.find(".select2-highlighted"),R=Q.closest(".select2-result").data("select2-data");if(R){this.highlight(O);this.onSelect(R,P)}else{if(P&&P.noFocus){this.close()}}},getPlaceholder:function(){var O;return this.opts.element.attr("placeholder")||this.opts.element.attr("data-placeholder")||this.opts.element.data("placeholder")||this.opts.placeholder||((O=this.getPlaceholderOption())!==m?O.text():m)},getPlaceholderOption:function(){if(this.select){var O=this.select.children().first();if(this.opts.placeholderOption!==m){return(this.opts.placeholderOption==="first"&&O)||(typeof this.opts.placeholderOption==="function"&&this.opts.placeholderOption(this.select))}else{if(O.text()===""&&O.val()===""){return O}}}},initContainerWidth:function(){function P(){var T,R,U,S,Q;if(this.opts.width==="off"){return null}else{if(this.opts.width==="element"){return this.opts.element.outerWidth(false)===0?"auto":this.opts.element.outerWidth(false)+"px"}else{if(this.opts.width==="copy"||this.opts.width==="resolve"){T=this.opts.element.attr("style");if(T!==m){R=T.split(";");for(S=0,Q=R.length;S<Q;S=S+1){U=R[S].replace(/\s/g,"").match(/[^-]width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i);if(U!==null&&U.length>=1){return U[1]}}}if(this.opts.width==="resolve"){T=this.opts.element.css("width");if(T.indexOf("%")>0){return T}return(this.opts.element.outerWidth(false)===0?"auto":this.opts.element.outerWidth(false)+"px")}return null}else{if(D.isFunction(this.opts.width)){return this.opts.width()}else{return this.opts.width}}}}}var O=P.call(this);if(O!==null){this.container.css("width",O)}}});x=L(N,{createContainer:function(){var O=D(document.createElement("div")).attr({"class":"select2-container"}).html(["<a href='javascript:void(0)' onclick='return false;' class='select2-choice' tabindex='-1'>"," <span class='select2-chosen'> </span><abbr class='select2-search-choice-close'></abbr>"," <span class='select2-arrow'><b></b></span>","</a>","<input class='select2-focusser select2-offscreen' type='text'/>","<div class='select2-drop select2-display-none'>"," <div class='select2-search'>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'/>"," </div>"," <ul class='select2-results'>"," </ul>","</div>"].join(""));return O},enableInterface:function(){if(this.parent.enableInterface.apply(this,arguments)){this.focusser.prop("disabled",!this.isInterfaceEnabled())}},opening:function(){var Q,P,O;if(this.opts.minimumResultsForSearch>=0){this.showSearch(true)}this.parent.opening.apply(this,arguments);if(this.showSearchInput!==false){this.search.val(this.focusser.val())}this.search.focus();Q=this.search.get(0);if(Q.createTextRange){P=Q.createTextRange();P.collapse(false);P.select()}else{if(Q.setSelectionRange){O=this.search.val().length;Q.setSelectionRange(O,O)}}if(this.search.val()===""){if(this.nextSearchTerm!=m){this.search.val(this.nextSearchTerm);this.search.select()}}this.focusser.prop("disabled",true).val("");this.updateResults(true);this.opts.element.trigger(D.Event("select2-open"))},close:function(O){if(!this.opened()){return}this.parent.close.apply(this,arguments);O=O||{focus:true};this.focusser.removeAttr("disabled");if(O.focus){this.focusser.focus()}},focus:function(){if(this.opened()){this.close()}else{this.focusser.removeAttr("disabled");this.focusser.focus()}},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments);this.focusser.removeAttr("disabled");this.focusser.focus()},destroy:function(){D("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id"));this.parent.destroy.apply(this,arguments)},initContainer:function(){var P,O=this.container,Q=this.dropdown;if(this.opts.minimumResultsForSearch<0){this.showSearch(false)}else{this.showSearch(true)}this.selection=P=O.find(".select2-choice");this.focusser=O.find(".select2-focusser");this.focusser.attr("id","s2id_autogen"+a());D("label[for='"+this.opts.element.attr("id")+"']").attr("for",this.focusser.attr("id"));this.focusser.attr("tabindex",this.elementTabIndex);this.search.on("keydown",this.bind(function(R){if(!this.isInterfaceEnabled()){return}if(R.which===K.PAGE_UP||R.which===K.PAGE_DOWN){A(R);return}switch(R.which){case K.UP:case K.DOWN:this.moveHighlight((R.which===K.UP)?-1:1);A(R);return;case K.ENTER:this.selectHighlighted();A(R);return;case K.TAB:if(this.opts.selectOnBlur){this.selectHighlighted({noFocus:true})}return;case K.ESC:this.cancel(R);A(R);return}}));this.search.on("blur",this.bind(function(R){if(document.activeElement===this.body().get(0)){window.setTimeout(this.bind(function(){this.search.focus()}),0)}}));this.focusser.on("keydown",this.bind(function(R){if(!this.isInterfaceEnabled()){return}if(R.which===K.TAB||K.isControl(R)||K.isFunctionKey(R)||R.which===K.ESC){return}if(this.opts.openOnEnter===false&&R.which===K.ENTER){A(R);return}if(R.which==K.DOWN||R.which==K.UP||(R.which==K.ENTER&&this.opts.openOnEnter)){if(R.altKey||R.ctrlKey||R.shiftKey||R.metaKey){return}this.open();A(R);return}if(R.which==K.DELETE||R.which==K.BACKSPACE){if(this.opts.allowClear){this.clear()}A(R);return}}));F(this.focusser);this.focusser.on("keyup-change input",this.bind(function(R){if(this.opts.minimumResultsForSearch>=0){R.stopPropagation();if(this.opened()){return}this.open()}}));P.on("mousedown","abbr",this.bind(function(R){if(!this.isInterfaceEnabled()){return}this.clear();b(R);this.close();this.selection.focus()}));P.on("mousedown",this.bind(function(R){if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}if(this.opened()){this.close()}else{if(this.isInterfaceEnabled()){this.open()}}A(R)}));Q.on("mousedown",this.bind(function(){this.search.focus()}));P.on("focus",this.bind(function(R){A(R)}));this.focusser.on("focus",this.bind(function(){if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){if(!this.opened()){this.container.removeClass("select2-container-active");this.opts.element.trigger(D.Event("select2-blur"))}}));this.search.on("focus",this.bind(function(){if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}this.container.addClass("select2-container-active")}));this.initContainerWidth();this.opts.element.addClass("select2-offscreen");this.setPlaceholder()},clear:function(P){var Q=this.selection.data("select2-data");if(Q){var O=this.getPlaceholderOption();this.opts.element.val(O?O.val():"");this.selection.find(".select2-chosen").empty();this.selection.removeData("select2-data");this.setPlaceholder();if(P!==false){this.opts.element.trigger({type:"select2-removed",val:this.id(Q),choice:Q});this.triggerChange({removed:Q})}}},initSelection:function(){var P;if(this.isPlaceholderOptionSelected()){this.updateSelection(null);this.close();this.setPlaceholder()}else{var O=this;this.opts.initSelection.call(null,this.opts.element,function(Q){if(Q!==m&&Q!==null){O.updateSelection(Q);O.close();O.setPlaceholder()}})}},isPlaceholderOptionSelected:function(){var O;if(!this.opts.placeholder){return false}return((O=this.getPlaceholderOption())!==m&&O.is(":selected"))||(this.opts.element.val()==="")||(this.opts.element.val()===m)||(this.opts.element.val()===null)},prepareOpts:function(){var P=this.parent.prepareOpts.apply(this,arguments),O=this;if(P.element.get(0).tagName.toLowerCase()==="select"){P.initSelection=function(Q,S){var R=Q.find(":selected");S(O.optionToData(R))}}else{if("data" in P){P.initSelection=P.initSelection||function(R,T){var S=R.val();var Q=null;P.query({matcher:function(U,X,V){var W=t(S,P.id(V));if(W){Q=V}return W},callback:!D.isFunction(T)?D.noop:function(){T(Q)}})}}}return P},getPlaceholder:function(){if(this.select){if(this.getPlaceholderOption()===m){return m}}return this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var O=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&O!==m){if(this.select&&this.getPlaceholderOption()===m){return}this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(O));this.selection.addClass("select2-default");this.container.removeClass("select2-allowclear")}},postprocessResults:function(T,P,S){var R=0,O=this,U=true;this.findHighlightableChoices().each2(function(V,W){if(t(O.id(W.data("select2-data")),O.opts.element.val())){R=V;return false}});if(S!==false){if(P===true&&R>=0){this.highlight(R)}else{this.highlight(0)}}if(P===true){var Q=this.opts.minimumResultsForSearch;if(Q>=0){this.showSearch(r(T.results)>=Q)}}},showSearch:function(O){if(this.showSearchInput===O){return}this.showSearchInput=O;this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!O);this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!O);D(this.dropdown,this.container).toggleClass("select2-with-searchbox",O)},onSelect:function(Q,P){if(!this.triggerSelect(Q)){return}var O=this.opts.element.val(),R=this.data();this.opts.element.val(this.id(Q));this.updateSelection(Q);this.opts.element.trigger({type:"select2-selected",val:this.id(Q),choice:Q});this.nextSearchTerm=this.opts.nextSearchTerm(Q,this.search.val());this.close();if(!P||!P.noFocus){this.selection.focus()}if(!t(O,this.id(Q))){this.triggerChange({added:Q,removed:R})}},updateSelection:function(R){var P=this.selection.find(".select2-chosen"),Q,O;this.selection.data("select2-data",R);P.empty();if(R!==null){Q=this.opts.formatSelection(R,P,this.opts.escapeMarkup)}if(Q!==m){P.append(Q)}O=this.opts.formatSelectionCssClass(R,P);if(O!==m){P.addClass(O)}this.selection.removeClass("select2-default");if(this.opts.allowClear&&this.getPlaceholder()!==m){this.container.addClass("select2-allowclear")}},val:function(){var S,P=false,Q=null,O=this,R=this.data();if(arguments.length===0){return this.opts.element.val()}S=arguments[0];if(arguments.length>1){P=arguments[1]}if(this.select){this.select.val(S).find(":selected").each2(function(T,U){Q=O.optionToData(U);return false});this.updateSelection(Q);this.setPlaceholder();if(P){this.triggerChange({added:Q,removed:R})}}else{if(!S&&S!==0){this.clear(P);return}if(this.opts.initSelection===m){throw new Error("cannot call val() if initSelection() is not defined")}this.opts.element.val(S);this.opts.initSelection(this.opts.element,function(T){O.opts.element.val(!T?"":O.id(T));O.updateSelection(T);O.setPlaceholder();if(P){O.triggerChange({added:T,removed:R})}})}},clearSearch:function(){this.search.val("");this.focusser.val("")},data:function(Q){var P,O=false;if(arguments.length===0){P=this.selection.data("select2-data");if(P==m){P=null}return P}else{if(arguments.length>1){O=arguments[1]}if(!Q){this.clear(O)}else{P=this.data();this.opts.element.val(!Q?"":this.id(Q));this.updateSelection(Q);if(O){this.triggerChange({added:Q,removed:P})}}}}});c=L(N,{createContainer:function(){var O=D(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["<ul class='select2-choices'>"," <li class='select2-search-field'>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>"," </li>","</ul>","<div class='select2-drop select2-drop-multi select2-display-none'>"," <ul class='select2-results'>"," </ul>","</div>"].join(""));return O},prepareOpts:function(){var P=this.parent.prepareOpts.apply(this,arguments),O=this;if(P.element.get(0).tagName.toLowerCase()==="select"){P.initSelection=function(Q,S){var R=[];Q.find(":selected").each2(function(T,U){R.push(O.optionToData(U))});S(R)}}else{if("data" in P){P.initSelection=P.initSelection||function(Q,T){var R=i(Q.val(),P.separator);var S=[];P.query({matcher:function(U,X,V){var W=D.grep(R,function(Y){return t(Y,P.id(V))}).length;if(W){S.push(V)}return W},callback:!D.isFunction(T)?D.noop:function(){var U=[];for(var X=0;X<R.length;X++){var Y=R[X];for(var W=0;W<S.length;W++){var V=S[W];if(t(Y,P.id(V))){U.push(V);S.splice(W,1);break}}}T(U)}})}}}return P},selectChoice:function(O){var P=this.container.find(".select2-search-choice-focus");if(P.length&&O&&O[0]==P[0]){}else{if(P.length){this.opts.element.trigger("choice-deselected",P)}P.removeClass("select2-search-choice-focus");if(O&&O.length){this.close();O.addClass("select2-search-choice-focus");this.opts.element.trigger("choice-selected",O)}}},destroy:function(){D("label[for='"+this.search.attr("id")+"']").attr("for",this.opts.element.attr("id"));this.parent.destroy.apply(this,arguments)},initContainer:function(){var O=".select2-choices",P;this.searchContainer=this.container.find(".select2-search-field");this.selection=P=this.container.find(O);var Q=this;this.selection.on("click",".select2-search-choice",function(R){Q.search[0].focus();Q.selectChoice(D(this))});this.search.attr("id","s2id_autogen"+a());D("label[for='"+this.opts.element.attr("id")+"']").attr("for",this.search.attr("id"));this.search.on("input paste",this.bind(function(){if(!this.isInterfaceEnabled()){return}if(!this.opened()){this.open()}}));this.search.attr("tabindex",this.elementTabIndex);this.keydowns=0;this.search.on("keydown",this.bind(function(V){if(!this.isInterfaceEnabled()){return}++this.keydowns;var T=P.find(".select2-search-choice-focus");var U=T.prev(".select2-search-choice:not(.select2-locked)");var S=T.next(".select2-search-choice:not(.select2-locked)");var W=f(this.search);if(T.length&&(V.which==K.LEFT||V.which==K.RIGHT||V.which==K.BACKSPACE||V.which==K.DELETE||V.which==K.ENTER)){var R=T;if(V.which==K.LEFT&&U.length){R=U}else{if(V.which==K.RIGHT){R=S.length?S:null}else{if(V.which===K.BACKSPACE){this.unselect(T.first());this.search.width(10);R=U.length?U:S}else{if(V.which==K.DELETE){this.unselect(T.first());this.search.width(10);R=S.length?S:null}else{if(V.which==K.ENTER){R=null}}}}}this.selectChoice(R);A(V);if(!R||!R.length){this.open()}return}else{if(((V.which===K.BACKSPACE&&this.keydowns==1)||V.which==K.LEFT)&&(W.offset==0&&!W.length)){this.selectChoice(P.find(".select2-search-choice:not(.select2-locked)").last());A(V);return}else{this.selectChoice(null)}}if(this.opened()){switch(V.which){case K.UP:case K.DOWN:this.moveHighlight((V.which===K.UP)?-1:1);A(V);return;case K.ENTER:this.selectHighlighted();A(V);return;case K.TAB:if(this.opts.selectOnBlur){this.selectHighlighted({noFocus:true})}this.close();return;case K.ESC:this.cancel(V);A(V);return}}if(V.which===K.TAB||K.isControl(V)||K.isFunctionKey(V)||V.which===K.BACKSPACE||V.which===K.ESC){return}if(V.which===K.ENTER){if(this.opts.openOnEnter===false){return}else{if(V.altKey||V.ctrlKey||V.shiftKey||V.metaKey){return}}}this.open();if(V.which===K.PAGE_UP||V.which===K.PAGE_DOWN){A(V)}if(V.which===K.ENTER){A(V)}}));this.search.on("keyup",this.bind(function(R){this.keydowns=0;this.resizeSearch()}));this.search.on("blur",this.bind(function(R){this.container.removeClass("select2-container-active");this.search.removeClass("select2-focused");this.selectChoice(null);if(!this.opened()){this.clearSearch()}R.stopImmediatePropagation();this.opts.element.trigger(D.Event("select2-blur"))}));this.container.on("click",O,this.bind(function(R){if(!this.isInterfaceEnabled()){return}if(D(R.target).closest(".select2-search-choice").length>0){return}this.selectChoice(null);this.clearPlaceholder();if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}this.open();this.focusSearch();R.preventDefault()}));this.container.on("focus",O,this.bind(function(){if(!this.isInterfaceEnabled()){return}if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}this.container.addClass("select2-container-active");this.dropdown.addClass("select2-drop-active");this.clearPlaceholder()}));this.initContainerWidth();this.opts.element.addClass("select2-offscreen");this.clearSearch()},enableInterface:function(){if(this.parent.enableInterface.apply(this,arguments)){this.search.prop("disabled",!this.isInterfaceEnabled())}},initSelection:function(){var P;if(this.opts.element.val()===""&&this.opts.element.text()===""){this.updateSelection([]);this.close();this.clearSearch()}if(this.select||this.opts.element.val()!==""){var O=this;this.opts.initSelection.call(null,this.opts.element,function(Q){if(Q!==m&&Q!==null){O.updateSelection(Q);O.close();O.clearSearch()}})}},clearSearch:function(){var P=this.getPlaceholder(),O=this.getMaxSearchWidth();if(P!==m&&this.getVal().length===0&&this.search.hasClass("select2-focused")===false){this.search.val(P).addClass("select2-default");this.search.width(O>0?O:this.container.css("width"))}else{this.search.val("").width(10)}},clearPlaceholder:function(){if(this.search.hasClass("select2-default")){this.search.val("").removeClass("select2-default")}},opening:function(){this.clearPlaceholder();this.resizeSearch();this.parent.opening.apply(this,arguments);this.focusSearch();this.updateResults(true);this.search.focus();this.opts.element.trigger(D.Event("select2-open"))},close:function(){if(!this.opened()){return}this.parent.close.apply(this,arguments)},focus:function(){this.close();this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(R){var Q=[],P=[],O=this;D(R).each(function(){if(q(O.id(this),Q)<0){Q.push(O.id(this));P.push(this)}});R=P;this.selection.find(".select2-search-choice").remove();D(R).each(function(){O.addSelectedChoice(this)});O.postprocessResults()},tokenize:function(){var O=this.search.val();O=this.opts.tokenizer.call(this,O,this.data(),this.bind(this.onSelect),this.opts);if(O!=null&&O!=m){this.search.val(O);if(O.length>0){this.open()}}},onSelect:function(P,O){if(!this.triggerSelect(P)){return}this.addSelectedChoice(P);this.opts.element.trigger({type:"selected",val:this.id(P),choice:P});if(this.select||!this.opts.closeOnSelect){this.postprocessResults(P,false,this.opts.closeOnSelect===true)}if(this.opts.closeOnSelect){this.close();this.search.width(10)}else{if(this.countSelectableResults()>0){this.search.width(10);this.resizeSearch();if(this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()){this.updateResults(true)}this.positionDropdown()}else{this.close();this.search.width(10)}}this.triggerChange({added:P});if(!O||!O.noFocus){this.focusSearch()}},cancel:function(){this.close();this.focusSearch()},addSelectedChoice:function(S){var U=!S.locked,Q=D("<li class='select2-search-choice'><div></div><a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a></li>"),V=D("<li class='select2-search-choice select2-locked'><div></div></li>");var R=U?Q:V,O=this.id(S),P=this.getVal(),T,W;T=this.opts.formatSelection(S,R.find("div"),this.opts.escapeMarkup);if(T!=m){R.find("div").replaceWith("<div>"+T+"</div>")}W=this.opts.formatSelectionCssClass(S,R.find("div"));if(W!=m){R.addClass(W)}if(U){R.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(X){if(!this.isInterfaceEnabled()){return}D(X.target).closest(".select2-search-choice").fadeOut("fast",this.bind(function(){this.unselect(D(X.target));this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");this.close();this.focusSearch()})).dequeue();A(X)})).on("focus",this.bind(function(){if(!this.isInterfaceEnabled()){return}this.container.addClass("select2-container-active");this.dropdown.addClass("select2-drop-active")}))}R.data("select2-data",S);R.insertBefore(this.searchContainer);P.push(O);this.setVal(P)},unselect:function(P){var R=this.getVal(),Q,O;P=P.closest(".select2-search-choice");if(P.length===0){throw"Invalid argument: "+P+". Must be .select2-search-choice"}Q=P.data("select2-data");if(!Q){return}O=q(this.id(Q),R);if(O>=0){R.splice(O,1);this.setVal(R);if(this.select){this.postprocessResults()}}P.remove();this.opts.element.trigger({type:"removed",val:this.id(Q),choice:Q});this.triggerChange({removed:Q})},postprocessResults:function(S,P,R){var T=this.getVal(),U=this.results.find(".select2-result"),Q=this.results.find(".select2-result-with-children"),O=this;U.each2(function(W,V){var X=O.id(V.data("select2-data"));if(q(X,T)>=0){V.addClass("select2-selected");V.find(".select2-result-selectable").addClass("select2-selected")}});Q.each2(function(W,V){if(!V.is(".select2-result-selectable")&&V.find(".select2-result-selectable:not(.select2-selected)").length===0){V.addClass("select2-selected")}});if(this.highlight()==-1&&R!==false){O.highlight(0)}if(!this.opts.createSearchChoice&&!U.filter(".select2-result:not(.select2-selected)").length>0){if(!S||S&&!S.more&&this.results.find(".select2-no-results").length===0){if(y(O.opts.formatNoMatches,"formatNoMatches")){this.results.append("<li class='select2-no-results'>"+O.opts.formatNoMatches(O.search.val())+"</li>")}}}},getMaxSearchWidth:function(){return this.selection.width()-h(this.search)},resizeSearch:function(){var T,R,Q,O,P,S=h(this.search);T=n(this.search)+10;R=this.search.offset().left;Q=this.selection.width();O=this.selection.offset().left;P=Q-(R-O)-S;if(P<T){P=Q-S}if(P<40){P=Q-S}if(P<=0){P=T}this.search.width(P)},getVal:function(){var O;if(this.select){O=this.select.val();return O===null?[]:O}else{O=this.opts.element.val();return i(O,this.opts.separator)}},setVal:function(P){var O;if(this.select){this.select.val(P)}else{O=[];D(P).each(function(){if(q(this,O)<0){O.push(this)}});this.opts.element.val(O.length===0?"":O.join(this.opts.separator))}},buildChangeDetails:function(O,R){var R=R.slice(0),O=O.slice(0);for(var Q=0;Q<R.length;Q++){for(var P=0;P<O.length;P++){if(t(this.opts.id(R[Q]),this.opts.id(O[P]))){R.splice(Q,1);Q--;O.splice(P,1);P--}}}return{added:R,removed:O}},val:function(S,P){var R,O=this,Q;if(arguments.length===0){return this.getVal()}R=this.data();if(!R.length){R=[]}if(!S&&S!==0){this.opts.element.val("");this.updateSelection([]);this.clearSearch();if(P){this.triggerChange({added:this.data(),removed:R})}return}this.setVal(S);if(this.select){this.opts.initSelection(this.select,this.bind(this.updateSelection));if(P){this.triggerChange(this.buildChangeDetails(R,this.data()))}}else{if(this.opts.initSelection===m){throw new Error("val() cannot be called if initSelection() is not defined")}this.opts.initSelection(this.opts.element,function(U){var T=D.map(U,O.id);O.setVal(T);O.updateSelection(U);O.clearSearch();if(P){O.triggerChange(O.buildChangeDetails(R,this.data()))}})}this.clearSearch()},onSortStart:function(){if(this.select){throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.")}this.search.width(0);this.searchContainer.hide()},onSortEnd:function(){var P=[],O=this;this.searchContainer.show();this.searchContainer.appendTo(this.searchContainer.parent());this.resizeSearch();this.selection.find(".select2-search-choice").each(function(){P.push(O.opts.id(D(this).data("select2-data")))});this.setVal(P);this.triggerChange()},data:function(Q,R){var P=this,S,O;if(arguments.length===0){return this.selection.find(".select2-search-choice").map(function(){return D(this).data("select2-data")}).get()}else{O=this.data();if(!Q){Q=[]}S=D.map(Q,function(T){return P.opts.id(T)});this.setVal(S);this.updateSelection(Q);this.clearSearch();if(R){this.triggerChange(this.buildChangeDetails(O,this.data()))}}}});D.fn.select2=function(){var T=Array.prototype.slice.call(arguments,0),P,S,O,V,X,W=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],U=["opened","isFocused","container","dropdown"],Q=["val","data"],R={search:"externalSearch"};this.each(function(){if(T.length===0||typeof(T[0])==="object"){P=T.length===0?{}:D.extend({},T[0]);P.element=D(this);if(P.element.get(0).tagName.toLowerCase()==="select"){X=P.element.prop("multiple")}else{X=P.multiple||false;if("tags" in P){P.multiple=X=true}}S=X?new c():new x();S.init(P)}else{if(typeof(T[0])==="string"){if(q(T[0],W)<0){throw"Unknown method: "+T[0]}V=m;S=D(this).data("select2");if(S===m){return}O=T[0];if(O==="container"){V=S.container}else{if(O==="dropdown"){V=S.dropdown}else{if(R[O]){O=R[O]}V=S[O].apply(S,T.slice(1))}}if(q(T[0],U)>=0||(q(T[0],Q)&&T.length==1)){return false}}else{throw"Invalid arguments to select2 plugin: "+T}}});return(V===m)?this:V};D.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:true,openOnEnter:true,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(P,Q,S,O){var R=[];u(P.text,S.term,R,O);return R.join("")},formatSelection:function(Q,P,O){return Q?O(Q.text):m},sortResults:function(P,O,Q){return P},formatResultCssClass:function(O){return m},formatSelectionCssClass:function(P,O){return m},formatNoMatches:function(){return"No matches found"},formatInputTooShort:function(O,P){var Q=P-O.length;return"Please enter "+Q+" more character"+(Q==1?"":"s")},formatInputTooLong:function(P,O){var Q=P.length-O;return"Please delete "+Q+" character"+(Q==1?"":"s")},formatSelectionTooBig:function(O){return"You can only select "+O+" item"+(O==1?"":"s")},formatLoadMore:function(O){return"Loading more results..."},formatSearching:function(){return"Searching..."},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(O){return O.id},matcher:function(O,P){return e(""+P).toUpperCase().indexOf(e(""+O).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:g,escapeMarkup:G,blurOnChange:false,selectOnBlur:false,adaptContainerCssClass:function(O){return O},adaptDropdownCssClass:function(O){return null},nextSearchTerm:function(O,P){return m}};D.fn.select2.ajaxDefaults={transport:D.ajax,params:{type:"GET",cache:false,dataType:"json"}};window.Select2={query:{ajax:E,local:H,tags:z},util:{debounce:k,markMatch:u,escapeMarkup:G,stripDiacritics:e},"class":{"abstract":N,single:x,multi:c}}}(jQuery)); \ No newline at end of file +(function(a){if(typeof a.fn.each2=="undefined"){a.extend(a.fn,{each2:function(f){var d=a([0]),e=-1,b=this.length;while(++e<b&&(d.context=d[0]=this[e])&&f.call(d[0],e,d)!==false){}return this}})}})(jQuery);(function(D,m){if(window.Select2!==m){return}var K,N,x,c,a,p,o={x:0,y:0},v,w,K={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(O){O=O.which?O.which:O;switch(O){case K.LEFT:case K.RIGHT:case K.UP:case K.DOWN:return true}return false},isControl:function(P){var O=P.which;switch(O){case K.SHIFT:case K.CTRL:case K.ALT:return true}if(P.metaKey){return true}return false},isFunctionKey:function(O){O=O.which?O.which:O;return O>=112&&O<=123}},B="<div class='select2-measure-scrollbar'></div>",d={"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z"};v=D(document);a=(function(){var O=1;return function(){return O++}}());function e(R){var P,Q,O,S;if(!R||R.length<1){return R}P="";for(Q=0,O=R.length;Q<O;Q++){S=R.charAt(Q);P+=d[S]||S}return P}function q(Q,R){var P=0,O=R.length;for(;P<O;P=P+1){if(t(Q,R[P])){return P}}return -1}function M(){var O=D(B);O.appendTo("body");var P={width:O.width()-O[0].clientWidth,height:O.height()-O[0].clientHeight};O.remove();return P}function t(P,O){if(P===O){return true}if(P===m||O===m){return false}if(P===null||O===null){return false}if(P.constructor===String){return P+""===O+""}if(O.constructor===String){return O+""===P+""}return false}function i(P,R){var S,Q,O;if(P===null||P.length<1){return[]}S=P.split(R);for(Q=0,O=S.length;Q<O;Q=Q+1){S[Q]=D.trim(S[Q])}return S}function h(O){return O.outerWidth(false)-O.width()}function F(P){var O="keyup-change-value";P.on("keydown",function(){if(D.data(P,O)===m){D.data(P,O,P.val())}});P.on("keyup",function(){var Q=D.data(P,O);if(Q!==m&&P.val()!==Q){D.removeData(P,O);P.trigger("keyup-change")}})}v.on("mousemove",function(O){o.x=O.pageX;o.y=O.pageY});function J(O){O.on("mousemove",function(Q){var P=o;if(P===m||P.x!==Q.pageX||P.y!==Q.pageY){D(Q.target).trigger("mousemove-filtered",Q)}})}function k(R,P,O){O=O||m;var Q;return function(){var S=arguments;window.clearTimeout(Q);Q=window.setTimeout(function(){P.apply(O,S)},R)}}function s(Q){var O=false,P;return function(){if(O===false){P=Q();O=true}return P}}function l(O,Q){var P=k(O,function(R){Q.trigger("scroll-debounced",R)});Q.on("scroll",function(R){if(q(R.target,Q.get())>=0){P(R)}})}function I(O){if(O[0]===document.activeElement){return}window.setTimeout(function(){var Q=O[0],R=O.val().length,P;O.focus();if(O.is(":visible")&&Q===document.activeElement){if(Q.setSelectionRange){Q.setSelectionRange(R,R)}else{if(Q.createTextRange){P=Q.createTextRange();P.collapse(false);P.select()}}}},0)}function f(O){O=D(O)[0];var R=0;var P=0;if("selectionStart" in O){R=O.selectionStart;P=O.selectionEnd-R}else{if("selection" in document){O.focus();var Q=document.selection.createRange();P=document.selection.createRange().text.length;Q.moveStart("character",-O.value.length);R=Q.text.length-P}}return{offset:R,length:P}}function A(O){O.preventDefault();O.stopPropagation()}function b(O){O.preventDefault();O.stopImmediatePropagation()}function n(P){if(!p){var O=P[0].currentStyle||window.getComputedStyle(P[0],null);p=D(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:O.fontSize,fontFamily:O.fontFamily,fontStyle:O.fontStyle,fontWeight:O.fontWeight,letterSpacing:O.letterSpacing,textTransform:O.textTransform,whiteSpace:"nowrap"});p.attr("class","select2-sizer");D("body").append(p)}p.text(P.val());return p.width()}function j(P,T,O){var R,S=[],Q;R=P.attr("class");if(R){R=""+R;D(R.split(" ")).each2(function(){if(this.indexOf("select2-")===0){S.push(this)}})}R=T.attr("class");if(R){R=""+R;D(R.split(" ")).each2(function(){if(this.indexOf("select2-")!==0){Q=O(this);if(Q){S.push(this)}}})}P.attr("class",S.join(" "))}function u(T,S,Q,O){var R=e(T.toUpperCase()).indexOf(e(S.toUpperCase())),P=S.length;if(R<0){Q.push(O(T));return}Q.push(O(T.substring(0,R)));Q.push("<span class='select2-match'>");Q.push(O(T.substring(R,R+P)));Q.push("</span>");Q.push(O(T.substring(R+P,T.length)))}function G(O){var P={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(O).replace(/[&<>"'\/\\]/g,function(Q){return P[Q]})}function E(P){var S,Q=null,T=P.quietMillis||100,R=P.url,O=this;return function(U){window.clearTimeout(S);S=window.setTimeout(function(){var X=P.data,W=R,Z=P.transport||D.fn.select2.ajaxDefaults.transport,V={type:P.type||"GET",cache:P.cache||false,jsonpCallback:P.jsonpCallback||m,dataType:P.dataType||"json"},Y=D.extend({},D.fn.select2.ajaxDefaults.params,V);X=X?X.call(O,U.term,U.page,U.context):null;W=(typeof W==="function")?W.call(O,U.term,U.page,U.context):W;if(Q){Q.abort()}if(P.params){if(D.isFunction(P.params)){D.extend(Y,P.params.call(O))}else{D.extend(Y,P.params)}}D.extend(Y,{url:W,dataType:P.dataType,data:X,success:function(ab){var aa=P.results(ab,U.page);U.callback(aa)}});Q=Z.call(O,Y)},T)}}function H(P){var S=P,R,Q,T=function(U){return""+U.text};if(D.isArray(S)){Q=S;S={results:Q}}if(D.isFunction(S)===false){Q=S;S=function(){return Q}}var O=S();if(O.text){T=O.text;if(!D.isFunction(T)){R=O.text;T=function(U){return U[R]}}}return function(W){var V=W.term,U={results:[]},X;if(V===""){W.callback(S());return}X=function(Z,ab){var aa,Y;Z=Z[0];if(Z.children){aa={};for(Y in Z){if(Z.hasOwnProperty(Y)){aa[Y]=Z[Y]}}aa.children=[];D(Z.children).each2(function(ac,ad){X(ad,aa.children)});if(aa.children.length||W.matcher(V,T(aa),Z)){ab.push(aa)}}else{if(W.matcher(V,T(Z),Z)){ab.push(Z)}}};D(S().results).each2(function(Z,Y){X(Y,U.results)});W.callback(U)}}function z(P){var O=D.isFunction(P);return function(S){var R=S.term,Q={results:[]};D(O?P():P).each(function(){var T=this.text!==m,U=T?this.text:this;if(R===""||S.matcher(R,U)){Q.results.push(T?this:{id:this,text:this})}});S.callback(Q)}}function y(O,P){if(D.isFunction(O)){return true}if(!O){return false}throw new Error(P+" must be a function or a falsy value")}function C(O){return D.isFunction(O)?O():O}function r(O){var P=0;D.each(O,function(Q,R){if(R.children){P+=r(R.children)}else{P++}});return P}function g(W,X,U,O){var P=W,Y=false,R,V,S,Q,T;if(!O.createSearchChoice||!O.tokenSeparators||O.tokenSeparators.length<1){return m}while(true){V=-1;for(S=0,Q=O.tokenSeparators.length;S<Q;S++){T=O.tokenSeparators[S];V=W.indexOf(T);if(V>=0){break}}if(V<0){break}R=W.substring(0,V);W=W.substring(V+T.length);if(R.length>0){R=O.createSearchChoice.call(this,R,X);if(R!==m&&R!==null&&O.id(R)!==m&&O.id(R)!==null){Y=false;for(S=0,Q=X.length;S<Q;S++){if(t(O.id(R),O.id(X[S]))){Y=true;break}}if(!Y){U(R)}}}}if(P!==W){return W}}function L(O,P){var Q=function(){};Q.prototype=new O;Q.prototype.constructor=Q;Q.prototype.parent=O.prototype;Q.prototype=D.extend(Q.prototype,P);return Q}N=L(Object,{bind:function(P){var O=this;return function(){P.apply(O,arguments)}},init:function(S){var Q,P,T=".select2-results",R,O;this.opts=S=this.prepareOpts(S);this.id=S.id;if(S.element.data("select2")!==m&&S.element.data("select2")!==null){S.element.data("select2").destroy()}this.container=this.createContainer();this.containerId="s2id_"+(S.element.attr("id")||"autogen"+a());this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1");this.container.attr("id",this.containerId);this.body=s(function(){return S.element.closest("body")});j(this.container,this.opts.element,this.opts.adaptContainerCssClass);this.container.attr("style",S.element.attr("style"));this.container.css(C(S.containerCss));this.container.addClass(C(S.containerCssClass));this.elementTabIndex=this.opts.element.attr("tabindex");this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",A);this.container.data("select2",this);this.dropdown=this.container.find(".select2-drop");j(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass);this.dropdown.addClass(C(S.dropdownCssClass));this.dropdown.data("select2",this);this.dropdown.on("click",A);this.results=Q=this.container.find(T);this.search=P=this.container.find("input.select2-input");this.queryCount=0;this.resultsPage=0;this.context=null;this.initContainer();this.container.on("click",A);J(this.results);this.dropdown.on("mousemove-filtered touchstart touchmove touchend",T,this.bind(this.highlightUnderEvent));l(80,this.results);this.dropdown.on("scroll-debounced",T,this.bind(this.loadMoreIfNeeded));D(this.container).on("change",".select2-input",function(U){U.stopPropagation()});D(this.dropdown).on("change",".select2-input",function(U){U.stopPropagation()});if(D.fn.mousewheel){Q.mousewheel(function(Y,Z,W,V){var X=Q.scrollTop(),U;if(V>0&&X-V<=0){Q.scrollTop(0);A(Y)}else{if(V<0&&Q.get(0).scrollHeight-Q.scrollTop()+V<=Q.height()){Q.scrollTop(Q.get(0).scrollHeight-Q.height());A(Y)}}})}F(P);P.on("keyup-change input paste",this.bind(this.updateResults));P.on("focus",function(){P.addClass("select2-focused")});P.on("blur",function(){P.removeClass("select2-focused")});this.dropdown.on("mouseup",T,this.bind(function(U){if(D(U.target).closest(".select2-result-selectable").length>0){this.highlightUnderEvent(U);this.selectHighlighted(U)}}));this.dropdown.on("click mouseup mousedown",function(U){U.stopPropagation()});if(D.isFunction(this.opts.initSelection)){this.initSelection();this.monitorSource()}if(S.maximumInputLength!==null){this.search.attr("maxlength",S.maximumInputLength)}var R=S.element.prop("disabled");if(R===m){R=false}this.enable(!R);var O=S.element.prop("readonly");if(O===m){O=false}this.readonly(O);w=w||M();this.autofocus=S.element.prop("autofocus");S.element.prop("autofocus",false);if(this.autofocus){this.focus()}this.nextSearchTerm=m},destroy:function(){var P=this.opts.element,O=P.data("select2");this.close();if(this.propertyObserver){delete this.propertyObserver;this.propertyObserver=null}if(O!==m){O.container.remove();O.dropdown.remove();P.removeClass("select2-offscreen").removeData("select2").off(".select2").prop("autofocus",this.autofocus||false);if(this.elementTabIndex){P.attr({tabindex:this.elementTabIndex})}else{P.removeAttr("tabindex")}P.show()}},optionToData:function(O){if(O.is("option")){return{id:O.prop("value"),text:O.text(),element:O.get(),css:O.attr("class"),disabled:O.prop("disabled"),locked:t(O.attr("locked"),"locked")||t(O.data("locked"),true)}}else{if(O.is("optgroup")){return{text:O.attr("label"),children:[],element:O.get(),css:O.attr("class")}}}},prepareOpts:function(T){var R,P,O,S,Q=this;R=T.element;if(R.get(0).tagName.toLowerCase()==="select"){this.select=P=T.element}if(P){D.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in T){throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a <select> element.")}})}T=D.extend({},{populateResults:function(V,X,aa){var Z,Y,U,W,ab=this.opts.id;Z=function(ai,ac,ah){var aj,ae,ao,al,af,an,ad,am,ak,ag;ai=T.sortResults(ai,ac,aa);for(aj=0,ae=ai.length;aj<ae;aj=aj+1){ao=ai[aj];af=(ao.disabled===true);al=(!af)&&(ab(ao)!==m);an=ao.children&&ao.children.length>0;ad=D("<li></li>");ad.addClass("select2-results-dept-"+ah);ad.addClass("select2-result");ad.addClass(al?"select2-result-selectable":"select2-result-unselectable");if(af){ad.addClass("select2-disabled")}if(an){ad.addClass("select2-result-with-children")}ad.addClass(Q.opts.formatResultCssClass(ao));am=D(document.createElement("div"));am.addClass("select2-result-label");ag=T.formatResult(ao,am,aa,Q.opts.escapeMarkup);if(ag!==m){am.html(ag)}ad.append(am);if(an){ak=D("<ul></ul>");ak.addClass("select2-result-sub");Z(ao.children,ak,ah+1);ad.append(ak)}ad.data("select2-data",ao);ac.append(ad)}};Z(X,V,0)}},D.fn.select2.defaults,T);if(typeof(T.id)!=="function"){O=T.id;T.id=function(U){return U[O]}}if(D.isArray(T.element.data("select2Tags"))){if("tags" in T){throw"tags specified as both an attribute 'data-select2-tags' and in options of Select2 "+T.element.attr("id")}T.tags=T.element.data("select2Tags")}if(P){T.query=this.bind(function(Y){var X={results:[],more:false},W=Y.term,V,U,Z;Z=function(aa,ac){var ab;if(aa.is("option")){if(Y.matcher(W,aa.text(),aa)){ac.push(Q.optionToData(aa))}}else{if(aa.is("optgroup")){ab=Q.optionToData(aa);aa.children().each2(function(ad,ae){Z(ae,ab.children)});if(ab.children.length>0){ac.push(ab)}}}};V=R.children();if(this.getPlaceholder()!==m&&V.length>0){U=this.getPlaceholderOption();if(U){V=V.not(U)}}V.each2(function(aa,ab){Z(ab,X.results)});Y.callback(X)});T.id=function(U){return U.id};T.formatResultCssClass=function(U){return U.css}}else{if(!("query" in T)){if("ajax" in T){S=T.element.data("ajax-url");if(S&&S.length>0){T.ajax.url=S}T.query=E.call(T.element,T.ajax)}else{if("data" in T){T.query=H(T.data)}else{if("tags" in T){T.query=z(T.tags);if(T.createSearchChoice===m){T.createSearchChoice=function(U){return{id:D.trim(U),text:D.trim(U)}}}if(T.initSelection===m){T.initSelection=function(U,W){var V=[];D(i(U.val(),T.separator)).each(function(){var Y={id:this,text:this},X=T.tags;if(D.isFunction(X)){X=X()}D(X).each(function(){if(t(this.id,Y.id)){Y=this;return false}});V.push(Y)});W(V)}}}}}}}if(typeof(T.query)!=="function"){throw"query function not defined for Select2 "+T.element.attr("id")}return T},monitorSource:function(){var O=this.opts.element,P;O.on("change.select2",this.bind(function(Q){if(this.opts.element.data("select2-change-triggered")!==true){this.initSelection()}}));P=this.bind(function(){var S,R,Q=this;var T=O.prop("disabled");if(T===m){T=false}this.enable(!T);var R=O.prop("readonly");if(R===m){R=false}this.readonly(R);j(this.container,this.opts.element,this.opts.adaptContainerCssClass);this.container.addClass(C(this.opts.containerCssClass));j(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass);this.dropdown.addClass(C(this.opts.dropdownCssClass))});O.on("propertychange.select2 DOMAttrModified.select2",P);if(this.mutationCallback===m){this.mutationCallback=function(Q){Q.forEach(P)}}if(typeof WebKitMutationObserver!=="undefined"){if(this.propertyObserver){delete this.propertyObserver;this.propertyObserver=null}this.propertyObserver=new WebKitMutationObserver(this.mutationCallback);this.propertyObserver.observe(O.get(0),{attributes:true,subtree:false})}},triggerSelect:function(P){var O=D.Event("select2-selecting",{val:this.id(P),object:P});this.opts.element.trigger(O);return !O.isDefaultPrevented()},triggerChange:function(O){O=O||{};O=D.extend({},O,{type:"change",val:this.val()});this.opts.element.data("select2-change-triggered",true);this.opts.element.trigger(O);this.opts.element.data("select2-change-triggered",false);this.opts.element.click();if(this.opts.blurOnChange){this.opts.element.blur()}},isInterfaceEnabled:function(){return this.enabledInterface===true},enableInterface:function(){var O=this._enabled&&!this._readonly,P=!O;if(O===this.enabledInterface){return false}this.container.toggleClass("select2-container-disabled",P);this.close();this.enabledInterface=O;return true},enable:function(O){if(O===m){O=true}if(this._enabled===O){return}this._enabled=O;this.opts.element.prop("disabled",!O);this.enableInterface()},disable:function(){this.enable(false)},readonly:function(O){if(O===m){O=false}if(this._readonly===O){return false}this._readonly=O;this.opts.element.prop("readonly",O);this.enableInterface();return true},opened:function(){return this.container.hasClass("select2-dropdown-open")},positionDropdown:function(){var Q=this.dropdown,S=this.container.offset(),Z=this.container.outerHeight(false),aa=this.container.outerWidth(false),W=Q.outerHeight(false),P=D(window).scrollLeft()+D(window).width(),ad=D(window).scrollTop()+D(window).height(),R=S.top+Z,ab=S.left,O=R+W<=ad,U=(S.top-W)>=this.body().scrollTop(),X=Q.outerWidth(false),af=ab+X<=P,ae=Q.hasClass("select2-drop-above"),T,ac,V,Y;if(this.opts.dropdownAutoWidth){Y=D(".select2-results",Q)[0];Q.addClass("select2-drop-auto-width");Q.css("width","");X=Q.outerWidth(false)+(Y.scrollHeight===Y.clientHeight?0:w.width);X>aa?aa=X:X=aa;af=ab+X<=P}else{this.container.removeClass("select2-drop-auto-width")}if(this.body().css("position")!=="static"){T=this.body().offset();R-=T.top;ab-=T.left}if(ae){ac=true;if(!U&&O){ac=false}}else{ac=false;if(!O&&U){ac=true}}if(!af){ab=S.left+aa-X}if(ac){R=S.top-W;this.container.addClass("select2-drop-above");Q.addClass("select2-drop-above")}else{this.container.removeClass("select2-drop-above");Q.removeClass("select2-drop-above")}V=D.extend({top:R,left:ab,width:aa},C(this.opts.dropdownCss));Q.css(V)},shouldOpen:function(){var O;if(this.opened()){return false}if(this._enabled===false||this._readonly===true){return false}O=D.Event("select2-opening");this.opts.element.trigger(O);return !O.isDefaultPrevented()},clearDropdownAlignmentPreference:function(){this.container.removeClass("select2-drop-above");this.dropdown.removeClass("select2-drop-above")},open:function(){if(!this.shouldOpen()){return false}this.opening();return true},opening:function(){var U=this.containerId,O="scroll."+U,R="resize."+U,Q="orientationchange."+U,P,T;this.container.addClass("select2-dropdown-open").addClass("select2-container-active");this.clearDropdownAlignmentPreference();if(this.dropdown[0]!==this.body().children().last()[0]){this.dropdown.detach().appendTo(this.body())}P=D("#select2-drop-mask");if(P.length==0){P=D(document.createElement("div"));P.attr("id","select2-drop-mask").attr("class","select2-drop-mask");P.hide();P.appendTo(this.body());P.on("mousedown touchstart click",function(W){var X=D("#select2-drop"),V;if(X.length>0){V=X.data("select2");if(V.opts.selectOnBlur){V.selectHighlighted({noFocus:true})}V.close({focus:false});W.preventDefault();W.stopPropagation()}})}if(this.dropdown.prev()[0]!==P[0]){this.dropdown.before(P)}D("#select2-drop").removeAttr("id");this.dropdown.attr("id","select2-drop");P.show();this.positionDropdown();this.dropdown.show();this.positionDropdown();this.dropdown.addClass("select2-drop-active");var S=this;this.container.parents().add(window).each(function(){D(this).on(R+" "+O+" "+Q,function(V){S.positionDropdown()})})},close:function(){if(!this.opened()){return}var R=this.containerId,O="scroll."+R,Q="resize."+R,P="orientationchange."+R;this.container.parents().add(window).each(function(){D(this).off(O).off(Q).off(P)});this.clearDropdownAlignmentPreference();D("#select2-drop-mask").hide();this.dropdown.removeAttr("id");this.dropdown.hide();this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");this.results.empty();this.clearSearch();this.search.removeClass("select2-active");this.opts.element.trigger(D.Event("select2-close"))},externalSearch:function(O){this.open();this.search.val(O);this.updateResults(false)},clearSearch:function(){},getMaximumSelectionSize:function(){return C(this.opts.maximumSelectionSize)},ensureHighlightVisible:function(){var R=this.results,Q,O,V,U,S,T,P;O=this.highlight();if(O<0){return}if(O==0){R.scrollTop(0);return}Q=this.findHighlightableChoices().find(".select2-result-label");V=D(Q[O]);U=V.offset().top+V.outerHeight(true);if(O===Q.length-1){P=R.find("li.select2-more-results");if(P.length>0){U=P.offset().top+P.outerHeight(true)}}S=R.offset().top+R.outerHeight(true);if(U>S){R.scrollTop(R.scrollTop()+(U-S))}T=V.offset().top-R.offset().top;if(T<0&&V.css("display")!="none"){R.scrollTop(R.scrollTop()+T)}},findHighlightableChoices:function(){return this.results.find(".select2-result-selectable:not(.select2-disabled)")},moveHighlight:function(R){var Q=this.findHighlightableChoices(),P=this.highlight();while(P>-1&&P<Q.length){P+=R;var O=D(Q[P]);if(O.hasClass("select2-result-selectable")&&!O.hasClass("select2-disabled")&&!O.hasClass("select2-selected")){this.highlight(P);break}}},highlight:function(P){var R=this.findHighlightableChoices(),O,Q;if(arguments.length===0){return q(R.filter(".select2-highlighted")[0],R.get())}if(P>=R.length){P=R.length-1}if(P<0){P=0}this.removeHighlight();O=D(R[P]);O.addClass("select2-highlighted");this.ensureHighlightVisible();Q=O.data("select2-data");if(Q){this.opts.element.trigger({type:"select2-highlight",val:this.id(Q),choice:Q})}},removeHighlight:function(){this.results.find(".select2-highlighted").removeClass("select2-highlighted")},countSelectableResults:function(){return this.findHighlightableChoices().length},highlightUnderEvent:function(P){var O=D(P.target).closest(".select2-result-selectable");if(O.length>0&&!O.is(".select2-highlighted")){var Q=this.findHighlightableChoices();this.highlight(Q.index(O))}else{if(O.length==0){this.removeHighlight()}}},loadMoreIfNeeded:function(){var S=this.results,R=S.find("li.select2-more-results"),V,U=-1,T=this.resultsPage+1,O=this,Q=this.search.val(),P=this.context;if(R.length===0){return}V=R.offset().top-S.offset().top-S.height();if(V<=this.opts.loadMorePadding){R.addClass("select2-active");this.opts.query({element:this.opts.element,term:Q,page:T,context:P,matcher:this.opts.matcher,callback:this.bind(function(W){if(!O.opened()){return}O.opts.populateResults.call(this,S,W.results,{term:Q,page:T,context:P});O.postprocessResults(W,false,false);if(W.more===true){R.detach().appendTo(S).text(O.opts.formatLoadMore(T+1));window.setTimeout(function(){O.loadMoreIfNeeded()},10)}else{R.remove()}O.positionDropdown();O.resultsPage=T;O.context=W.context;this.opts.element.trigger({type:"select2-loaded",items:W})})})}},tokenize:function(){},updateResults:function(W){var aa=this.search,U=this.results,O=this.opts,T,Z=this,X,S=aa.val(),Q=D.data(this.container,"select2-last-term"),Y;if(W!==true&&Q&&t(S,Q)){return}D.data(this.container,"select2-last-term",S);if(W!==true&&(this.showSearchInput===false||!this.opened())){return}function V(){aa.removeClass("select2-active");Z.positionDropdown()}function P(ab){U.html(ab);V()}Y=++this.queryCount;var R=this.getMaximumSelectionSize();if(R>=1){T=this.data();if(D.isArray(T)&&T.length>=R&&y(O.formatSelectionTooBig,"formatSelectionTooBig")){P("<li class='select2-selection-limit'>"+O.formatSelectionTooBig(R)+"</li>");return}}if(aa.val().length<O.minimumInputLength){if(y(O.formatInputTooShort,"formatInputTooShort")){P("<li class='select2-no-results'>"+O.formatInputTooShort(aa.val(),O.minimumInputLength)+"</li>")}else{P("")}if(W&&this.showSearch){this.showSearch(true)}return}if(O.maximumInputLength&&aa.val().length>O.maximumInputLength){if(y(O.formatInputTooLong,"formatInputTooLong")){P("<li class='select2-no-results'>"+O.formatInputTooLong(aa.val(),O.maximumInputLength)+"</li>")}else{P("")}return}if(O.formatSearching&&this.findHighlightableChoices().length===0){P("<li class='select2-searching'>"+O.formatSearching()+"</li>")}aa.addClass("select2-active");this.removeHighlight();X=this.tokenize();if(X!=m&&X!=null){aa.val(X)}this.resultsPage=1;O.query({element:O.element,term:aa.val(),page:this.resultsPage,context:null,matcher:O.matcher,callback:this.bind(function(ac){var ab;if(Y!=this.queryCount){return}if(!this.opened()){this.search.removeClass("select2-active");return}this.context=(ac.context===m)?null:ac.context;if(this.opts.createSearchChoice&&aa.val()!==""){ab=this.opts.createSearchChoice.call(Z,aa.val(),ac.results);if(ab!==m&&ab!==null&&Z.id(ab)!==m&&Z.id(ab)!==null){if(D(ac.results).filter(function(){return t(Z.id(this),Z.id(ab))}).length===0){ac.results.unshift(ab)}}}if(ac.results.length===0&&y(O.formatNoMatches,"formatNoMatches")){P("<li class='select2-no-results'>"+O.formatNoMatches(aa.val())+"</li>");return}U.empty();Z.opts.populateResults.call(this,U,ac.results,{term:aa.val(),page:this.resultsPage,context:null});if(ac.more===true&&y(O.formatLoadMore,"formatLoadMore")){U.append("<li class='select2-more-results'>"+Z.opts.escapeMarkup(O.formatLoadMore(this.resultsPage))+"</li>");window.setTimeout(function(){Z.loadMoreIfNeeded()},10)}this.postprocessResults(ac,W);V();this.opts.element.trigger({type:"select2-loaded",items:ac})})})},cancel:function(){this.close()},blur:function(){if(this.opts.selectOnBlur){this.selectHighlighted({noFocus:true})}this.close();this.container.removeClass("select2-container-active");if(this.search[0]===document.activeElement){this.search.blur()}this.clearSearch();this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus")},focusSearch:function(){I(this.search)},selectHighlighted:function(P){var O=this.highlight(),Q=this.results.find(".select2-highlighted"),R=Q.closest(".select2-result").data("select2-data");if(R){this.highlight(O);this.onSelect(R,P)}else{if(P&&P.noFocus){this.close()}}},getPlaceholder:function(){var O;return this.opts.element.attr("placeholder")||this.opts.element.attr("data-placeholder")||this.opts.element.data("placeholder")||this.opts.placeholder||((O=this.getPlaceholderOption())!==m?O.text():m)},getPlaceholderOption:function(){if(this.select){var O=this.select.children().first();if(this.opts.placeholderOption!==m){return(this.opts.placeholderOption==="first"&&O)||(typeof this.opts.placeholderOption==="function"&&this.opts.placeholderOption(this.select))}else{if(O.text()===""&&O.val()===""){return O}}}},initContainerWidth:function(){function P(){var T,R,U,S,Q;if(this.opts.width==="off"){return null}else{if(this.opts.width==="element"){return this.opts.element.outerWidth(false)===0?"auto":this.opts.element.outerWidth(false)+"px"}else{if(this.opts.width==="copy"||this.opts.width==="resolve"){T=this.opts.element.attr("style");if(T!==m){R=T.split(";");for(S=0,Q=R.length;S<Q;S=S+1){U=R[S].replace(/\s/g,"").match(/[^-]width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i);if(U!==null&&U.length>=1){return U[1]}}}if(this.opts.width==="resolve"){T=this.opts.element.css("width");if(T.indexOf("%")>0){return T}return(this.opts.element.outerWidth(false)===0?"auto":this.opts.element.outerWidth(false)+"px")}return null}else{if(D.isFunction(this.opts.width)){return this.opts.width()}else{return this.opts.width}}}}}var O=P.call(this);if(O!==null){this.container.css("width",O)}}});x=L(N,{createContainer:function(){var O=D(document.createElement("div")).attr({"class":"select2-container"}).html(["<a href='javascript:void(0)' onclick='return false;' class='select2-choice' tabindex='-1'>"," <span class='select2-chosen'> </span><abbr class='select2-search-choice-close'></abbr>"," <span class='select2-arrow'><b></b></span>","</a>","<input class='select2-focusser select2-offscreen' type='text'/>","<div class='select2-drop select2-display-none'>"," <div class='select2-search'>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'/>"," </div>"," <ul class='select2-results'>"," </ul>","</div>"].join(""));return O},enableInterface:function(){if(this.parent.enableInterface.apply(this,arguments)){this.focusser.prop("disabled",!this.isInterfaceEnabled())}},opening:function(){var Q,P,O;if(this.opts.minimumResultsForSearch>=0){this.showSearch(true)}this.parent.opening.apply(this,arguments);if(this.showSearchInput!==false){this.search.val(this.focusser.val())}this.search.focus();Q=this.search.get(0);if(Q.createTextRange){P=Q.createTextRange();P.collapse(false);P.select()}else{if(Q.setSelectionRange){O=this.search.val().length;Q.setSelectionRange(O,O)}}if(this.search.val()===""){if(this.nextSearchTerm!=m){this.search.val(this.nextSearchTerm);this.search.select()}}this.focusser.prop("disabled",true).val("");this.updateResults(true);this.opts.element.trigger(D.Event("select2-open"))},close:function(O){if(!this.opened()){return}this.parent.close.apply(this,arguments);O=O||{focus:true};this.focusser.removeAttr("disabled");if(O.focus){this.focusser.focus()}},focus:function(){if(this.opened()){this.close()}else{this.focusser.removeAttr("disabled");this.focusser.focus()}},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments);this.focusser.removeAttr("disabled");this.focusser.focus()},destroy:function(){D("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id"));this.parent.destroy.apply(this,arguments)},initContainer:function(){var P,O=this.container,Q=this.dropdown;if(this.opts.minimumResultsForSearch<0){this.showSearch(false)}else{this.showSearch(true)}this.selection=P=O.find(".select2-choice");this.focusser=O.find(".select2-focusser");this.focusser.attr("id","s2id_autogen"+a());D("label[for='"+this.opts.element.attr("id")+"']").attr("for",this.focusser.attr("id"));this.focusser.attr("tabindex",this.elementTabIndex);this.search.on("keydown",this.bind(function(R){if(!this.isInterfaceEnabled()){return}if(R.which===K.PAGE_UP||R.which===K.PAGE_DOWN){A(R);return}switch(R.which){case K.UP:case K.DOWN:this.moveHighlight((R.which===K.UP)?-1:1);A(R);return;case K.ENTER:this.selectHighlighted();A(R);return;case K.TAB:this.selectHighlighted({noFocus:true});return;case K.ESC:this.cancel(R);A(R);return}}));this.search.on("blur",this.bind(function(R){if(document.activeElement===this.body().get(0)){window.setTimeout(this.bind(function(){this.search.focus()}),0)}}));this.focusser.on("keydown",this.bind(function(R){if(!this.isInterfaceEnabled()){return}if(R.which===K.TAB||K.isControl(R)||K.isFunctionKey(R)||R.which===K.ESC){return}if(this.opts.openOnEnter===false&&R.which===K.ENTER){A(R);return}if(R.which==K.DOWN||R.which==K.UP||(R.which==K.ENTER&&this.opts.openOnEnter)){if(R.altKey||R.ctrlKey||R.shiftKey||R.metaKey){return}this.open();A(R);return}if(R.which==K.DELETE||R.which==K.BACKSPACE){if(this.opts.allowClear){this.clear()}A(R);return}}));F(this.focusser);this.focusser.on("keyup-change input",this.bind(function(R){if(this.opts.minimumResultsForSearch>=0){R.stopPropagation();if(this.opened()){return}this.open()}}));P.on("mousedown","abbr",this.bind(function(R){if(!this.isInterfaceEnabled()){return}this.clear();b(R);this.close();this.selection.focus()}));P.on("mousedown",this.bind(function(R){if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}if(this.opened()){this.close()}else{if(this.isInterfaceEnabled()){this.open()}}A(R)}));Q.on("mousedown",this.bind(function(){this.search.focus()}));P.on("focus",this.bind(function(R){A(R)}));this.focusser.on("focus",this.bind(function(){if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){if(!this.opened()){this.container.removeClass("select2-container-active");this.opts.element.trigger(D.Event("select2-blur"))}}));this.search.on("focus",this.bind(function(){if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}this.container.addClass("select2-container-active")}));this.initContainerWidth();this.opts.element.addClass("select2-offscreen");this.setPlaceholder()},clear:function(Q){var R=this.selection.data("select2-data");if(R){var P=D.Event("select2-clearing");this.opts.element.trigger(P);if(P.isDefaultPrevented()){return}var O=this.getPlaceholderOption();this.opts.element.val(O?O.val():"");this.selection.find(".select2-chosen").empty();this.selection.removeData("select2-data");this.setPlaceholder();if(Q!==false){this.opts.element.trigger({type:"select2-removed",val:this.id(R),choice:R});this.triggerChange({removed:R})}}},initSelection:function(){var P;if(this.isPlaceholderOptionSelected()){this.updateSelection(null);this.close();this.setPlaceholder()}else{var O=this;this.opts.initSelection.call(null,this.opts.element,function(Q){if(Q!==m&&Q!==null){O.updateSelection(Q);O.close();O.setPlaceholder()}})}},isPlaceholderOptionSelected:function(){var O;if(!this.getPlaceholder()){return false}return((O=this.getPlaceholderOption())!==m&&O.is(":selected"))||(this.opts.element.val()==="")||(this.opts.element.val()===m)||(this.opts.element.val()===null)},prepareOpts:function(){var P=this.parent.prepareOpts.apply(this,arguments),O=this;if(P.element.get(0).tagName.toLowerCase()==="select"){P.initSelection=function(Q,S){var R=Q.find(":selected");S(O.optionToData(R))}}else{if("data" in P){P.initSelection=P.initSelection||function(R,T){var S=R.val();var Q=null;P.query({matcher:function(U,X,V){var W=t(S,P.id(V));if(W){Q=V}return W},callback:!D.isFunction(T)?D.noop:function(){T(Q)}})}}}return P},getPlaceholder:function(){if(this.select){if(this.getPlaceholderOption()===m){return m}}return this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var O=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&O!==m){if(this.select&&this.getPlaceholderOption()===m){return}this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(O));this.selection.addClass("select2-default");this.container.removeClass("select2-allowclear")}},postprocessResults:function(T,P,S){var R=0,O=this,U=true;this.findHighlightableChoices().each2(function(V,W){if(t(O.id(W.data("select2-data")),O.opts.element.val())){R=V;return false}});if(S!==false){if(P===true&&R>=0){this.highlight(R)}else{this.highlight(0)}}if(P===true){var Q=this.opts.minimumResultsForSearch;if(Q>=0){this.showSearch(r(T.results)>=Q)}}},showSearch:function(O){if(this.showSearchInput===O){return}this.showSearchInput=O;this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!O);this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!O);D(this.dropdown,this.container).toggleClass("select2-with-searchbox",O)},onSelect:function(Q,P){if(!this.triggerSelect(Q)){return}var O=this.opts.element.val(),R=this.data();this.opts.element.val(this.id(Q));this.updateSelection(Q);this.opts.element.trigger({type:"select2-selected",val:this.id(Q),choice:Q});this.nextSearchTerm=this.opts.nextSearchTerm(Q,this.search.val());this.close();if(!P||!P.noFocus){this.focusser.focus()}if(!t(O,this.id(Q))){this.triggerChange({added:Q,removed:R})}},updateSelection:function(R){var P=this.selection.find(".select2-chosen"),Q,O;this.selection.data("select2-data",R);P.empty();if(R!==null){Q=this.opts.formatSelection(R,P,this.opts.escapeMarkup)}if(Q!==m){P.append(Q)}O=this.opts.formatSelectionCssClass(R,P);if(O!==m){P.addClass(O)}this.selection.removeClass("select2-default");if(this.opts.allowClear&&this.getPlaceholder()!==m){this.container.addClass("select2-allowclear")}},val:function(){var S,P=false,Q=null,O=this,R=this.data();if(arguments.length===0){return this.opts.element.val()}S=arguments[0];if(arguments.length>1){P=arguments[1]}if(this.select){this.select.val(S).find(":selected").each2(function(T,U){Q=O.optionToData(U);return false});this.updateSelection(Q);this.setPlaceholder();if(P){this.triggerChange({added:Q,removed:R})}}else{if(!S&&S!==0){this.clear(P);return}if(this.opts.initSelection===m){throw new Error("cannot call val() if initSelection() is not defined")}this.opts.element.val(S);this.opts.initSelection(this.opts.element,function(T){O.opts.element.val(!T?"":O.id(T));O.updateSelection(T);O.setPlaceholder();if(P){O.triggerChange({added:T,removed:R})}})}},clearSearch:function(){this.search.val("");this.focusser.val("")},data:function(Q){var P,O=false;if(arguments.length===0){P=this.selection.data("select2-data");if(P==m){P=null}return P}else{if(arguments.length>1){O=arguments[1]}if(!Q){this.clear(O)}else{P=this.data();this.opts.element.val(!Q?"":this.id(Q));this.updateSelection(Q);if(O){this.triggerChange({added:Q,removed:P})}}}}});c=L(N,{createContainer:function(){var O=D(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["<ul class='select2-choices'>"," <li class='select2-search-field'>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>"," </li>","</ul>","<div class='select2-drop select2-drop-multi select2-display-none'>"," <ul class='select2-results'>"," </ul>","</div>"].join(""));return O},prepareOpts:function(){var P=this.parent.prepareOpts.apply(this,arguments),O=this;if(P.element.get(0).tagName.toLowerCase()==="select"){P.initSelection=function(Q,S){var R=[];Q.find(":selected").each2(function(T,U){R.push(O.optionToData(U))});S(R)}}else{if("data" in P){P.initSelection=P.initSelection||function(Q,T){var R=i(Q.val(),P.separator);var S=[];P.query({matcher:function(U,X,V){var W=D.grep(R,function(Y){return t(Y,P.id(V))}).length;if(W){S.push(V)}return W},callback:!D.isFunction(T)?D.noop:function(){var U=[];for(var X=0;X<R.length;X++){var Y=R[X];for(var W=0;W<S.length;W++){var V=S[W];if(t(Y,P.id(V))){U.push(V);S.splice(W,1);break}}}T(U)}})}}}return P},selectChoice:function(O){var P=this.container.find(".select2-search-choice-focus");if(P.length&&O&&O[0]==P[0]){}else{if(P.length){this.opts.element.trigger("choice-deselected",P)}P.removeClass("select2-search-choice-focus");if(O&&O.length){this.close();O.addClass("select2-search-choice-focus");this.opts.element.trigger("choice-selected",O)}}},destroy:function(){D("label[for='"+this.search.attr("id")+"']").attr("for",this.opts.element.attr("id"));this.parent.destroy.apply(this,arguments)},initContainer:function(){var O=".select2-choices",P;this.searchContainer=this.container.find(".select2-search-field");this.selection=P=this.container.find(O);var Q=this;this.selection.on("click",".select2-search-choice:not(.select2-locked)",function(R){Q.search[0].focus();Q.selectChoice(D(this))});this.search.attr("id","s2id_autogen"+a());D("label[for='"+this.opts.element.attr("id")+"']").attr("for",this.search.attr("id"));this.search.on("input paste",this.bind(function(){if(!this.isInterfaceEnabled()){return}if(!this.opened()){this.open()}}));this.search.attr("tabindex",this.elementTabIndex);this.keydowns=0;this.search.on("keydown",this.bind(function(V){if(!this.isInterfaceEnabled()){return}++this.keydowns;var T=P.find(".select2-search-choice-focus");var U=T.prev(".select2-search-choice:not(.select2-locked)");var S=T.next(".select2-search-choice:not(.select2-locked)");var W=f(this.search);if(T.length&&(V.which==K.LEFT||V.which==K.RIGHT||V.which==K.BACKSPACE||V.which==K.DELETE||V.which==K.ENTER)){var R=T;if(V.which==K.LEFT&&U.length){R=U}else{if(V.which==K.RIGHT){R=S.length?S:null}else{if(V.which===K.BACKSPACE){this.unselect(T.first());this.search.width(10);R=U.length?U:S}else{if(V.which==K.DELETE){this.unselect(T.first());this.search.width(10);R=S.length?S:null}else{if(V.which==K.ENTER){R=null}}}}}this.selectChoice(R);A(V);if(!R||!R.length){this.open()}return}else{if(((V.which===K.BACKSPACE&&this.keydowns==1)||V.which==K.LEFT)&&(W.offset==0&&!W.length)){this.selectChoice(P.find(".select2-search-choice:not(.select2-locked)").last());A(V);return}else{this.selectChoice(null)}}if(this.opened()){switch(V.which){case K.UP:case K.DOWN:this.moveHighlight((V.which===K.UP)?-1:1);A(V);return;case K.ENTER:this.selectHighlighted();A(V);return;case K.TAB:this.selectHighlighted({noFocus:true});this.close();return;case K.ESC:this.cancel(V);A(V);return}}if(V.which===K.TAB||K.isControl(V)||K.isFunctionKey(V)||V.which===K.BACKSPACE||V.which===K.ESC){return}if(V.which===K.ENTER){if(this.opts.openOnEnter===false){return}else{if(V.altKey||V.ctrlKey||V.shiftKey||V.metaKey){return}}}this.open();if(V.which===K.PAGE_UP||V.which===K.PAGE_DOWN){A(V)}if(V.which===K.ENTER){A(V)}}));this.search.on("keyup",this.bind(function(R){this.keydowns=0;this.resizeSearch()}));this.search.on("blur",this.bind(function(R){this.container.removeClass("select2-container-active");this.search.removeClass("select2-focused");this.selectChoice(null);if(!this.opened()){this.clearSearch()}R.stopImmediatePropagation();this.opts.element.trigger(D.Event("select2-blur"))}));this.container.on("click",O,this.bind(function(R){if(!this.isInterfaceEnabled()){return}if(D(R.target).closest(".select2-search-choice").length>0){return}this.selectChoice(null);this.clearPlaceholder();if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}this.open();this.focusSearch();R.preventDefault()}));this.container.on("focus",O,this.bind(function(){if(!this.isInterfaceEnabled()){return}if(!this.container.hasClass("select2-container-active")){this.opts.element.trigger(D.Event("select2-focus"))}this.container.addClass("select2-container-active");this.dropdown.addClass("select2-drop-active");this.clearPlaceholder()}));this.initContainerWidth();this.opts.element.addClass("select2-offscreen");this.clearSearch()},enableInterface:function(){if(this.parent.enableInterface.apply(this,arguments)){this.search.prop("disabled",!this.isInterfaceEnabled())}},initSelection:function(){var P;if(this.opts.element.val()===""&&this.opts.element.text()===""){this.updateSelection([]);this.close();this.clearSearch()}if(this.select||this.opts.element.val()!==""){var O=this;this.opts.initSelection.call(null,this.opts.element,function(Q){if(Q!==m&&Q!==null){O.updateSelection(Q);O.close();O.clearSearch()}})}},clearSearch:function(){var P=this.getPlaceholder(),O=this.getMaxSearchWidth();if(P!==m&&this.getVal().length===0&&this.search.hasClass("select2-focused")===false){this.search.val(P).addClass("select2-default");this.search.width(O>0?O:this.container.css("width"))}else{this.search.val("").width(10)}},clearPlaceholder:function(){if(this.search.hasClass("select2-default")){this.search.val("").removeClass("select2-default")}},opening:function(){this.clearPlaceholder();this.resizeSearch();this.parent.opening.apply(this,arguments);this.focusSearch();this.updateResults(true);this.search.focus();this.opts.element.trigger(D.Event("select2-open"))},close:function(){if(!this.opened()){return}this.parent.close.apply(this,arguments)},focus:function(){this.close();this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(R){var Q=[],P=[],O=this;D(R).each(function(){if(q(O.id(this),Q)<0){Q.push(O.id(this));P.push(this)}});R=P;this.selection.find(".select2-search-choice").remove();D(R).each(function(){O.addSelectedChoice(this)});O.postprocessResults()},tokenize:function(){var O=this.search.val();O=this.opts.tokenizer.call(this,O,this.data(),this.bind(this.onSelect),this.opts);if(O!=null&&O!=m){this.search.val(O);if(O.length>0){this.open()}}},onSelect:function(P,O){if(!this.triggerSelect(P)){return}this.addSelectedChoice(P);this.opts.element.trigger({type:"selected",val:this.id(P),choice:P});if(this.select||!this.opts.closeOnSelect){this.postprocessResults(P,false,this.opts.closeOnSelect===true)}if(this.opts.closeOnSelect){this.close();this.search.width(10)}else{if(this.countSelectableResults()>0){this.search.width(10);this.resizeSearch();if(this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()){this.updateResults(true)}this.positionDropdown()}else{this.close();this.search.width(10)}}this.triggerChange({added:P});if(!O||!O.noFocus){this.focusSearch()}},cancel:function(){this.close();this.focusSearch()},addSelectedChoice:function(S){var U=!S.locked,Q=D("<li class='select2-search-choice'><div></div><a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a></li>"),V=D("<li class='select2-search-choice select2-locked'><div></div></li>");var R=U?Q:V,O=this.id(S),P=this.getVal(),T,W;T=this.opts.formatSelection(S,R.find("div"),this.opts.escapeMarkup);if(T!=m){R.find("div").replaceWith("<div>"+T+"</div>")}W=this.opts.formatSelectionCssClass(S,R.find("div"));if(W!=m){R.addClass(W)}if(U){R.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(X){if(!this.isInterfaceEnabled()){return}D(X.target).closest(".select2-search-choice").fadeOut("fast",this.bind(function(){this.unselect(D(X.target));this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");this.close();this.focusSearch()})).dequeue();A(X)})).on("focus",this.bind(function(){if(!this.isInterfaceEnabled()){return}this.container.addClass("select2-container-active");this.dropdown.addClass("select2-drop-active")}))}R.data("select2-data",S);R.insertBefore(this.searchContainer);P.push(O);this.setVal(P)},unselect:function(P){var R=this.getVal(),Q,O;P=P.closest(".select2-search-choice");if(P.length===0){throw"Invalid argument: "+P+". Must be .select2-search-choice"}Q=P.data("select2-data");if(!Q){return}while((O=q(this.id(Q),R))>=0){R.splice(O,1);this.setVal(R);if(this.select){this.postprocessResults()}}P.remove();this.opts.element.trigger({type:"removed",val:this.id(Q),choice:Q});this.triggerChange({removed:Q})},postprocessResults:function(S,P,R){var T=this.getVal(),U=this.results.find(".select2-result"),Q=this.results.find(".select2-result-with-children"),O=this;U.each2(function(W,V){var X=O.id(V.data("select2-data"));if(q(X,T)>=0){V.addClass("select2-selected");V.find(".select2-result-selectable").addClass("select2-selected")}});Q.each2(function(W,V){if(!V.is(".select2-result-selectable")&&V.find(".select2-result-selectable:not(.select2-selected)").length===0){V.addClass("select2-selected")}});if(this.highlight()==-1&&R!==false){O.highlight(0)}if(!this.opts.createSearchChoice&&!U.filter(".select2-result:not(.select2-selected)").length>0){if(!S||S&&!S.more&&this.results.find(".select2-no-results").length===0){if(y(O.opts.formatNoMatches,"formatNoMatches")){this.results.append("<li class='select2-no-results'>"+O.opts.formatNoMatches(O.search.val())+"</li>")}}}},getMaxSearchWidth:function(){return this.selection.width()-h(this.search)},resizeSearch:function(){var T,R,Q,O,P,S=h(this.search);T=n(this.search)+10;R=this.search.offset().left;Q=this.selection.width();O=this.selection.offset().left;P=Q-(R-O)-S;if(P<T){P=Q-S}if(P<40){P=Q-S}if(P<=0){P=T}this.search.width(Math.floor(P))},getVal:function(){var O;if(this.select){O=this.select.val();return O===null?[]:O}else{O=this.opts.element.val();return i(O,this.opts.separator)}},setVal:function(P){var O;if(this.select){this.select.val(P)}else{O=[];D(P).each(function(){if(q(this,O)<0){O.push(this)}});this.opts.element.val(O.length===0?"":O.join(this.opts.separator))}},buildChangeDetails:function(O,R){var R=R.slice(0),O=O.slice(0);for(var Q=0;Q<R.length;Q++){for(var P=0;P<O.length;P++){if(t(this.opts.id(R[Q]),this.opts.id(O[P]))){R.splice(Q,1);Q--;O.splice(P,1);P--}}}return{added:R,removed:O}},val:function(S,P){var R,O=this,Q;if(arguments.length===0){return this.getVal()}R=this.data();if(!R.length){R=[]}if(!S&&S!==0){this.opts.element.val("");this.updateSelection([]);this.clearSearch();if(P){this.triggerChange({added:this.data(),removed:R})}return}this.setVal(S);if(this.select){this.opts.initSelection(this.select,this.bind(this.updateSelection));if(P){this.triggerChange(this.buildChangeDetails(R,this.data()))}}else{if(this.opts.initSelection===m){throw new Error("val() cannot be called if initSelection() is not defined")}this.opts.initSelection(this.opts.element,function(U){var T=D.map(U,O.id);O.setVal(T);O.updateSelection(U);O.clearSearch();if(P){O.triggerChange(O.buildChangeDetails(R,this.data()))}})}this.clearSearch()},onSortStart:function(){if(this.select){throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.")}this.search.width(0);this.searchContainer.hide()},onSortEnd:function(){var P=[],O=this;this.searchContainer.show();this.searchContainer.appendTo(this.searchContainer.parent());this.resizeSearch();this.selection.find(".select2-search-choice").each(function(){P.push(O.opts.id(D(this).data("select2-data")))});this.setVal(P);this.triggerChange()},data:function(Q,R){var P=this,S,O;if(arguments.length===0){return this.selection.find(".select2-search-choice").map(function(){return D(this).data("select2-data")}).get()}else{O=this.data();if(!Q){Q=[]}S=D.map(Q,function(T){return P.opts.id(T)});this.setVal(S);this.updateSelection(Q);this.clearSearch();if(R){this.triggerChange(this.buildChangeDetails(O,this.data()))}}}});D.fn.select2=function(){var T=Array.prototype.slice.call(arguments,0),P,S,O,V,X,W=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],U=["opened","isFocused","container","dropdown"],Q=["val","data"],R={search:"externalSearch"};this.each(function(){if(T.length===0||typeof(T[0])==="object"){P=T.length===0?{}:D.extend({},T[0]);P.element=D(this);if(P.element.get(0).tagName.toLowerCase()==="select"){X=P.element.prop("multiple")}else{X=P.multiple||false;if("tags" in P){P.multiple=X=true}}S=X?new c():new x();S.init(P)}else{if(typeof(T[0])==="string"){if(q(T[0],W)<0){throw"Unknown method: "+T[0]}V=m;S=D(this).data("select2");if(S===m){return}O=T[0];if(O==="container"){V=S.container}else{if(O==="dropdown"){V=S.dropdown}else{if(R[O]){O=R[O]}V=S[O].apply(S,T.slice(1))}}if(q(T[0],U)>=0||(q(T[0],Q)&&T.length==1)){return false}}else{throw"Invalid arguments to select2 plugin: "+T}}});return(V===m)?this:V};D.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:true,openOnEnter:true,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(P,Q,S,O){var R=[];u(P.text,S.term,R,O);return R.join("")},formatSelection:function(Q,P,O){return Q?O(Q.text):m},sortResults:function(P,O,Q){return P},formatResultCssClass:function(O){return m},formatSelectionCssClass:function(P,O){return m},formatNoMatches:function(){return"No matches found"},formatInputTooShort:function(O,P){var Q=P-O.length;return"Please enter "+Q+" more character"+(Q==1?"":"s")},formatInputTooLong:function(P,O){var Q=P.length-O;return"Please delete "+Q+" character"+(Q==1?"":"s")},formatSelectionTooBig:function(O){return"You can only select "+O+" item"+(O==1?"":"s")},formatLoadMore:function(O){return"Loading more results..."},formatSearching:function(){return"Searching..."},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(O){return O.id},matcher:function(O,P){return e(""+P).toUpperCase().indexOf(e(""+O).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:g,escapeMarkup:G,blurOnChange:false,selectOnBlur:false,adaptContainerCssClass:function(O){return O},adaptDropdownCssClass:function(O){return null},nextSearchTerm:function(O,P){return m}};D.fn.select2.ajaxDefaults={transport:D.ajax,params:{type:"GET",cache:false,dataType:"json"}};window.Select2={query:{ajax:E,local:H,tags:z},util:{debounce:k,markMatch:u,escapeMarkup:G,stripDiacritics:e},"class":{"abstract":N,single:x,multi:c}}}(jQuery)); \ No newline at end of file diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/packed/mvc/dataset/hda-base.js --- a/static/scripts/packed/mvc/dataset/hda-base.js +++ b/static/scripts/packed/mvc/dataset/hda-base.js @@ -1,1 +1,1 @@ -var HDABaseView=Backbone.View.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){if(a.logger){this.logger=this.model.logger=a.logger}this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urlTemplates=a.urlTemplates;this.expanded=a.expanded||false;this.model.bind("change",function(d,c){var b=_.omit(this.model.changedAttributes(),"display_apps","display_types");if(_.keys(b).length){this.render()}else{if(this.expanded){this._render_displayApps()}}},this)},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);this.urls=this._renderUrls(this.urlTemplates,this.model.toJSON());a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this._setUpBehaviors(a);this.body=$(this._render_body());a.append(this.body);this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b._renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b._renderMetaDownloadUrls(e,a)}else{try{c[f]=_.template(e,a)}catch(g){throw (b+"._renderUrls error: "+g+"\n rendering:"+e+"\n with "+JSON.stringify(a))}}}});return c},_renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},_setUpBehaviors:function(a){a=a||this.$el;make_popup_menus(a);a.find("[title]").tooltip({placement:"bottom"})},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NEW)||(!this.model.get("accessible"))){this.displayButton=null;return null}var b={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){b.enabled=false;b.title=_l("Cannot display datasets removed from disk")}else{if(this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD){b.enabled=false;b.title=_l("This dataset must finish uploading before it can be viewed")}else{b.title=_l("View data");b.href=this.urls.display;var a=this;b.on_click=function(){Galaxy.frame_manager.frame_new({title:"Data Viewer",type:"url",location:"center",content:a.urls.display})}}}this.displayButton=new IconButtonView({model:new IconButton(b)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a.trim())},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayAppArea:function(){return $("<div/>").addClass("display-apps")},_render_displayApps:function(c){c=c||this.$el;var d=c.find("div.display-apps"),a=this.model.get("display_types"),b=this.model.get("display_apps");if((!this.model.hasData())||(!c||!c.length)||(!d.length)){return}d.html(null);if(!_.isEmpty(a)){d.append(HDABaseView.templates.displayApps({displayApps:a}))}if(!_.isEmpty(b)){d.append(HDABaseView.templates.displayApps({displayApps:b}))}},_render_peek:function(){var a=this.model.get("peek");if(!a){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(a))},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: none");if(this.expanded){this._render_body_html(a);a.css("display","block")}return a},_render_body_html:function(a){a.html("");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NEW:this._render_body_new(a);break;case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.PAUSED:this._render_body_paused(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+this.model.get("state")+'".</div>'))}a.append('<div style="clear: both"></div>');this._setUpBehaviors(a)},_render_body_new:function(b){var a=_l("This is a new dataset and not all of its data are available yet");b.append($("<div>"+_l(a)+"</div>"))},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+"</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+"</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_paused:function(a){a.append($("<div>"+_l("Job is paused. Use the history menu to resume")+"</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+"</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred with this dataset")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(_.extend(this.model.toJSON(),{urls:this.urls}))));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayAppArea());this._render_displayApps(a);a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this;this.expanded=(a===undefined)?(!this.body.is(":visible")):(a);if(this.expanded){b._render_body_html(b.body);this.body.slideDown("fast",function(){b.trigger("body-expanded",b.model.get("id"))})}else{this.body.slideUp("fast",function(){b.trigger("body-collapsed",b.model.get("id"))})}},remove:function(b){var a=this;this.$el.fadeOut("fast",function(){a.$el.remove();a.off();if(b){b()}})},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetadata"],displayApps:Handlebars.templates["template-hda-displayApps"]}; \ No newline at end of file +var HDABaseView=Backbone.View.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){if(a.logger){this.logger=this.model.logger=a.logger}this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urlTemplates=a.urlTemplates;this.expanded=a.expanded||false;this.model.bind("change",function(d,c){var b=_.omit(this.model.changedAttributes(),"display_apps","display_types");if(_.keys(b).length){this.render()}else{if(this.expanded){this._render_displayApps()}}},this)},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);this.$el.find("[title]").tooltip("destroy");this.urls=this._renderUrls(this.urlTemplates,this.model.toJSON());a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this._setUpBehaviors(a);this.body=$(this._render_body());a.append(this.body);this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b._renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b._renderMetaDownloadUrls(e,a)}else{try{c[f]=_.template(e,a)}catch(g){throw (b+"._renderUrls error: "+g+"\n rendering:"+e+"\n with "+JSON.stringify(a))}}}});return c},_renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},_setUpBehaviors:function(a){a=a||this.$el;make_popup_menus(a);a.find("[title]").tooltip({placement:"bottom"})},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NEW)||(!this.model.get("accessible"))){this.displayButton=null;return null}var b={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){b.enabled=false;b.title=_l("Cannot display datasets removed from disk")}else{if(this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD){b.enabled=false;b.title=_l("This dataset must finish uploading before it can be viewed")}else{b.title=_l("View data");b.href=this.urls.display;var a=this;b.on_click=function(){Galaxy.frame_manager.frame_new({title:"Data Viewer",type:"url",location:"center",content:a.urls.display})}}}this.displayButton=new IconButtonView({model:new IconButton(b)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a.trim())},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayAppArea:function(){return $("<div/>").addClass("display-apps")},_render_displayApps:function(c){c=c||this.$el;var d=c.find("div.display-apps"),a=this.model.get("display_types"),b=this.model.get("display_apps");if((!this.model.hasData())||(!c||!c.length)||(!d.length)){return}d.html(null);if(!_.isEmpty(a)){d.append(HDABaseView.templates.displayApps({displayApps:a}))}if(!_.isEmpty(b)){d.append(HDABaseView.templates.displayApps({displayApps:b}))}},_render_peek:function(){var a=this.model.get("peek");if(!a){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(a))},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: none");if(this.expanded){this._render_body_html(a);a.css("display","block")}return a},_render_body_html:function(a){a.html("");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NEW:this._render_body_new(a);break;case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.PAUSED:this._render_body_paused(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+this.model.get("state")+'".</div>'))}a.append('<div style="clear: both"></div>');this._setUpBehaviors(a)},_render_body_new:function(b){var a=_l("This is a new dataset and not all of its data are available yet");b.append($("<div>"+_l(a)+"</div>"))},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+"</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+"</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_paused:function(a){a.append($("<div>"+_l("Job is paused. Use the history menu to resume")+"</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+"</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred with this dataset")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(_.extend(this.model.toJSON(),{urls:this.urls}))));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayAppArea());this._render_displayApps(a);a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this;this.expanded=(a===undefined)?(!this.body.is(":visible")):(a);if(this.expanded){b._render_body_html(b.body);this.body.slideDown("fast",function(){b.trigger("body-expanded",b.model.get("id"))})}else{this.body.slideUp("fast",function(){b.trigger("body-collapsed",b.model.get("id"))})}},remove:function(b){var a=this;this.$el.fadeOut("fast",function(){a.$el.remove();a.off();if(b){b()}})},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetadata"],displayApps:Handlebars.templates["template-hda-displayApps"]}; \ No newline at end of file diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/packed/utils/galaxy.uploadbox.js --- a/static/scripts/packed/utils/galaxy.uploadbox.js +++ b/static/scripts/packed/utils/galaxy.uploadbox.js @@ -1,1 +1,1 @@ -(function(d){jQuery.event.props.push("dataTransfer");var c={url:"",paramname:"content",maxfilesize:2048,data:{},dragover:function(){},dragleave:function(){},initialize:function(){},start:function(){},progress:function(){},success:function(){},error:function(f,g,h){alert(h)},error_browser:"Your browser does not support drag-and-drop file uploads.",error_filesize:"This file is too large. Please use an FTP client to upload it.",error_default:"The upload failed. Please make sure the file is available and accessible.",text_default:"Drag&drop files here or click to browse your local drive.",text_degrade:"Click here to browse your local drive. <br><br>Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."};var a=[];var b=-1;var e=false;d.fn.uploadbox=function(n){var f=d.extend({},c,n);var l=window.File&&window.FileReader&&window.FormData&&window.XMLHttpRequest;this.append('<input id="uploadbox_input" type="file" style="display: none" multiple>');this.append('<div id="uploadbox_info"></div>');if(l){this.find("#uploadbox_info").html(f.text_default)}else{this.find("#uploadbox_info").html(f.text_degrade)}this.on("drop",i);this.on("dragover",j);this.on("dragleave",m);this.on("click",function(p){p.stopPropagation();d("#uploadbox_input").trigger(p)});d("#uploadbox_input").change(function(q){var p=q.target.files;o(p)});function i(q){if(!q.dataTransfer){return}var p=q.dataTransfer.files;o(p);q.preventDefault();return false}function j(p){p.preventDefault();f.dragover.call(this,p)}function m(p){p.stopPropagation();f.dragleave.call(this,p)}function g(p){if(p.lengthComputable){f.progress(this.index,this.file,Math.round((p.loaded*100)/p.total))}}function o(r){var q=a.length;for(var p=0;p<r.length;p++){a.push(r[p])}for(var p=q;p<a.length;p++){f.start(p,a[p],"")}if(!e){h()}}function h(){if(b+1==a.length){e=false;return}e=true;var s=++b;try{var q=new FileReader();var t=a[s];var r=t.size;var p=1048576*f.maxfilesize;q.index=s;if(r<p){q.onloadend=function(v){k(s,t)};q.onerror=function(v){f.error(s,t,f.error_default);e=false};q.readAsDataURL(t)}else{f.error(s,t,f.error_filesize);h()}}catch(u){f.error(s,t,u)}}function k(p,r){var s=new FormData();for(var q in f.data){s.append(q,f.data[q])}s.append(f.paramname,r,r.name);var t=new XMLHttpRequest();t.upload.index=p;t.upload.file=r;t.upload.addEventListener("progress",g,false);t.open("POST",f.url,true);t.setRequestHeader("Accept","application/json");t.setRequestHeader("Cache-Control","no-cache");t.setRequestHeader("X-Requested-With","XMLHttpRequest");t.send(s);t.onloadend=function(){var u=null;if(t.responseText){try{u=jQuery.parseJSON(t.responseText)}catch(v){u=t.responseText}}if(t.status<200||t.status>299){f.error(p,r,t.statusText+" (Server Code "+t.status+")");e=false}else{f.success(p,r,u);h()}}}return this}})(jQuery); \ No newline at end of file +(function(g){jQuery.event.props.push("dataTransfer");var c={url:"",paramname:"content",maxfilesize:250,dragover:function(){},dragleave:function(){},announce:function(){},initialize:function(){},progress:function(){},success:function(){},error:function(i,j,k){alert(k)},complete:function(){},error_browser:"Your browser does not support drag-and-drop file uploads.",error_filesize:"This file is too large (>250MB). Please use an FTP client to upload it.",error_default:"Please make sure the file is available."};var f={};var a={};var b=0;var d=0;var h=false;var e=null;g.fn.uploadbox=function(x){f=g.extend({},c,x);e=this;e.append('<input id="uploadbox_input" type="file" style="display: none" multiple>');e.on("drop",l);e.on("dragover",m);e.on("dragleave",t);g("#uploadbox_input").change(function(y){v(y.target.files)});function l(y){if(!y.dataTransfer){return}v(y.dataTransfer.files);y.preventDefault();return false}function m(y){y.preventDefault();f.dragover.call(y)}function t(y){y.stopPropagation();f.dragleave.call(y)}function i(y){if(y.lengthComputable){f.progress(this.index,this.file,Math.round((y.loaded*100)/y.total))}}function v(A){if(h){return}for(var z=0;z<A.length;z++){var y=String(b++);a[y]=A[z];d++;f.announce(y,a[y],"")}}function o(y){if(a[y]){delete a[y];d--}}function j(){if(d==0){h=false;f.complete();return}else{h=true}var B=-1;for(var D in a){B=D;break}var C=a[B];o(B);var F=f.initialize(B,C);try{var z=new FileReader();var A=C.size;var y=1048576*f.maxfilesize;z.index=B;if(A<y){z.onload=function(G){n(B,C,F)};z.onerror=function(G){r(B,C,f.error_default)};z.readAsDataURL(C)}else{r(B,C,f.error_filesize)}}catch(E){r(B,C,E)}}function n(y,A,B){var C=new FormData();for(var z in B){C.append(z,B[z])}C.append(f.paramname,A,A.name);var D=new XMLHttpRequest();D.upload.index=y;D.upload.file=A;D.upload.addEventListener("progress",i,false);D.open("POST",f.url,true);D.setRequestHeader("Accept","application/json");D.setRequestHeader("Cache-Control","no-cache");D.setRequestHeader("X-Requested-With","XMLHttpRequest");D.send(C);D.onloadend=function(){var E=null;if(D.responseText){try{E=jQuery.parseJSON(D.responseText)}catch(F){E=D.responseText}}if(D.status<200||D.status>299){var G=D.statusText;if(!D.statusText){G=f.error_default}r(y,A,G+" (Server Code "+D.status+")")}else{u(y,A,E)}}}function u(y,z,A){f.success(y,z,A);j()}function r(y,z,A){f.error(y,z,A);j()}function s(){g("#uploadbox_input").trigger("click")}function q(y){for(y in a){o(y)}}function w(){if(!h){j()}}function k(y){f=g.extend({},f,y);return f}function p(){return window.File&&window.FileReader&&window.FormData&&window.XMLHttpRequest}return{select:s,remove:o,upload:w,reset:q,configure:k,compatible:p}}})(jQuery); \ No newline at end of file diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/scripts/utils/galaxy.uploadbox.js --- a/static/scripts/utils/galaxy.uploadbox.js +++ b/static/scripts/utils/galaxy.uploadbox.js @@ -19,11 +19,10 @@ progress : function() {}, success : function() {}, error : function(index, file, message) { alert(message); }, + complete : function() {}, error_browser : "Your browser does not support drag-and-drop file uploads.", error_filesize : "This file is too large (>250MB). Please use an FTP client to upload it.", - error_default : "Please make sure the file is available.", - text_default : "Drag&drop files into this box or click 'Select' to select files!", - text_degrade : "Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+." + error_default : "Please make sure the file is available." } // options @@ -32,7 +31,7 @@ // file queue var queue = {}; - // counter for file being currently processed + // queue index counter var queue_index = 0; // queue length @@ -50,21 +49,11 @@ // parse options opts = $.extend({}, default_opts, options); - // compatibility - var mode = window.File && window.FileReader && window.FormData && window.XMLHttpRequest; - // element el = this; // append upload button el.append('<input id="uploadbox_input" type="file" style="display: none" multiple>'); - el.append('<div id="uploadbox_info"></div>'); - - // set info text - if (mode) - el.find('#uploadbox_info').html(opts.text_default); - else - el.find('#uploadbox_info').html(opts.text_degrade); // attach events el.on('drop', drop); @@ -76,6 +65,9 @@ { // add files to queue add(e.target.files); + + // reset + $(this).val(''); }); // drop event @@ -120,11 +112,15 @@ // respond to an upload request function add(files) { + // only allow adding file if current batch is complete + if (queue_status) + return; + // add new files to queue for (var i = 0; i < files.length; i++) { // new identifier - var index = String(++queue_index); + var index = String(queue_index++); // add to queue queue[index] = files[i]; @@ -153,6 +149,15 @@ // process an upload, recursive function process() { + // validate + if (queue_length == 0) + { + queue_status = false; + opts.complete(); + return; + } else + queue_status = true; + // get an identifier from the queue var index = -1; for (var key in queue) @@ -161,10 +166,6 @@ break; } - // validate - if (queue_length == 0) - return; - // get current file from queue var file = queue[index]; @@ -172,7 +173,7 @@ remove(index) // start - var data = opts.initialize(index, file, length); + var data = opts.initialize(index, file); // add file to queue try @@ -312,12 +313,6 @@ process(); } - // current queue length - function length() - { - return queue_length; - } - // set options function configure(options) { @@ -328,21 +323,20 @@ return opts; } - // visibility of on screen information - function info() + // verify browser compatibility + function compatible() { - return el.find('#uploadbox_info'); + return window.File && window.FileReader && window.FormData && window.XMLHttpRequest && window.FileList; } // export functions return { - 'select' : select, - 'remove' : remove, - 'upload' : upload, - 'reset' : reset, - 'length' : length, - 'configure' : configure, - 'info' : info + 'select' : select, + 'remove' : remove, + 'upload' : upload, + 'reset' : reset, + 'configure' : configure, + 'compatible' : compatible }; } })(jQuery); \ No newline at end of file diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/style/blue/base.css --- a/static/style/blue/base.css +++ b/static/style/blue/base.css @@ -1116,16 +1116,17 @@ .galaxy-frame .frame{z-index:1002;overflow:hidden;position:absolute;background:#fff;border:1px solid #888;-webkit-box-shadow:0 0 5px rgba(0,0,0,0.3);}.galaxy-frame .frame .f-content{position:absolute;overflow:hidden;background:#fff;border:none;top:24px;bottom:3px;left:3px;right:3px} .galaxy-frame .frame .f-cover{position:absolute;display:none;top:0px;left:0px;height:100%;width:100%;opacity:0.0;background:#fff} .galaxy-frame .frame .f-iframe{border:none;width:100%;height:100%} -.galaxy-frame .frame .f-header{height:17px;margin:2px;cursor:pointer;border:1px solid #000;background:#2c3143;color:#fff;font-weight:bold} +.galaxy-frame .frame .f-header{height:17px;margin:2px;cursor:pointer;border:1px solid #000;background:#2c3143;color:#fff} .galaxy-frame .frame .f-title{position:absolute;top:2px;left:16px;right:16px;font-size:12px;font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif;text-align:center} -.galaxy-frame .frame .f-icon{position:absolute;cursor:pointer;font-style:normal} +.galaxy-frame .frame .f-icon{position:absolute;cursor:pointer} .galaxy-frame .frame .f-not-allowed{cursor:not-allowed} .galaxy-frame .frame .f-close{right:5px;top:1px} .galaxy-frame .frame .f-pin{left:6px;top:1px} .galaxy-frame .frame .f-resize{background:#fff;width:16px;height:16px;color:#2c3143;right:0px;bottom:0px;text-align:center;line-height:16px;border:0px} +.upload-info{font-weight:normal;text-align:center} .upload-box{width:100%;height:250px;max-height:250px;text-align:center;overflow:scroll;font-size:12px;line-height:1.33;-moz-border-radius:5px;border-radius:5px;border:1px dashed #bfbfbf;padding:20px}.upload-box .panel{display:none}.upload-box .panel .panel-heading{position:relative;height:19px;padding:5px}.upload-box .panel .panel-heading .title{position:absolute;top:2px;font-weight:normal;text-align:left;margin:0px;max-width:300px;overflow:hidden} .upload-box .panel .panel-heading .info{position:absolute;top:3px;font-weight:normal;right:20px;text-align:right;margin:0px} -.upload-box .panel .panel-heading .remove{position:absolute;cursor:pointer;top:0px;right:3px} +.upload-box .panel .panel-heading .symbol{position:absolute;cursor:pointer;top:0px;right:3px} .upload-box .panel .panel-body{position:relative;padding:5px} .upload-box .panel .panel-footer{position:relative;height:20px;padding:0px}.upload-box .panel .panel-footer .progress{height:10px;margin:5px} .upload-box .panel .panel-footer .error{font-weight:normal;margin:2px} @@ -1168,12 +1169,12 @@ .panel-warning-message{background-image:url(warn_small.png);background-color:#fce1ba} .panel-done-message{background-image:url(ok_small.png);background-color:#aff1af} .panel-info-message{background-image:url(info_small.png);background-color:#a6e4f7} -#masthead{position:absolute;top:0;left:0;width:100%;min-width:980px;padding:0}#masthead .nav{z-index:15001} +#masthead{position:absolute;top:0;left:0;width:100%;min-width:990px;padding:0}#masthead .nav{z-index:15001} #masthead .nav>li>a{cursor:pointer;text-decoration:none}#masthead .nav>li>a:hover{color:gold} #masthead li.dropdown>a:hover .caret{border-top-color:gold;border-bottom-color:gold} #masthead .navbar-brand{position:absolute;left:0;top:0;font-family:verdana;font-weight:bold;font-size:20px;line-height:1;color:white;padding:5px 20px 12px;margin-left:-15px;z-index:2000}#masthead .navbar-brand img{display:inline;width:26px;vertical-align:top} #masthead .navbar-brand a{color:white;text-decoration:none} -#masthead .iconbar{position:absolute;top:2px;right:110px;cursor:pointer;color:#999;overflow:hidden}#masthead .iconbar .symbol{float:left;margin:0px 8px} +#masthead .iconbar{position:absolute;top:2px;right:110px;cursor:pointer;color:#999;overflow:hidden}#masthead .iconbar .symbol{float:left;margin:0px 10px} #masthead .iconbar .symbol .number{font-weight:bold;font-size:12px;font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif;position:relative;left:23px;top:-18px} #masthead .iconbar .toggle{color:#BCC800} .quota-meter-container{position:absolute;top:0;right:0;height:32px} @@ -1246,9 +1247,10 @@ .errormessage .alert-link,.warningmessage .alert-link,.donemessage .alert-link,.infomessage .alert-link,.errormessagesmall .alert-link,.warningmessagesmall .alert-link,.donemessagesmall .alert-link,.infomessagesmall .alert-link{font-weight:bold} .errormessage>p,.warningmessage>p,.donemessage>p,.infomessage>p,.errormessagesmall>p,.warningmessagesmall>p,.donemessagesmall>p,.infomessagesmall>p,.errormessage>ul,.warningmessage>ul,.donemessage>ul,.infomessage>ul,.errormessagesmall>ul,.warningmessagesmall>ul,.donemessagesmall>ul,.infomessagesmall>ul{margin-bottom:0} .errormessage>p+p,.warningmessage>p+p,.donemessage>p+p,.infomessage>p+p,.errormessagesmall>p+p,.warningmessagesmall>p+p,.donemessagesmall>p+p,.infomessagesmall>p+p{margin-top:5px} -.errormessage{background-color:#f9c7c5;border-color:#dd1c15;color:#7e2a27}.errormessage hr{border-top-color:#c61913} -.errormessage .alert-link{color:#571d1b} -.warningmessage,.warningmessagesmall{background-image:url(warn_small.png)} +.errormessage,.errormessagesmall{background-color:#f9c7c5;border-color:#dd1c15;color:#7e2a27}.errormessage hr,.errormessagesmall hr{border-top-color:#c61913} +.errormessage .alert-link,.errormessagesmall .alert-link{color:#571d1b} +.warningmessage,.warningmessagesmall{background-color:#fce1ba;border-color:#e28709;color:#80571e;background-image:url(warn_small.png)}.warningmessage hr,.warningmessagesmall hr{border-top-color:#c97908} +.warningmessage .alert-link,.warningmessagesmall .alert-link{color:#573b14} .donemessage,.donemessagesmall{background-color:#aff1af;border-color:#20b420;color:#295f29;background-image:url(ok_small.png)}.donemessage hr,.donemessagesmall hr{border-top-color:#1c9e1c} .donemessage .alert-link,.donemessagesmall .alert-link{color:#193b19} .infomessage,.infomessagesmall{background-color:#a6e4f7;border-color:#1197c0;color:#1f5566;background-image:url(info_small.png)}.infomessage hr,.infomessagesmall hr{border-top-color:#0f85a8} diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/style/src/less/base.less --- a/static/style/src/less/base.less +++ b/static/style/src/less/base.less @@ -335,7 +335,7 @@ top:0; left:0; width:100%; - min-width:980px; + min-width:990px; padding: 0; .nav { @@ -398,7 +398,7 @@ .symbol { float : left; - margin : 0px 8px; + margin : 0px 10px; } .symbol .number @@ -770,28 +770,23 @@ background-position: 5px 5px; } -.errormessage { +.errormessage, .errormessagesmall { .alert-danger(); } .warningmessage, .warningmessagesmall { + .alert-warning(); background-image: url(warn_small.png); - //border-color: @warn_message_border; - //background-color: @warn_message_bg; } .donemessage, .donemessagesmall { .alert-success(); background-image: url(ok_small.png); - // border-color: @done_message_border; - // background-color: @done_message_bg; } .infomessage, .infomessagesmall { .alert-info(); background-image: url(info_small.png); - //border-color: @info_message_border; - //background-color: @info_message_bg; } .errormark, .warningmark, .donemark, .infomark, .ok_bgr, .err_bgr { diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/style/src/less/frame.less --- a/static/style/src/less/frame.less +++ b/static/style/src/less/frame.less @@ -111,7 +111,6 @@ border : 1px solid @black; background : @base-color-1; color : @white; - font-weight : bold; } .f-title @@ -133,7 +132,6 @@ { position : absolute; cursor : pointer; - font-style : normal; } .f-not-allowed diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 static/style/src/less/upload.less --- a/static/style/src/less/upload.less +++ b/static/style/src/less/upload.less @@ -1,3 +1,9 @@ +.upload-info +{ + font-weight: normal; + text-align: center; +} + .upload-box { width : 100%; @@ -43,7 +49,7 @@ margin: 0px; } - .remove + .symbol { position: absolute; cursor: pointer; diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/install_and_test_tool_shed_repositories/functional_tests.py --- a/test/install_and_test_tool_shed_repositories/functional_tests.py +++ b/test/install_and_test_tool_shed_repositories/functional_tests.py @@ -254,6 +254,49 @@ success = result.wasSuccessful() return success +def extract_log_data( test_result, from_tool_test=True ): + '''Extract any useful data from the test_result.failures and test_result.errors attributes.''' + for failure in test_result.failures + test_result.errors: + # Record the twill test identifier and information about the tool, so the repository owner can discover which test is failing. + test_id = str( failure[0] ) + if not from_tool_test: + tool_id = None + tool_version = None + else: + tool_id, tool_version = get_tool_info_from_test_id( test_id ) + test_status = dict( test_id=test_id, tool_id=tool_id, tool_version=tool_version ) + log_output = failure[1].replace( '\\n', '\n' ) + # Remove debug output that the reviewer or owner doesn't need. + log_output = re.sub( r'control \d+:.+', r'', log_output ) + log_output = re.sub( r'\n+', r'\n', log_output ) + appending_to = 'output' + tmp_output = {} + output = {} + # Iterate through the functional test output and extract only the important data. Captured logging and stdout are not recorded. + for line in log_output.split( '\n' ): + if line.startswith( 'Traceback' ): + appending_to = 'traceback' + elif '>> end captured' in line or '>> end tool' in line: + continue + elif 'request returned None from get_history' in line: + continue + elif '>> begin captured logging <<' in line: + appending_to = 'logging' + continue + elif '>> begin captured stdout <<' in line: + appending_to = 'stdout' + continue + elif '>> begin captured stderr <<' in line or '>> begin tool stderr <<' in line: + appending_to = 'stderr' + continue + if appending_to not in tmp_output: + tmp_output[ appending_to ] = [] + tmp_output[ appending_to ].append( line ) + for output_type in [ 'stderr', 'traceback' ]: + if output_type in tmp_output: + test_status[ output_type ] = '\n'.join( tmp_output[ output_type ] ) + return test_status + def get_api_url( base, parts=[], params=None, key=None ): if 'api' in parts and parts.index( 'api' ) != 0: parts.pop( parts.index( 'api' ) ) @@ -1054,43 +1097,7 @@ params ) log.debug( 'Revision %s of repository %s installed and passed functional tests.', changeset_revision, name ) else: - # If the functional tests fail, log the output and update the failed changeset revision's metadata record in the tool shed via the API. - for failure in result.failures + result.errors: - # Record the twill test identifier and information about the tool, so the repository owner can discover which test is failing. - test_id = str( failure[0] ) - tool_id, tool_version = get_tool_info_from_test_id( test_id ) - test_status = dict( test_id=test_id, tool_id=tool_id, tool_version=tool_version ) - log_output = failure[1].replace( '\\n', '\n' ) - # Remove debug output that the reviewer or owner doesn't need. - log_output = re.sub( r'control \d+:.+', r'', log_output ) - log_output = re.sub( r'\n+', r'\n', log_output ) - appending_to = 'output' - tmp_output = {} - output = {} - # Iterate through the functional test output and extract only the important data. Captured logging and stdout are not recorded. - for line in log_output.split( '\n' ): - if line.startswith( 'Traceback' ): - appending_to = 'traceback' - elif '>> end captured' in line or '>> end tool' in line: - continue - elif 'request returned None from get_history' in line: - continue - elif '>> begin captured logging <<' in line: - appending_to = 'logging' - continue - elif '>> begin captured stdout <<' in line: - appending_to = 'stdout' - continue - elif '>> begin captured stderr <<' in line or '>> begin tool stderr <<' in line: - appending_to = 'stderr' - continue - if appending_to not in tmp_output: - tmp_output[ appending_to ] = [] - tmp_output[ appending_to ].append( line ) - for output_type in [ 'stderr', 'traceback' ]: - if output_type in tmp_output: - test_status[ output_type ] = '\n'.join( tmp_output[ output_type ] ) - repository_status[ 'failed_tests' ].append( test_status ) + repository_status[ 'failed_tests' ] = extract_log_data( result, from_tool_test=True ) # Call the register_test_result method, which executes a PUT request to the repository_revisions API controller with the outcome # of the tests, and updates tool_test_results with the relevant log data. # This also sets the do_not_test and tools_functionally correct flags to the appropriate values, and updates the time_last_tested @@ -1129,7 +1136,7 @@ name=repository.name, owner=repository.owner, changeset_revision=repository.changeset_revision, - error_message=repository.error_message ) + error_message=extract_log_data( result, from_tool_test=False ) ) repository_status[ 'installation_errors' ][ 'repository_dependencies' ].append( test_result ) params[ 'tools_functionally_correct' ] = False params[ 'test_install_error' ] = True diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/tool_shed/functional/test_0000_basic_repository_features.py --- a/test/tool_shed/functional/test_0000_basic_repository_features.py +++ b/test/tool_shed/functional/test_0000_basic_repository_features.py @@ -38,7 +38,7 @@ self.login( email=common.test_user_1_email, username=common.test_user_1_name ) category = test_db_util.get_category_by_name( 'Test 0000 Basic Repository Features 1' ) strings_displayed = [ 'Repository %s' % "'%s'" % repository_name, - 'Repository %s has been created' % "'%s'" % repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % repository_name ] self.get_or_create_repository( name=repository_name, description=repository_description, long_description=repository_long_description, diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/tool_shed/functional/test_0120_simple_repository_dependency_multiple_owners.py --- a/test/tool_shed/functional/test_0120_simple_repository_dependency_multiple_owners.py +++ b/test/tool_shed/functional/test_0120_simple_repository_dependency_multiple_owners.py @@ -58,7 +58,7 @@ self.logout() self.login( email=common.test_user_2_email, username=common.test_user_2_name ) strings_displayed = [ 'Repository %s' % "'%s'" % datatypes_repository_name, - 'Repository %s has been created' % "'%s'" % datatypes_repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % datatypes_repository_name ] repository = self.get_or_create_repository( name=datatypes_repository_name, description=datatypes_repository_description, long_description=datatypes_repository_long_description, @@ -98,7 +98,7 @@ self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) strings_displayed = [ 'Repository %s' % "'%s'" % tool_repository_name, - 'Repository %s has been created' % "'%s'" % tool_repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % tool_repository_name ] repository = self.get_or_create_repository( name=tool_repository_name, description=tool_repository_description, long_description=tool_repository_long_description, diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/tool_shed/functional/test_0400_repository_component_reviews.py --- a/test/tool_shed/functional/test_0400_repository_component_reviews.py +++ b/test/tool_shed/functional/test_0400_repository_component_reviews.py @@ -93,7 +93,7 @@ self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) strings_displayed = [ 'Repository %s' % "'%s'" % repository_name, - 'Repository %s has been created' % "'%s'" % repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % repository_name ] repository = self.get_or_create_repository( name=repository_name, description=repository_description, long_description=repository_long_description, diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/tool_shed/functional/test_0410_repository_component_review_access_control.py --- a/test/tool_shed/functional/test_0410_repository_component_review_access_control.py +++ b/test/tool_shed/functional/test_0410_repository_component_review_access_control.py @@ -72,7 +72,7 @@ self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) strings_displayed = [ 'Repository %s' % "'%s'" % repository_name, - 'Repository %s has been created' % "'%s'" % repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % repository_name ] repository = self.get_or_create_repository( name=repository_name, description=repository_description, long_description=repository_long_description, diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/tool_shed/functional/test_0420_citable_urls_for_repositories.py --- a/test/tool_shed/functional/test_0420_citable_urls_for_repositories.py +++ b/test/tool_shed/functional/test_0420_citable_urls_for_repositories.py @@ -52,7 +52,7 @@ self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) strings_displayed = [ 'Repository %s' % "'%s'" % repository_name, - 'Repository %s has been created' % "'%s'" % repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % repository_name ] repository = self.get_or_create_repository( name=repository_name, description=repository_description, long_description=repository_long_description, diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/tool_shed/functional/test_0430_browse_utilities.py --- a/test/tool_shed/functional/test_0430_browse_utilities.py +++ b/test/tool_shed/functional/test_0430_browse_utilities.py @@ -57,7 +57,7 @@ self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) strings_displayed = [ 'Repository %s' % "'%s'" % datatypes_repository_name, - 'Repository %s has been created' % "'%s'" % datatypes_repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % datatypes_repository_name ] repository = self.get_or_create_repository( name=datatypes_repository_name, description=datatypes_repository_description, long_description=datatypes_repository_long_description, @@ -85,7 +85,7 @@ self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) strings_displayed = [ 'Repository %s' % "'%s'" % emboss_repository_name, - 'Repository %s has been created' % "'%s'" % emboss_repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % emboss_repository_name ] emboss_repository = self.get_or_create_repository( name=emboss_repository_name, description=emboss_repository_description, long_description=emboss_repository_long_description, @@ -122,7 +122,7 @@ self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) strings_displayed = [ 'Repository %s' % "'%s'" % freebayes_repository_name, - 'Repository %s has been created' % "'%s'" % freebayes_repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % freebayes_repository_name ] repository = self.get_or_create_repository( name=freebayes_repository_name, description=freebayes_repository_description, long_description=freebayes_repository_long_description, diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/tool_shed/functional/test_0450_skip_tool_tests.py --- a/test/tool_shed/functional/test_0450_skip_tool_tests.py +++ b/test/tool_shed/functional/test_0450_skip_tool_tests.py @@ -76,7 +76,7 @@ self.login( email=common.test_user_1_email, username=common.test_user_1_name ) category = test_db_util.get_category_by_name( category_name ) strings_displayed = [ 'Repository %s' % "'%s'" % repository_name, - 'Repository %s has been created' % "'%s'" % repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % repository_name ] repository = self.get_or_create_repository( name=repository_name, description=repository_description, long_description=repository_long_description, diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/tool_shed/functional/test_1120_simple_repository_dependency_multiple_owners.py --- a/test/tool_shed/functional/test_1120_simple_repository_dependency_multiple_owners.py +++ b/test/tool_shed/functional/test_1120_simple_repository_dependency_multiple_owners.py @@ -63,7 +63,7 @@ self.logout() self.login( email=common.test_user_2_email, username=common.test_user_2_name ) strings_displayed = [ 'Repository %s' % "'%s'" % datatypes_repository_name, - 'Repository %s has been created' % "'%s'" % datatypes_repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % datatypes_repository_name ] repository = self.get_or_create_repository( name=datatypes_repository_name, description=datatypes_repository_description, long_description=datatypes_repository_long_description, @@ -105,7 +105,7 @@ self.logout() self.login( email=common.test_user_1_email, username=common.test_user_1_name ) strings_displayed = [ 'Repository %s' % "'%s'" % tool_repository_name, - 'Repository %s has been created' % "'%s'" % tool_repository_name ] + 'Repository %s has been created' % "<b>%s</b>" % tool_repository_name ] repository = self.get_or_create_repository( name=tool_repository_name, description=tool_repository_description, long_description=tool_repository_long_description, diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 test/tool_shed/functional_tests.py --- a/test/tool_shed/functional_tests.py +++ b/test/tool_shed/functional_tests.py @@ -56,6 +56,40 @@ default_galaxy_test_port_max = 9999 default_galaxy_test_host = 'localhost' +# should this serve static resources (scripts, images, styles, etc.) +STATIC_ENABLED = True + +def get_static_settings(): + """Returns dictionary of the settings necessary for a galaxy App + to be wrapped in the static middleware. + + This mainly consists of the filesystem locations of url-mapped + static resources. + """ + cwd = os.getcwd() + static_dir = os.path.join( cwd, 'static' ) + #TODO: these should be copied from universe_wsgi.ini + return dict( + #TODO: static_enabled needed here? + static_enabled = True, + static_cache_time = 360, + static_dir = static_dir, + static_images_dir = os.path.join( static_dir, 'images', '' ), + static_favicon_dir = os.path.join( static_dir, 'favicon.ico' ), + static_scripts_dir = os.path.join( static_dir, 'scripts', '' ), + static_style_dir = os.path.join( static_dir, 'june_2007_style', 'blue' ), + static_robots_txt = os.path.join( static_dir, 'robots.txt' ), + ) + +def get_webapp_global_conf(): + """Get the global_conf dictionary sent as the first argument to app_factory. + """ + # (was originally sent 'dict()') - nothing here for now except static settings + global_conf = dict() + if STATIC_ENABLED: + global_conf.update( get_static_settings() ) + return global_conf + tool_sheds_conf_xml_template = '''<?xml version="1.0"?><tool_sheds><tool_shed name="Embedded tool shed for functional tests" url="http://${shed_url}:${shed_port}/"/> @@ -144,6 +178,9 @@ galaxy_migrated_tool_path = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir ) galaxy_tool_dependency_dir = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir ) os.environ[ 'GALAXY_TEST_TOOL_DEPENDENCY_DIR' ] = galaxy_tool_dependency_dir + hgweb_config_dir = hgweb_config_file_path + os.environ[ 'TEST_HG_WEB_CONFIG_DIR' ] = hgweb_config_dir + print "Directory location for hgweb.config:", hgweb_config_dir if 'TOOL_SHED_TEST_DBURI' in os.environ: toolshed_database_connection = os.environ[ 'TOOL_SHED_TEST_DBURI' ] else: @@ -152,7 +189,29 @@ galaxy_database_connection = os.environ[ 'GALAXY_TEST_DBURI' ] else: galaxy_database_connection = 'sqlite:///' + os.path.join( galaxy_db_path, 'universe_test.sqlite' ) - kwargs = {} + tool_shed_global_conf = get_webapp_global_conf() + tool_shed_global_conf[ '__file__' ] = 'tool_shed_wsgi.ini.sample' + kwargs = dict( admin_users = 'test@bx.psu.edu', + allow_user_creation = True, + allow_user_deletion = True, + database_connection = toolshed_database_connection, + datatype_converters_config_file = 'datatype_converters_conf.xml.sample', + file_path = shed_file_path, + global_conf = tool_shed_global_conf, + hgweb_config_dir = hgweb_config_dir, + job_queue_workers = 5, + id_secret = 'changethisinproductiontoo', + log_destination = "stdout", + new_file_path = new_repos_path, + running_functional_tests = True, + shed_tool_data_table_config = shed_tool_data_table_conf_file, + smtp_server = 'smtp.dummy.string.tld', + email_from = 'functional@localhost', + template_path = 'templates', + tool_path=tool_path, + tool_parse_help = False, + tool_data_table_config_path = galaxy_tool_data_table_conf_file, + use_heartbeat = False ) for dir in [ tool_shed_test_tmp_dir ]: try: os.makedirs( dir ) @@ -162,11 +221,6 @@ print "Tool shed database connection:", toolshed_database_connection print "Galaxy database connection:", galaxy_database_connection - hgweb_config_dir = hgweb_config_file_path - os.environ[ 'TEST_HG_WEB_CONFIG_DIR' ] = hgweb_config_dir - - print "Directory location for hgweb.config:", hgweb_config_dir - # Generate the tool_data_table_conf.xml file. file( galaxy_tool_data_table_conf_file, 'w' ).write( tool_data_table_conf_xml_template ) # Generate the shed_tool_data_table_conf.xml file. @@ -174,7 +228,6 @@ os.environ[ 'TOOL_SHED_TEST_TOOL_DATA_TABLE_CONF' ] = shed_tool_data_table_conf_file # ---- Build Tool Shed Application -------------------------------------------------- toolshedapp = None - global_conf = { '__file__' : 'tool_shed_wsgi.ini.sample' } # if not toolshed_database_connection.startswith( 'sqlite://' ): # kwargs[ 'database_engine_option_max_overflow' ] = '20' if tool_dependency_dir is not None: @@ -183,41 +236,22 @@ kwargs[ 'object_store' ] = 'distributed' kwargs[ 'distributed_object_store_config_file' ] = 'distributed_object_store_conf.xml.sample' + kwargs[ 'global_conf' ] = tool_shed_global_conf if not toolshed_database_connection.startswith( 'sqlite://' ): kwargs[ 'database_engine_option_pool_size' ] = '10' - toolshedapp = ToolshedUniverseApplication( admin_users = 'test@bx.psu.edu', - allow_user_creation = True, - allow_user_deletion = True, - database_connection = toolshed_database_connection, - datatype_converters_config_file = 'datatype_converters_conf.xml.sample', - file_path = shed_file_path, - global_conf = global_conf, - hgweb_config_dir = hgweb_config_dir, - job_queue_workers = 5, - id_secret = 'changethisinproductiontoo', - log_destination = "stdout", - new_file_path = new_repos_path, - running_functional_tests = True, - shed_tool_data_table_config = shed_tool_data_table_conf_file, - smtp_server = 'smtp.dummy.string.tld', - email_from = 'functional@localhost', - template_path = 'templates', - tool_path=tool_path, - tool_parse_help = False, - tool_data_table_config_path = galaxy_tool_data_table_conf_file, - use_heartbeat = False, - **kwargs ) + toolshedapp = ToolshedUniverseApplication( **kwargs ) log.info( "Embedded Toolshed application started" ) # ---- Run tool shed webserver ------------------------------------------------------ tool_shed_server = None - toolshedwebapp = toolshedbuildapp.app_factory( dict( database_connection=toolshed_database_connection ), - use_translogger=False, - static_enabled=False, - app=toolshedapp ) + tool_shed_global_conf[ 'database_connection' ] = toolshed_database_connection + toolshedwebapp = toolshedbuildapp.app_factory( tool_shed_global_conf, + use_translogger=False, + static_enabled=True, + app=toolshedapp ) if tool_shed_test_port is not None: tool_shed_server = httpserver.serve( toolshedwebapp, host=tool_shed_test_host, port=tool_shed_test_port, start_loop=False ) else: @@ -268,50 +302,53 @@ migrated_tool_conf_xml = shed_tool_conf_template_parser.safe_substitute( shed_tool_path=galaxy_migrated_tool_path ) file( galaxy_migrated_tool_conf_file, 'w' ).write( migrated_tool_conf_xml ) os.environ[ 'GALAXY_TEST_SHED_TOOL_CONF' ] = galaxy_shed_tool_conf_file + galaxy_global_conf = get_webapp_global_conf() + galaxy_global_conf[ '__file__' ] = 'universe_wsgi.ini.sample' + + kwargs = dict( allow_user_creation = True, + allow_user_deletion = True, + admin_users = 'test@bx.psu.edu', + allow_library_path_paste = True, + database_connection = galaxy_database_connection, + datatype_converters_config_file = "datatype_converters_conf.xml.sample", + enable_tool_shed_check = True, + file_path = galaxy_file_path, + global_conf = galaxy_global_conf, + hours_between_check = 0.001, + id_secret = 'changethisinproductiontoo', + job_queue_workers = 5, + log_destination = "stdout", + migrated_tools_config = galaxy_migrated_tool_conf_file, + new_file_path = galaxy_tempfiles, + running_functional_tests=True, + shed_tool_data_table_config = shed_tool_data_table_conf_file, + shed_tool_path = galaxy_shed_tool_path, + template_path = "templates", + tool_data_path = tool_data_path, + tool_dependency_dir = galaxy_tool_dependency_dir, + tool_path = tool_path, + tool_config_file = [ galaxy_tool_conf_file, galaxy_shed_tool_conf_file ], + tool_sheds_config_file = galaxy_tool_sheds_conf_file, + tool_parse_help = False, + tool_data_table_config_path = galaxy_tool_data_table_conf_file, + update_integrated_tool_panel = False, + use_heartbeat = False ) # ---- Build Galaxy Application -------------------------------------------------- - galaxy_global_conf = { '__file__' : 'universe_wsgi.ini.sample' } if not galaxy_database_connection.startswith( 'sqlite://' ): kwargs[ 'database_engine_option_pool_size' ] = '10' kwargs[ 'database_engine_option_max_overflow' ] = '20' - galaxyapp = GalaxyUniverseApplication( allow_user_creation = True, - allow_user_deletion = True, - admin_users = 'test@bx.psu.edu', - allow_library_path_paste = True, - database_connection = galaxy_database_connection, - datatype_converters_config_file = "datatype_converters_conf.xml.sample", - enable_tool_shed_check = True, - file_path = galaxy_file_path, - global_conf = global_conf, - hours_between_check = 0.001, - id_secret = 'changethisinproductiontoo', - job_queue_workers = 5, - log_destination = "stdout", - migrated_tools_config = galaxy_migrated_tool_conf_file, - new_file_path = galaxy_tempfiles, - running_functional_tests=True, - shed_tool_data_table_config = shed_tool_data_table_conf_file, - shed_tool_path = galaxy_shed_tool_path, - template_path = "templates", - tool_data_path = tool_data_path, - tool_dependency_dir = galaxy_tool_dependency_dir, - tool_path = tool_path, - tool_config_file = [ galaxy_tool_conf_file, galaxy_shed_tool_conf_file ], - tool_sheds_config_file = galaxy_tool_sheds_conf_file, - tool_parse_help = False, - tool_data_table_config_path = galaxy_tool_data_table_conf_file, - update_integrated_tool_panel = False, - use_heartbeat = False, - **kwargs ) + galaxyapp = GalaxyUniverseApplication( **kwargs ) log.info( "Embedded Galaxy application started" ) # ---- Run galaxy webserver ------------------------------------------------------ galaxy_server = None - galaxywebapp = galaxybuildapp.app_factory( dict( database_file=galaxy_database_connection ), - use_translogger=False, - static_enabled=False, - app=galaxyapp ) + galaxy_global_conf[ 'database_file' ] = galaxy_database_connection + galaxywebapp = galaxybuildapp.app_factory( galaxy_global_conf, + use_translogger=False, + static_enabled=True, + app=galaxyapp ) if galaxy_test_port is not None: galaxy_server = httpserver.serve( galaxywebapp, host=galaxy_test_host, port=galaxy_test_port, start_loop=False ) @@ -412,4 +449,8 @@ return 1 if __name__ == "__main__": - sys.exit( main() ) + try: + sys.exit( main() ) + except Exception, e: + log.exception( str( e ) ) + exit(1) diff -r 397de5e98f7a828aaf78068c348c5633de352a4f -r edf026397ac097296149af86f2088b820a644df0 tool_conf.xml.main --- a/tool_conf.xml.main +++ b/tool_conf.xml.main @@ -336,33 +336,4 @@ <label text="Filtering" id="filtering" /><tool file="ngs_rna/filter_transcripts_via_tracking.xml" /></section> - <label text="RGENETICS" id="rgenetics" /> - <section name="SNP/WGA: Data; Filters" id="rgdat"> - <label text="Data: Import and upload" id="rgimport" /> - <tool file="data_source/upload.xml"/> - <tool file="data_source/access_libraries.xml" /> - <tool file="data_source/hapmapmart.xml" /> - <label text="Data: Filter and Clean" id="rgfilter" /> - <tool file="rgenetics/rgClean.xml"/> - <tool file="rgenetics/rgPedSub.xml"/> - <tool file="rgenetics/rgLDIndep.xml"/> - <label text="Simulate" id="rgsim" /> - <tool file="rgenetics/rgfakePhe.xml"/> - <tool file="rgenetics/rgfakePed.xml"/> - </section> - <section name="SNP/WGA: QC; LD; Plots" id="rgqcplot"> - <label text="QC; Eigenstrat" id="rgvisual" /> - <tool file="rgenetics/rgQC.xml"/> - <tool file="rgenetics/rgEigPCA.xml"/> - <label text="LD; Manhattan/QQ; GRR" id="rgld" /> - <tool file="rgenetics/rgHaploView.xml"/> - <tool file="rgenetics/rgManQQ.xml"/> - <tool file="rgenetics/rgGRR.xml"/> - </section> - <section name="SNP/WGA: Statistical Models" id="rgmodel"> - <tool file="rgenetics/rgCaCo.xml"/> - <tool file="rgenetics/rgTDT.xml"/> - <tool file="rgenetics/rgGLM.xml"/> - <tool file="rgenetics/rgManQQ.xml"/> - </section></toolbox> https://bitbucket.org/galaxy/galaxy-central/commits/6e4f698f10d7/ Changeset: 6e4f698f10d7 User: martenson Date: 2013-09-24 18:34:56 Summary: Merged galaxy/galaxy-central into default Affected #: 7 files diff -r edf026397ac097296149af86f2088b820a644df0 -r 6e4f698f10d70b4fde28fe6815edf240119c5613 lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -2329,9 +2329,12 @@ self.id = None self.user = None + class StoredWorkflow( object, Dictifiable): + dict_collection_visible_keys = ( 'id', 'name', 'published' ) dict_element_visible_keys = ( 'id', 'name', 'published' ) + def __init__( self ): self.id = None self.user = None @@ -2359,7 +2362,11 @@ return rval -class Workflow( object ): +class Workflow( object, Dictifiable ): + + dict_collection_visible_keys = ( 'name', 'has_cycles', 'has_errors' ) + dict_element_visible_keys = ( 'name', 'has_cycles', 'has_errors' ) + def __init__( self ): self.user = None self.name = None @@ -2367,7 +2374,9 @@ self.has_errors = None self.steps = [] + class WorkflowStep( object ): + def __init__( self ): self.id = None self.type = None @@ -2378,36 +2387,48 @@ self.input_connections = [] self.config = None + class WorkflowStepConnection( object ): + def __init__( self ): self.output_step_id = None self.output_name = None self.input_step_id = None self.input_name = None + class WorkflowOutput(object): + def __init__( self, workflow_step, output_name): self.workflow_step = workflow_step self.output_name = output_name + class StoredWorkflowUserShareAssociation( object ): + def __init__( self ): self.stored_workflow = None self.user = None + class StoredWorkflowMenuEntry( object ): + def __init__( self ): self.stored_workflow = None self.user = None self.order_index = None + class WorkflowInvocation( object ): pass + class WorkflowInvocationStep( object ): pass + class MetadataFile( object ): + def __init__( self, dataset = None, name = None ): if isinstance( dataset, HistoryDatasetAssociation ): self.history_dataset = dataset diff -r edf026397ac097296149af86f2088b820a644df0 -r 6e4f698f10d70b4fde28fe6815edf240119c5613 lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py --- a/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py +++ b/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py @@ -10,6 +10,7 @@ from tool_shed.galaxy_install import repository_util from tool_shed.util import common_util from tool_shed.util import encoding_util +from tool_shed.util import workflow_util import tool_shed.util.shed_util_common as suc log = logging.getLogger( __name__ ) @@ -33,6 +34,102 @@ """RESTful controller for interactions with tool shed repositories.""" @web.expose_api + def exported_workflows( self, trans, id, **kwd ): + """ + GET /api/tool_shed_repositories/{encoded_tool_shed_repository_id}/exported_workflows + + Display a list of dictionaries containing information about this tool shed repository's exported workflows. + + :param id: the encoded id of the ToolShedRepository object + """ + # Example URL: http://localhost:8763/api/tool_shed_repositories/f2db41e1fa331b3e/exported_w... + # Since exported workflows are dictionaries with very few attributes that differentiate them from each other, we'll build the + # list based on the following dictionary of those few attributes. + exported_workflows = [] + repository = suc.get_tool_shed_repository_by_id( trans, id ) + metadata = repository.metadata + if metadata: + exported_workflow_tups = metadata.get( 'workflows', [] ) + else: + exported_workflow_tups = [] + for index, exported_workflow_tup in enumerate( exported_workflow_tups ): + # The exported_workflow_tup looks like ( relative_path, exported_workflow_dict ), where the value of relative_path is the location + # on disk (relative to the root of the installed repository) where the exported_workflow_dict file (.ga file) is located. + exported_workflow_dict = exported_workflow_tup[ 1 ] + annotation = exported_workflow_dict.get( 'annotation', '' ) + format_version = exported_workflow_dict.get( 'format-version', '' ) + workflow_name = exported_workflow_dict.get( 'name', '' ) + # Since we don't have an in-memory object with an id, we'll identify the exported workflow via it's location (i.e., index) in the list. + display_dict = dict( index=index, annotation=annotation, format_version=format_version, workflow_name=workflow_name ) + exported_workflows.append( display_dict ) + return exported_workflows + + @web.expose_api + def import_workflow( self, trans, payload, **kwd ): + """ + POST /api/tool_shed_repositories/import_workflow + + Import the specified exported workflow contained in the specified installed tool shed repository into Galaxy. + + :param key: the API key of the Galaxy user with which the imported workflow will be associated. + :param id: the encoded id of the ToolShedRepository object + + The following parameters are included in the payload. + :param index: the index location of the workflow tuple in the list of exported workflows stored in the metadata for the specified repository + """ + api_key = kwd.get( 'key', None ) + if api_key is None: + raise HTTPBadRequest( detail="Missing required parameter 'key' whose value is the API key for the Galaxy user importing the specified workflow." ) + tool_shed_repository_id = kwd.get( 'id', '' ) + if not tool_shed_repository_id: + raise HTTPBadRequest( detail="Missing required parameter 'id'." ) + index = payload.get( 'index', None ) + if index is None: + raise HTTPBadRequest( detail="Missing required parameter 'index'." ) + repository = suc.get_tool_shed_repository_by_id( trans, tool_shed_repository_id ) + exported_workflows = json.from_json_string( self.exported_workflows( trans, tool_shed_repository_id ) ) + # Since we don't have an in-memory object with an id, we'll identify the exported workflow via it's location (i.e., index) in the list. + exported_workflow = exported_workflows[ int( index ) ] + workflow_name = exported_workflow[ 'workflow_name' ] + workflow, status, message = workflow_util.import_workflow( trans, repository, workflow_name ) + if status == 'error': + log.error( message, exc_info=True ) + trans.response.status = 500 + return message + else: + return workflow.to_dict( view='element' ) + + @web.expose_api + def import_workflows( self, trans, **kwd ): + """ + POST /api/tool_shed_repositories/import_workflow + + Import all of the exported workflows contained in the specified installed tool shed repository into Galaxy. + + :param key: the API key of the Galaxy user with which the imported workflows will be associated. + :param id: the encoded id of the ToolShedRepository object + """ + api_key = kwd.get( 'key', None ) + if api_key is None: + raise HTTPBadRequest( detail="Missing required parameter 'key' whose value is the API key for the Galaxy user importing the specified workflow." ) + tool_shed_repository_id = kwd.get( 'id', '' ) + if not tool_shed_repository_id: + raise HTTPBadRequest( detail="Missing required parameter 'id'." ) + repository = suc.get_tool_shed_repository_by_id( trans, tool_shed_repository_id ) + exported_workflows = json.from_json_string( self.exported_workflows( trans, tool_shed_repository_id ) ) + imported_workflow_dicts = [] + for exported_workflow_dict in exported_workflows: + workflow_name = exported_workflow_dict[ 'workflow_name' ] + workflow, status, message = workflow_util.import_workflow( trans, repository, workflow_name ) + if status == 'error': + log.error( message, exc_info=True ) + trans.response.status = 500 + return message + else: + imported_workflow_dicts.append( workflow.to_dict( view='element' ) ) + return imported_workflow_dicts + + @web.expose_api def index( self, trans, **kwd ): """ GET /api/tool_shed_repositories @@ -58,28 +155,6 @@ return message @web.expose_api - def show( self, trans, id, **kwd ): - """ - GET /api/tool_shed_repositories/{encoded_tool_shed_repsository_id} - Display a dictionary containing information about a specified tool_shed_repository. - - :param id: the encoded id of the ToolShedRepository object - """ - # Example URL: http://localhost:8763/api/tool_shed_repositories/df7a1f0c02a5b08e - try: - tool_shed_repository = suc.get_tool_shed_repository_by_id( trans, id ) - tool_shed_repository_dict = tool_shed_repository.as_dict( value_mapper=default_tool_shed_repository_value_mapper( trans, tool_shed_repository ) ) - tool_shed_repository_dict[ 'url' ] = web.url_for( controller='tool_shed_repositories', - action='show', - id=trans.security.encode_id( tool_shed_repository.id ) ) - return tool_shed_repository_dict - except Exception, e: - message = "Error in tool_shed_repositories API in index: " + str( e ) - log.error( message, exc_info=True ) - trans.response.status = 500 - return message - - @web.expose_api def install_repository_revision( self, trans, payload, **kwd ): """ POST /api/tool_shed_repositories/install_repository_revision @@ -412,3 +487,25 @@ tool_shed_repositories.append( repository_dict ) # Display the list of repaired repositories. return tool_shed_repositories + + @web.expose_api + def show( self, trans, id, **kwd ): + """ + GET /api/tool_shed_repositories/{encoded_tool_shed_repsository_id} + Display a dictionary containing information about a specified tool_shed_repository. + + :param id: the encoded id of the ToolShedRepository object + """ + # Example URL: http://localhost:8763/api/tool_shed_repositories/df7a1f0c02a5b08e + try: + tool_shed_repository = suc.get_tool_shed_repository_by_id( trans, id ) + tool_shed_repository_dict = tool_shed_repository.as_dict( value_mapper=default_tool_shed_repository_value_mapper( trans, tool_shed_repository ) ) + tool_shed_repository_dict[ 'url' ] = web.url_for( controller='tool_shed_repositories', + action='show', + id=trans.security.encode_id( tool_shed_repository.id ) ) + return tool_shed_repository_dict + except Exception, e: + message = "Error in tool_shed_repositories API in index: " + str( e ) + log.error( message, exc_info=True ) + trans.response.status = 500 + return message diff -r edf026397ac097296149af86f2088b820a644df0 -r 6e4f698f10d70b4fde28fe6815edf240119c5613 lib/galaxy/webapps/galaxy/buildapp.py --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -178,7 +178,10 @@ # Galaxy API for tool shed features. webapp.mapper.resource( 'tool_shed_repository', 'tool_shed_repositories', - member={ 'repair_repository_revision' : 'POST' }, + member={ 'repair_repository_revision' : 'POST', + 'exported_workflows' : 'GET', + 'import_workflow' : 'POST', + 'import_workflows' : 'POST' }, controller='tool_shed_repositories', name_prefix='tool_shed_repository_', path_prefix='/api', diff -r edf026397ac097296149af86f2088b820a644df0 -r 6e4f698f10d70b4fde28fe6815edf240119c5613 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py --- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py +++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py @@ -358,66 +358,26 @@ @web.expose @web.require_admin def import_workflow( self, trans, workflow_name, repository_id, **kwd ): - """Import a workflow contained in an installed tool shed repository into the Galaxy instance.""" + """Import a workflow contained in an installed tool shed repository into Galaxy.""" message = kwd.get( 'message', '' ) status = kwd.get( 'status', 'done' ) if workflow_name: workflow_name = encoding_util.tool_shed_decode( workflow_name ) - repository = suc.get_tool_shed_repository_by_id( trans, repository_id ) - changeset_revision = repository.changeset_revision - metadata = repository.metadata - workflows = metadata.get( 'workflows', [] ) - tools_metadata = metadata.get( 'tools', [] ) - workflow_dict = None - for workflow_data_tuple in workflows: - # The value of workflow_data_tuple is ( relative_path_to_workflow_file, exported_workflow_dict ). - relative_path_to_workflow_file, exported_workflow_dict = workflow_data_tuple - if exported_workflow_dict[ 'name' ] == workflow_name: - # If the exported workflow is available on disk, import it. - if os.path.exists( relative_path_to_workflow_file ): - workflow_file = open( relative_path_to_workflow_file, 'rb' ) - workflow_data = workflow_file.read() - workflow_file.close() - workflow_dict = json.from_json_string( workflow_data ) + repository = suc.get_tool_shed_repository_by_id( trans, repository_id ) + if repository: + workflow, status, message = workflow_util.import_workflow( trans, repository, workflow_name ) + if workflow: + workflow_name = encoding_util.tool_shed_encode( str( workflow.name ) ) else: - # Use the current exported_workflow_dict. - workflow_dict = exported_workflow_dict - break - if workflow_dict: - # Create workflow if possible. - workflow, missing_tool_tups = workflow_util.get_workflow_from_dict( trans=trans, - workflow_dict=workflow_dict, - tools_metadata=tools_metadata, - repository_id=repository_id, - changeset_revision=changeset_revision ) - # Save the workflow in the Galaxy database. - # Pass workflow_dict along to create annotation at this point - stored_workflow = workflow_util.save_workflow( trans, workflow, workflow_dict ) - # Use the latest version of the saved workflow. - workflow = stored_workflow.latest_workflow - if workflow_name: - workflow.name = workflow_name - # Provide user feedback and show workflow list. - if workflow.has_errors: - message += "Imported, but some steps in this workflow have validation errors. " - status = "error" - if workflow.has_cycles: - message += "Imported, but this workflow contains cycles. " - status = "error" + message += 'Unable to locate a workflow named <b>%s</b> within the installed tool shed repository named <b>%s</b>' % \ + ( str( workflow_name ), str( repository.name ) ) + status = 'error' else: - message += "Workflow <b>%s</b> imported successfully. " % workflow.name - if missing_tool_tups: - # TODO: rework this since it is used in the tool shed, but shoudn't be used in Galaxy. - name_and_id_str = '' - for missing_tool_tup in missing_tool_tups: - tool_id, tool_name, other = missing_tool_tup - name_and_id_str += 'name: %s, id: %s' % ( str( tool_id ), str( tool_name ) ) - log.debug( "The following tools required by this workflow are missing from this Galaxy instance: %s" % name_and_id_str ) + message = 'Invalid repository id <b>%s</b> received.' % str( repository_id ) + status = 'error' else: - message += 'The workflow named %s is not included in the metadata for revision %s of repository %s' % \ - ( str( workflow_name ), str( changeset_revision ), str( repository.name ) ) + message = 'The value of workflow_name is required, but was not received.' status = 'error' - workflow_name = encoding_util.tool_shed_encode( workflow.name ), return trans.response.send_redirect( web.url_for( controller='admin_toolshed', action='view_workflow', workflow_name=workflow_name, diff -r edf026397ac097296149af86f2088b820a644df0 -r 6e4f698f10d70b4fde28fe6815edf240119c5613 lib/tool_shed/util/metadata_util.py --- a/lib/tool_shed/util/metadata_util.py +++ b/lib/tool_shed/util/metadata_util.py @@ -1896,7 +1896,7 @@ changeset_revisions.append( changeset_revision ) add_tool_versions( trans, encoded_id, repository_metadata, changeset_revisions ) elif len( repo ) == 1 and not invalid_file_tups: - message = "Revision '%s' includes no tools, datatypes or exported workflows for which metadata can " % str( repository.tip( trans.app ) ) + message = "Revision <b>%s</b> includes no Galaxy utilities for which metadata can " % str( repository.tip( trans.app ) ) message += "be defined so this revision cannot be automatically installed into a local Galaxy instance." status = "error" if invalid_file_tups: diff -r edf026397ac097296149af86f2088b820a644df0 -r 6e4f698f10d70b4fde28fe6815edf240119c5613 lib/tool_shed/util/workflow_util.py --- a/lib/tool_shed/util/workflow_util.py +++ b/lib/tool_shed/util/workflow_util.py @@ -1,4 +1,5 @@ import logging +import os import galaxy.tools import galaxy.tools.parameters import galaxy.webapps.galaxy.controllers.workflow @@ -151,7 +152,7 @@ def new( self, trans, type, tools_metadata=None, tool_id=None ): """Return module for type and (optional) tool_id initialized with new / default state.""" assert type in self.module_types - return self.module_types[type].new( trans, tool_id ) + return self.module_types[ type ].new( trans, tool_id ) def from_dict( self, trans, repository_id, changeset_revision, step_dict, **kwd ): """Return module initialized from the data in dictionary `step_dict`.""" @@ -219,13 +220,11 @@ tool_errors = module.type == 'tool' and not module.tool module_data_inputs = get_workflow_data_inputs( step, module ) module_data_outputs = get_workflow_data_outputs( step, module, workflow.steps ) - step_dict = { - 'id' : step.order_index, - 'data_inputs' : module_data_inputs, - 'data_outputs' : module_data_outputs, - 'position' : step.position, - 'tool_errors' : tool_errors - } + step_dict = { 'id' : step.order_index, + 'data_inputs' : module_data_inputs, + 'data_outputs' : module_data_outputs, + 'position' : step.position, + 'tool_errors' : tool_errors } input_conn_dict = {} for conn in step.input_connections: input_conn_dict[ conn.input_name ] = dict( id=conn.output_step.order_index, output_name=conn.output_name ) @@ -401,8 +400,9 @@ post_job_actions = step_dict.get( 'post_job_actions', {} ) for name, pja_dict in post_job_actions.items(): trans.model.PostJobAction( pja_dict[ 'action_type' ], - step, pja_dict[ 'output_name' ], - pja_dict[ 'action_arguments' ] ) + step, + pja_dict[ 'output_name' ], + pja_dict[ 'action_arguments' ] ) steps.append( step ) steps_by_external_id[ step_dict[ 'id' ] ] = step # Second pass to deal with connections between steps. @@ -433,6 +433,64 @@ break return module_name +def import_workflow( trans, repository, workflow_name ): + """Import a workflow contained in an installed tool shed repository into Galaxy (this method is called only from Galaxy).""" + status = 'done' + message = '' + changeset_revision = repository.changeset_revision + metadata = repository.metadata + workflows = metadata.get( 'workflows', [] ) + tools_metadata = metadata.get( 'tools', [] ) + workflow_dict = None + for workflow_data_tuple in workflows: + # The value of workflow_data_tuple is ( relative_path_to_workflow_file, exported_workflow_dict ). + relative_path_to_workflow_file, exported_workflow_dict = workflow_data_tuple + if exported_workflow_dict[ 'name' ] == workflow_name: + # If the exported workflow is available on disk, import it. + if os.path.exists( relative_path_to_workflow_file ): + workflow_file = open( relative_path_to_workflow_file, 'rb' ) + workflow_data = workflow_file.read() + workflow_file.close() + workflow_dict = json.from_json_string( workflow_data ) + else: + # Use the current exported_workflow_dict. + workflow_dict = exported_workflow_dict + break + if workflow_dict: + # Create workflow if possible. + workflow, missing_tool_tups = get_workflow_from_dict( trans=trans, + workflow_dict=workflow_dict, + tools_metadata=tools_metadata, + repository_id=repository.id, + changeset_revision=changeset_revision ) + # Save the workflow in the Galaxy database. Pass workflow_dict along to create annotation at this point. + stored_workflow = save_workflow( trans, workflow, workflow_dict ) + # Use the latest version of the saved workflow. + workflow = stored_workflow.latest_workflow + if workflow_name: + workflow.name = workflow_name + # Provide user feedback and show workflow list. + if workflow.has_errors: + message += "Imported, but some steps in this workflow have validation errors. " + status = "error" + if workflow.has_cycles: + message += "Imported, but this workflow contains cycles. " + status = "error" + else: + message += "Workflow <b>%s</b> imported successfully. " % workflow.name + if missing_tool_tups: + name_and_id_str = '' + for missing_tool_tup in missing_tool_tups: + tool_id, tool_name, other = missing_tool_tup + name_and_id_str += 'name: %s, id: %s' % ( str( tool_id ), str( tool_name ) ) + message += "The following tools required by this workflow are missing from this Galaxy instance: %s. " % name_and_id_str + else: + workflow = None + message += 'The workflow named %s is not included in the metadata for revision %s of repository %s' % \ + ( str( workflow_name ), str( changeset_revision ), str( repository.name ) ) + status = 'error' + return workflow, status, message + def save_workflow( trans, workflow, workflow_dict = None): """Use the received in-memory Workflow object for saving to the Galaxy database.""" stored = trans.model.StoredWorkflow() diff -r edf026397ac097296149af86f2088b820a644df0 -r 6e4f698f10d70b4fde28fe6815edf240119c5613 scripts/api/import_workflows_from_installed_tool_shed_repository.py --- /dev/null +++ b/scripts/api/import_workflows_from_installed_tool_shed_repository.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +""" +Import one or more exported workflows contained within a specified tool shed repository installed into Galaxy. + +Here is a working example of how to use this script to repair a repository installed into Galaxy. +python ./import_workflows_from_installed_tool_shed_repository.py -a 22be3b -l http://localhost:8763/ -n workflow_with_tools -o test -r ef45bb64237e -u http://localhost:9009/ +""" + +import os +import sys +import argparse +sys.path.insert( 0, os.path.dirname( __file__ ) ) +from common import display +from common import submit + +def clean_url( url ): + if url.find( '//' ) > 0: + # We have an url that includes a protocol, something like: http://localhost:9009 + items = url.split( '//' ) + return items[ 1 ].rstrip( '/' ) + return url.rstrip( '/' ) + +def main( options ): + api_key = options.api + base_galaxy_url = options.local_url.rstrip( '/' ) + base_tool_shed_url = options.tool_shed_url.rstrip( '/' ) + cleaned_tool_shed_url = clean_url( base_tool_shed_url ) + installed_tool_shed_repositories_url = '%s/api/tool_shed_repositories' % base_galaxy_url + tool_shed_repository_id = None + installed_tool_shed_repositories = display( api_key, installed_tool_shed_repositories_url, return_formatted=False ) + for installed_tool_shed_repository in installed_tool_shed_repositories: + tool_shed = str( installed_tool_shed_repository[ 'tool_shed' ] ) + name = str( installed_tool_shed_repository[ 'name' ] ) + owner = str( installed_tool_shed_repository[ 'owner' ] ) + changeset_revision = str( installed_tool_shed_repository[ 'changeset_revision' ] ) + if tool_shed == cleaned_tool_shed_url and name == options.name and owner == options.owner and changeset_revision == options.changeset_revision: + tool_shed_repository_id = installed_tool_shed_repository[ 'id' ] + break + if tool_shed_repository_id: + # Get the list of exported workflows contained in the installed repository. + url = '%s%s' % ( base_galaxy_url, '/api/tool_shed_repositories/%s/exported_workflows' % str( tool_shed_repository_id ) ) + exported_workflows = display( api_key, url, return_formatted=False ) + if exported_workflows: + # Import all of the workflows in the list of exported workflows. + data = {} + # NOTE: to import a single workflow, add an index to data (e.g., + # data[ 'index' ] = 0 + # and change the url to be ~/import_workflow (simgular). For example, + # url = '%s%s' % ( base_galaxy_url, '/api/tool_shed_repositories/%s/import_workflow' % str( tool_shed_repository_id ) ) + url = '%s%s' % ( base_galaxy_url, '/api/tool_shed_repositories/%s/import_workflows' % str( tool_shed_repository_id ) ) + submit( options.api, url, data ) + else: + print "Invalid tool_shed / name / owner / changeset_revision." + +if __name__ == '__main__': + parser = argparse.ArgumentParser( description='Import workflows contained in an installed tool shed repository via the Galaxy API.' ) + parser.add_argument( "-a", "--api", dest="api", required=True, help="API Key" ) + parser.add_argument( "-u", "--url", dest="tool_shed_url", required=True, help="Tool Shed URL" ) + parser.add_argument( "-l", "--local", dest="local_url", required=True, help="URL of the galaxy instance." ) + parser.add_argument( "-n", "--name", required=True, help="Repository name." ) + parser.add_argument( "-o", "--owner", required=True, help="Repository owner." ) + parser.add_argument( "-r", "--revision", dest="changeset_revision", required=True, help="Repository owner." ) + options = parser.parse_args() + main( options ) https://bitbucket.org/galaxy/galaxy-central/commits/746d156319c1/ Changeset: 746d156319c1 User: martenson Date: 2013-09-24 19:01:15 Summary: repaired a comparison bug Affected #: 1 file diff -r 6e4f698f10d70b4fde28fe6815edf240119c5613 -r 746d156319c1ed2ba80fab5a1a5f181fcd4a1758 templates/base/base_panels.mako --- a/templates/base/base_panels.mako +++ b/templates/base/base_panels.mako @@ -6,7 +6,7 @@ self.message_box_visible = app.config.message_box_visible self.show_inactivity_warning = False if trans.user: - self.show_inactivity_warning = ( ( trans.user.active is False ) and ( app.config.user_activation_on is True) and ( app.config.inactivity_box_content is not None ) ) + self.show_inactivity_warning = ( ( trans.user.active is False ) and ( app.config.user_activation_on ) and ( app.config.inactivity_box_content is not None ) ) self.overlay_visible=False self.active_view=None self.body_class="" 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.