galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
December 2013
- 1 participants
- 207 discussions
commit/galaxy-central: carlfeberhard: History panel: allow anon use of dataset search
by commits-noreply@bitbucket.org 03 Dec '13
by commits-noreply@bitbucket.org 03 Dec '13
03 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5830078f639c/
Changeset: 5830078f639c
User: carlfeberhard
Date: 2013-12-03 21:13:17
Summary: History panel: allow anon use of dataset search
Affected #: 5 files
diff -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 -r 5830078f639cd0b145ca3975f9c621c3d3b69cf1 static/scripts/packed/templates/compiled/history-templates.js
--- a/static/scripts/packed/templates/compiled/history-templates.js
+++ b/static/scripts/packed/templates/compiled/history-templates.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-body"]=b(function(g,r,p,k,z){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);z=z||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';if(B=p.body){B=B.call(D,{hash:{},data:C})}else{B=D.body;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+='\n </div>\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';return A}function m(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';B=p["if"].call(D,D.misc_blurb,{hash:{},inverse:o.noop,fn:o.program(4,l,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.data_type,{hash:{},inverse:o.noop,fn:o.program(6,j,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.metadata_dbkey,{hash:{},inverse:o.noop,fn:o.program(9,f,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.misc_info,{hash:{},inverse:o.noop,fn:o.program(12,x,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';B=p.unless.call(D,D.deleted,{hash:{},inverse:o.noop,fn:o.program(14,w,C),data:C});if(B||B===0){A+=B}A+="\n\n ";return A}function l(D,C){var A="",B;A+='\n <div class="dataset-blurb">\n <span class="value">';if(B=p.misc_blurb){B=B.call(D,{hash:{},data:C})}else{B=D.misc_blurb;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function j(E,D){var A="",C,B;A+='\n <div class="dataset-datatype">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(7,i,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">';if(C=p.data_type){C=C.call(E,{hash:{},data:D})}else{C=E.data_type;C=typeof C===e?C.apply(E):C}A+=d(C)+"</span>\n </div>\n ";return A}function i(B,A){return"format"}function f(E,D){var A="",C,B;A+='\n <div class="dataset-dbkey">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(10,y,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">\n ';if(C=p.metadata_dbkey){C=C.call(E,{hash:{},data:D})}else{C=E.metadata_dbkey;C=typeof C===e?C.apply(E):C}A+=d(C)+"\n </span>\n </div>\n ";return A}function y(B,A){return"database"}function x(D,C){var A="",B;A+='\n <div class="dataset-info">\n <span class="value">';if(B=p.misc_info){B=B.call(D,{hash:{},data:C})}else{B=D.misc_info;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function w(D,C){var A="",B;A+='\n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="dataset-display-applications">\n ';B=p.each.call(D,D.display_apps,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p.each.call(D,D.display_types,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-peek">\n ';B=p["if"].call(D,D.peek,{hash:{},inverse:o.noop,fn:o.program(19,s,C),data:C});if(B||B===0){A+=B}A+="\n </div>\n\n ";return A}function v(D,C){var A="",B;A+='\n <div class="display-application">\n <span class="display-application-location">';if(B=p.label){B=B.call(D,{hash:{},data:C})}else{B=D.label;B=typeof B===e?B.apply(D):B}A+=d(B)+'</span>\n <span class="display-application-links">\n ';B=p.each.call(D,D.links,{hash:{},inverse:o.noop,fn:o.program(16,u,C),data:C});if(B||B===0){A+=B}A+="\n </span>\n </div>\n ";return A}function u(E,D){var A="",C,B;A+='\n <a target="';if(C=p.target){C=C.call(E,{hash:{},data:D})}else{C=E.target;C=typeof C===e?C.apply(E):C}A+=d(C)+'" href="';if(C=p.href){C=C.call(E,{hash:{},data:D})}else{C=E.href;C=typeof C===e?C.apply(E):C}A+=d(C)+'">';B={hash:{},inverse:o.noop,fn:o.program(17,t,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+="</a>\n ";return A}function t(C,B){var A;if(A=p.text){A=A.call(C,{hash:{},data:B})}else{A=C.text;A=typeof A===e?A.apply(C):A}return d(A)}function s(D,C){var A="",B;A+='\n <pre class="peek">';if(B=p.peek){B=B.call(D,{hash:{},data:C})}else{B=D.peek;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+="</pre>\n ";return A}q+='<div class="dataset-body">\n ';h=p["if"].call(r,r.body,{hash:{},inverse:o.program(3,m,z),fn:o.program(1,n,z),data:z});if(h||h===0){q+=h}q+="\n</div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-skeleton"]=b(function(f,r,p,k,w){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,f.helpers);w=w||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(B,A){var x="",z,y;x+='\n <div class="errormessagesmall">\n ';y={hash:{},inverse:o.noop,fn:o.program(2,m,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+=":\n ";y={hash:{},inverse:o.noop,fn:o.program(4,l,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </div>\n ";return x}function m(y,x){return"There was an error getting the data for this dataset"}function l(z,y){var x;if(x=p.error){x=x.call(z,{hash:{},data:y})}else{x=z.error;x=typeof x===e?x.apply(z):x}return d(x)}function j(A,z){var x="",y;x+="\n ";y=p["if"].call(A,A.purged,{hash:{},inverse:o.program(10,v,z),fn:o.program(7,i,z),data:z});if(y||y===0){x+=y}x+="\n ";return x}function i(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(8,g,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n\n ";return x}function g(y,x){return"This dataset has been deleted and removed from disk."}function v(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(11,u,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n \n Click <a href="javascript:void(0);" class="dataset-undelete">here</a> to undelete it\n or <a href="javascript:void(0);" class="dataset-purge">here</a> to immediately remove it from disk\n </strong></div>\n ';return x}function u(y,x){return"This dataset has been deleted."}function t(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(14,s,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n Click <a href="javascript:void(0);" class="dataset-unhide">here</a> to unhide it\n </strong></div>\n ';return x}function s(y,x){return"This dataset has been hidden."}q+='<div class="dataset hda">\n <div class="dataset-warnings">\n ';h=p["if"].call(r,r.error,{hash:{},inverse:o.noop,fn:o.program(1,n,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p["if"].call(r,r.deleted,{hash:{},inverse:o.noop,fn:o.program(6,j,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p.unless.call(r,r.visible,{hash:{},inverse:o.noop,fn:o.program(13,t,w),data:w});if(h||h===0){q+=h}q+='\n </div>\n\n <div class="dataset-selector"><span class="fa fa-2x fa-square-o"></span></div>\n <div class="dataset-primary-actions"></div>\n <div class="dataset-title-bar clear">\n <span class="dataset-state-icon state-icon"></span>\n <div class="dataset-title">\n <span class="hda-hid">';if(h=p.hid){h=h.call(r,{hash:{},data:w})}else{h=r.hid;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n <span class="dataset-name">';if(h=p.name){h=h.call(r,{hash:{},data:w})}else{h=r.name;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n </div>\n </div>\n\n <div class="dataset-body"></div>\n</div>';return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(g,r,p,k,u){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);u=u||{};var q="",i,f,o=this,e="function",c=p.blockHelperMissing,d=this.escapeExpression;function n(z,y){var v="",x,w;v+='\n <div class="history-name" title="';w={hash:{},inverse:o.noop,fn:o.program(2,m,y),data:y};if(x=p.local){x=x.call(z,w)}else{x=z.local;x=typeof x===e?x.apply(z):x}if(!p.local){x=c.call(z,x,w)}if(x||x===0){v+=x}v+='">\n ';if(x=p.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===e?x.apply(z):x}v+=d(x)+"\n </div>\n ";return v}function m(w,v){return"You must be logged in to edit your history name"}function l(y,x){var v="",w;v+='\n <div class="history-size">';if(w=p.nice_size){w=w.call(y,{hash:{},data:x})}else{w=y.nice_size;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function j(y,x){var v="",w;v+='\n \n <div class="';if(w=p.status){w=w.call(y,{hash:{},data:x})}else{w=y.status;w=typeof w===e?w.apply(y):w}v+=d(w)+'message">';if(w=p.message){w=w.call(y,{hash:{},data:x})}else{w=y.message;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function h(w,v){return"You are over your disk quota"}function t(w,v){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(w,v){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(4,l,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(6,j,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(8,h,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(10,t,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(12,s,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(h,s,q,l,w){this.compilerInfo=[4,">= 1.0.0"];q=this.merge(q,h.helpers);w=w||{};var r="",i,f,p=this,e="function",c=q.blockHelperMissing,d=this.escapeExpression;function o(B,A){var x="",z,y;x+='\n <div class="history-name" title="';y={hash:{},inverse:p.noop,fn:p.program(2,n,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='">\n ';if(z=q.name){z=z.call(B,{hash:{},data:A})}else{z=B.name;z=typeof z===e?z.apply(B):z}x+=d(z)+"\n </div>\n ";return x}function n(y,x){return"Click to rename history"}function m(A,z){var x="",y;x+='\n <div class="history-size">';if(y=q.nice_size){y=y.call(A,{hash:{},data:z})}else{y=A.nice_size;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function k(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:p.noop,fn:p.program(7,j,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n ";return x}function j(y,x){return"You are currently viewing a deleted history!"}function g(A,z){var x="",y;x+='\n \n <div class="';if(y=q.status){y=y.call(A,{hash:{},data:z})}else{y=A.status;y=typeof y===e?y.apply(A):y}x+=d(y)+'message">';if(y=q.message){y=y.call(A,{hash:{},data:z})}else{y=A.message;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function v(y,x){return"You are over your disk quota"}function u(y,x){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function t(y,x){return"Your history is empty. Click 'Get Data' on the left pane to start"}r+='<div class="history-controls">\n\n <div class="history-title">\n ';i=q["if"].call(s,s.name,{hash:{},inverse:p.noop,fn:p.program(1,o,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=q["if"].call(s,s.nice_size,{hash:{},inverse:p.noop,fn:p.program(4,m,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n ';i=q["if"].call(s,s.deleted,{hash:{},inverse:p.noop,fn:p.program(6,k,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="message-container">\n ';i=q["if"].call(s,s.message,{hash:{},inverse:p.noop,fn:p.program(9,g,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:p.noop,fn:p.program(11,v,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+=".\n ";f={hash:{},inverse:p.noop,fn:p.program(13,u,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:p.noop,fn:p.program(15,t,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+="\n </div>";return r})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-body"]=b(function(g,r,p,k,z){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);z=z||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';if(B=p.body){B=B.call(D,{hash:{},data:C})}else{B=D.body;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+='\n </div>\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';return A}function m(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';B=p["if"].call(D,D.misc_blurb,{hash:{},inverse:o.noop,fn:o.program(4,l,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.data_type,{hash:{},inverse:o.noop,fn:o.program(6,j,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.metadata_dbkey,{hash:{},inverse:o.noop,fn:o.program(9,f,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.misc_info,{hash:{},inverse:o.noop,fn:o.program(12,x,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';B=p.unless.call(D,D.deleted,{hash:{},inverse:o.noop,fn:o.program(14,w,C),data:C});if(B||B===0){A+=B}A+="\n\n ";return A}function l(D,C){var A="",B;A+='\n <div class="dataset-blurb">\n <span class="value">';if(B=p.misc_blurb){B=B.call(D,{hash:{},data:C})}else{B=D.misc_blurb;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function j(E,D){var A="",C,B;A+='\n <div class="dataset-datatype">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(7,i,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">';if(C=p.data_type){C=C.call(E,{hash:{},data:D})}else{C=E.data_type;C=typeof C===e?C.apply(E):C}A+=d(C)+"</span>\n </div>\n ";return A}function i(B,A){return"format"}function f(E,D){var A="",C,B;A+='\n <div class="dataset-dbkey">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(10,y,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">\n ';if(C=p.metadata_dbkey){C=C.call(E,{hash:{},data:D})}else{C=E.metadata_dbkey;C=typeof C===e?C.apply(E):C}A+=d(C)+"\n </span>\n </div>\n ";return A}function y(B,A){return"database"}function x(D,C){var A="",B;A+='\n <div class="dataset-info">\n <span class="value">';if(B=p.misc_info){B=B.call(D,{hash:{},data:C})}else{B=D.misc_info;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function w(D,C){var A="",B;A+='\n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="dataset-display-applications">\n ';B=p.each.call(D,D.display_apps,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p.each.call(D,D.display_types,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-peek">\n ';B=p["if"].call(D,D.peek,{hash:{},inverse:o.noop,fn:o.program(19,s,C),data:C});if(B||B===0){A+=B}A+="\n </div>\n\n ";return A}function v(D,C){var A="",B;A+='\n <div class="display-application">\n <span class="display-application-location">';if(B=p.label){B=B.call(D,{hash:{},data:C})}else{B=D.label;B=typeof B===e?B.apply(D):B}A+=d(B)+'</span>\n <span class="display-application-links">\n ';B=p.each.call(D,D.links,{hash:{},inverse:o.noop,fn:o.program(16,u,C),data:C});if(B||B===0){A+=B}A+="\n </span>\n </div>\n ";return A}function u(E,D){var A="",C,B;A+='\n <a target="';if(C=p.target){C=C.call(E,{hash:{},data:D})}else{C=E.target;C=typeof C===e?C.apply(E):C}A+=d(C)+'" href="';if(C=p.href){C=C.call(E,{hash:{},data:D})}else{C=E.href;C=typeof C===e?C.apply(E):C}A+=d(C)+'">';B={hash:{},inverse:o.noop,fn:o.program(17,t,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+="</a>\n ";return A}function t(C,B){var A;if(A=p.text){A=A.call(C,{hash:{},data:B})}else{A=C.text;A=typeof A===e?A.apply(C):A}return d(A)}function s(D,C){var A="",B;A+='\n <pre class="peek">';if(B=p.peek){B=B.call(D,{hash:{},data:C})}else{B=D.peek;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+="</pre>\n ";return A}q+='<div class="dataset-body">\n ';h=p["if"].call(r,r.body,{hash:{},inverse:o.program(3,m,z),fn:o.program(1,n,z),data:z});if(h||h===0){q+=h}q+="\n</div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-skeleton"]=b(function(f,r,p,k,w){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,f.helpers);w=w||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(B,A){var x="",z,y;x+='\n <div class="errormessagesmall">\n ';y={hash:{},inverse:o.noop,fn:o.program(2,m,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+=":\n ";y={hash:{},inverse:o.noop,fn:o.program(4,l,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </div>\n ";return x}function m(y,x){return"There was an error getting the data for this dataset"}function l(z,y){var x;if(x=p.error){x=x.call(z,{hash:{},data:y})}else{x=z.error;x=typeof x===e?x.apply(z):x}return d(x)}function j(A,z){var x="",y;x+="\n ";y=p["if"].call(A,A.purged,{hash:{},inverse:o.program(10,v,z),fn:o.program(7,i,z),data:z});if(y||y===0){x+=y}x+="\n ";return x}function i(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(8,g,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n\n ";return x}function g(y,x){return"This dataset has been deleted and removed from disk."}function v(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(11,u,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n \n Click <a href="javascript:void(0);" class="dataset-undelete">here</a> to undelete it\n or <a href="javascript:void(0);" class="dataset-purge">here</a> to immediately remove it from disk\n </strong></div>\n ';return x}function u(y,x){return"This dataset has been deleted."}function t(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(14,s,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n Click <a href="javascript:void(0);" class="dataset-unhide">here</a> to unhide it\n </strong></div>\n ';return x}function s(y,x){return"This dataset has been hidden."}q+='<div class="dataset hda">\n <div class="dataset-warnings">\n ';h=p["if"].call(r,r.error,{hash:{},inverse:o.noop,fn:o.program(1,n,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p["if"].call(r,r.deleted,{hash:{},inverse:o.noop,fn:o.program(6,j,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p.unless.call(r,r.visible,{hash:{},inverse:o.noop,fn:o.program(13,t,w),data:w});if(h||h===0){q+=h}q+='\n </div>\n\n <div class="dataset-selector"><span class="fa fa-2x fa-square-o"></span></div>\n <div class="dataset-primary-actions"></div>\n <div class="dataset-title-bar clear">\n <span class="dataset-state-icon state-icon"></span>\n <div class="dataset-title">\n <span class="hda-hid">';if(h=p.hid){h=h.call(r,{hash:{},data:w})}else{h=r.hid;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n <span class="dataset-name">';if(h=p.name){h=h.call(r,{hash:{},data:w})}else{h=r.name;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n </div>\n </div>\n\n <div class="dataset-body"></div>\n</div>';return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(g,r,p,k,u){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);u=u||{};var q="",i,f,o=this,e="function",c=p.blockHelperMissing,d=this.escapeExpression;function n(z,y){var v="",x,w;v+='\n <div class="history-name" title="';w={hash:{},inverse:o.noop,fn:o.program(2,m,y),data:y};if(x=p.local){x=x.call(z,w)}else{x=z.local;x=typeof x===e?x.apply(z):x}if(!p.local){x=c.call(z,x,w)}if(x||x===0){v+=x}v+='">\n ';if(x=p.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===e?x.apply(z):x}v+=d(x)+"\n </div>\n ";return v}function m(w,v){return"You must be logged in to edit your history name"}function l(y,x){var v="",w;v+='\n <div class="history-size">';if(w=p.nice_size){w=w.call(y,{hash:{},data:x})}else{w=y.nice_size;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function j(y,x){var v="",w;v+='\n \n <div class="';if(w=p.status){w=w.call(y,{hash:{},data:x})}else{w=y.status;w=typeof w===e?w.apply(y):w}v+=d(w)+'message">';if(w=p.message){w=w.call(y,{hash:{},data:x})}else{w=y.message;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function h(w,v){return"You are over your disk quota"}function t(w,v){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(w,v){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(4,l,u),data:u});if(i||i===0){q+=i}q+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(6,j,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(8,h,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(10,t,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(12,s,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(h,s,q,l,w){this.compilerInfo=[4,">= 1.0.0"];q=this.merge(q,h.helpers);w=w||{};var r="",i,f,p=this,e="function",c=q.blockHelperMissing,d=this.escapeExpression;function o(B,A){var x="",z,y;x+='\n <div class="history-name" title="';y={hash:{},inverse:p.noop,fn:p.program(2,n,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='">\n ';if(z=q.name){z=z.call(B,{hash:{},data:A})}else{z=B.name;z=typeof z===e?z.apply(B):z}x+=d(z)+"\n </div>\n ";return x}function n(y,x){return"Click to rename history"}function m(A,z){var x="",y;x+='\n <div class="history-size">';if(y=q.nice_size){y=y.call(A,{hash:{},data:z})}else{y=A.nice_size;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function k(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:p.noop,fn:p.program(7,j,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n ";return x}function j(y,x){return"You are currently viewing a deleted history!"}function g(A,z){var x="",y;x+='\n \n <div class="';if(y=q.status){y=y.call(A,{hash:{},data:z})}else{y=A.status;y=typeof y===e?y.apply(A):y}x+=d(y)+'message">';if(y=q.message){y=y.call(A,{hash:{},data:z})}else{y=A.message;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function v(y,x){return"You are over your disk quota"}function u(y,x){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function t(y,x){return"Your history is empty. Click 'Get Data' on the left pane to start"}r+='<div class="history-controls">\n\n <div class="history-title">\n ';i=q["if"].call(s,s.name,{hash:{},inverse:p.noop,fn:p.program(1,o,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=q["if"].call(s,s.nice_size,{hash:{},inverse:p.noop,fn:p.program(4,m,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n ';i=q["if"].call(s,s.deleted,{hash:{},inverse:p.noop,fn:p.program(6,k,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="message-container">\n ';i=q["if"].call(s,s.message,{hash:{},inverse:p.noop,fn:p.program(9,g,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:p.noop,fn:p.program(11,v,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+=".\n ";f={hash:{},inverse:p.noop,fn:p.program(13,u,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:p.noop,fn:p.program(15,t,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+="\n </div>";return r})})();
\ No newline at end of file
diff -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 -r 5830078f639cd0b145ca3975f9c621c3d3b69cf1 static/scripts/packed/templates/compiled/template-history-historyPanel-anon.js
--- a/static/scripts/packed/templates/compiled/template-history-historyPanel-anon.js
+++ b/static/scripts/packed/templates/compiled/template-history-historyPanel-anon.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(g,r,p,k,u){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);u=u||{};var q="",i,f,o=this,e="function",c=p.blockHelperMissing,d=this.escapeExpression;function n(z,y){var v="",x,w;v+='\n <div class="history-name" title="';w={hash:{},inverse:o.noop,fn:o.program(2,m,y),data:y};if(x=p.local){x=x.call(z,w)}else{x=z.local;x=typeof x===e?x.apply(z):x}if(!p.local){x=c.call(z,x,w)}if(x||x===0){v+=x}v+='">\n ';if(x=p.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===e?x.apply(z):x}v+=d(x)+"\n </div>\n ";return v}function m(w,v){return"You must be logged in to edit your history name"}function l(y,x){var v="",w;v+='\n <div class="history-size">';if(w=p.nice_size){w=w.call(y,{hash:{},data:x})}else{w=y.nice_size;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function j(y,x){var v="",w;v+='\n \n <div class="';if(w=p.status){w=w.call(y,{hash:{},data:x})}else{w=y.status;w=typeof w===e?w.apply(y):w}v+=d(w)+'message">';if(w=p.message){w=w.call(y,{hash:{},data:x})}else{w=y.message;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function h(w,v){return"You are over your disk quota"}function t(w,v){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(w,v){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(4,l,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(6,j,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(8,h,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(10,t,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(12,s,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(g,r,p,k,u){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);u=u||{};var q="",i,f,o=this,e="function",c=p.blockHelperMissing,d=this.escapeExpression;function n(z,y){var v="",x,w;v+='\n <div class="history-name" title="';w={hash:{},inverse:o.noop,fn:o.program(2,m,y),data:y};if(x=p.local){x=x.call(z,w)}else{x=z.local;x=typeof x===e?x.apply(z):x}if(!p.local){x=c.call(z,x,w)}if(x||x===0){v+=x}v+='">\n ';if(x=p.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===e?x.apply(z):x}v+=d(x)+"\n </div>\n ";return v}function m(w,v){return"You must be logged in to edit your history name"}function l(y,x){var v="",w;v+='\n <div class="history-size">';if(w=p.nice_size){w=w.call(y,{hash:{},data:x})}else{w=y.nice_size;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function j(y,x){var v="",w;v+='\n \n <div class="';if(w=p.status){w=w.call(y,{hash:{},data:x})}else{w=y.status;w=typeof w===e?w.apply(y):w}v+=d(w)+'message">';if(w=p.message){w=w.call(y,{hash:{},data:x})}else{w=y.message;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function h(w,v){return"You are over your disk quota"}function t(w,v){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(w,v){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(4,l,u),data:u});if(i||i===0){q+=i}q+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(6,j,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(8,h,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(10,t,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(12,s,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();
\ No newline at end of file
diff -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 -r 5830078f639cd0b145ca3975f9c621c3d3b69cf1 static/scripts/templates/compiled/history-templates.js
--- a/static/scripts/templates/compiled/history-templates.js
+++ b/static/scripts/templates/compiled/history-templates.js
@@ -383,7 +383,7 @@
buffer += "\n </div>\n\n <div class=\"history-subtitle clear\">\n ";
stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n </div>\n\n <div class=\"message-container\">\n ";
+ buffer += "\n\n <div class=\"history-secondary-actions\"></div>\n </div>\n\n <div class=\"message-container\">\n ";
stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"quota-message errormessage\">\n ";
diff -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 -r 5830078f639cd0b145ca3975f9c621c3d3b69cf1 static/scripts/templates/compiled/template-history-historyPanel-anon.js
--- a/static/scripts/templates/compiled/template-history-historyPanel-anon.js
+++ b/static/scripts/templates/compiled/template-history-historyPanel-anon.js
@@ -79,7 +79,7 @@
buffer += "\n </div>\n\n <div class=\"history-subtitle clear\">\n ";
stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n </div>\n\n <div class=\"message-container\">\n ";
+ buffer += "\n\n <div class=\"history-secondary-actions\"></div>\n </div>\n\n <div class=\"message-container\">\n ";
stack1 = helpers['if'].call(depth0, depth0.message, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n </div>\n\n <div class=\"quota-message errormessage\">\n ";
diff -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 -r 5830078f639cd0b145ca3975f9c621c3d3b69cf1 static/scripts/templates/history-templates.html
--- a/static/scripts/templates/history-templates.html
+++ b/static/scripts/templates/history-templates.html
@@ -69,6 +69,8 @@
{{#if nice_size }}
<div class="history-size">{{nice_size}}</div>
{{/if}}
+
+ <div class="history-secondary-actions"></div></div><div class="message-container">
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
03 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a6044ab1ffe7/
Changeset: a6044ab1ffe7
User: carlfeberhard
Date: 2013-12-03 21:03:32
Summary: History panel: allow searching datasets: name, tags, annotation, dbkey, file_ext, blurb, and info will be searched when enter is pressed in the search field, include whitespace by enclosing search term in double quotes, allow specifying which field to search by using the idiom 'field=term' where field is any of the previous field names (or more user-centric aliases: database for dbkey, etc.), (GUI filters as an alternate means to accomplish field specifiers to be added soon); Allow showing and hiding search input; Tweak style on panel-header buttons; pack scripts
Affected #: 14 files
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/mvc/history/history-panel.js
--- a/static/scripts/mvc/history/history-panel.js
+++ b/static/scripts/mvc/history/history-panel.js
@@ -664,6 +664,13 @@
this._renderTags( $newRender );
this._renderAnnotation( $newRender );
}
+ // button for opening search
+ faIconButton({
+ title : _l( 'Search datasets' ),
+ classes : 'history-search-btn',
+ faIcon : 'fa-search'
+ }).prependTo( $newRender.find( '.history-secondary-actions' ) );
+
this._setUpBehaviours( $newRender );
// render hda views (if any and any shown (show_deleted/hidden)
@@ -696,10 +703,9 @@
});
},
- /** Set up HistoryPanel js/widget behaviours
- */
- //TODO: these should be either sub-MVs, or handled by events
+ /** Set up HistoryPanel js/widget behaviours */
_setUpBehaviours : function( $where ){
+ //TODO: these should be either sub-MVs, or handled by events
$where = $where || this.$el;
$where.find( '[title]' ).tooltip({ placement: 'bottom' });
@@ -757,7 +763,8 @@
events : {
// allow (error) messages to be clicked away
//TODO: switch to common close (X) idiom
- 'click .message-container' : 'clearMessages'
+ 'click .message-container' : 'clearMessages',
+ 'click .history-search-btn' : 'toggleSearchControls'
},
/** Update the history size display (curr. upper right of panel).
@@ -843,7 +850,11 @@
$searchInput = this.renderSearchControls().hide();
this.$el.find( '.history-title' ).before( $searchInput );
}
- $searchInput.slideToggle( this.fxSpeed );
+ $searchInput.slideToggle( this.fxSpeed, function(){
+ if( $( this ).is( ':visible' ) ){
+ $( this ).find( 'input' ).focus();
+ }
+ });
},
// ........................................................................ multi-select of hdas
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/mvc/ui.js
--- a/static/scripts/mvc/ui.js
+++ b/static/scripts/mvc/ui.js
@@ -590,7 +590,7 @@
// a button for clearing the search bar, placed on the right hand side
function clearBtnTemplate(){
- return '<span class="search-clear fa fa-times-circle"></span>';
+ return '<span class="search-clear fa fa-times-circle" title="' + _l( 'clear search (esc)' ) + '"></span>';
}
function $clearBtn(){
//TODO: to base.less
@@ -602,6 +602,7 @@
'line-height': '23px',
color : 'grey'
})
+ .tooltip({ placement: 'bottom' })
.click( function( event ){
clearSearchInput.call( this, event );
});
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/packed/galaxy.masthead.js
--- a/static/scripts/packed/galaxy.masthead.js
+++ b/static/scripts/packed/galaxy.masthead.js
@@ -1,1 +1,1 @@
-define(["utils/galaxy.utils"],function(c){var a=Backbone.View.extend({el_masthead:"#everything",options:null,list:{},itemLast:null,itemCounter:0,$background:null,backgroundVisible:false,initialize:function(f){this.options=f;$("body").off();this.setElement($(this._template(f)));$(this.el_masthead).append($(this.el));this.$background=$(this.el).find("#masthead-background");var e=this;window.onbeforeunload=function(){var h="";for(key in e.list){if(e.list[key].options.on_unload){var g=e.list[key].options.on_unload();if(g){h+=g+" "}}}if(h!=""){return h}}},events:{click:"_eventRefresh",mousedown:function(f){f.preventDefault()}},append:function(e){return this._add(e,true)},prepend:function(e){return this._add(e,false)},_add:function(g,f){var e=$(this.el).find("#"+g.mastheadLocation);if(e){var h="masthead-item-"+this.itemCounter++;var i=$(g.el);i.attr("id",h);i.addClass("masthead-item");if(f){e.append(i)}else{e.prepend(i)}this.list[h]=g;return h}return null},_eventRefresh:function(h){var i=$(h.target).closest(".masthead-item");if(i.length){i=i.attr("id")}if(this.itemLast&&this.itemLast!=i){var g=this.list[this.itemLast];if(g){if(g.mastheadReset){g.mastheadReset()}}}var f=false;if(i){var g=this.list[i];if(g){if(g.mastheadReset){if(this.itemLast==i){f=this.backgroundVisible?false:true}else{f=true}}}}if(f){this.$background.show()}else{this.$background.hide()}this.backgroundVisible=f;this.itemLast=i},_templateItem:function(e){return'<div id="'+e+'" class="masthead-item"></div>'},_template:function(e){return'<div><div id="masthead" class="navbar navbar-fixed-top navbar-inverse"><div style="position: relative; right: -50%; float: left;"><div id="navbar" style="display: block; position: relative; right: 50%;"></div></div><div class="navbar-brand"><a href="'+e.logo_url+'"><img border="0" src="'+galaxy_config.root+'static/images/galaxyIcon_noText.png"><span id="brand"> Galaxy '+e.brand+'</span></a></div><div class="quota-meter-container"></div><div id="iconbar" class="iconbar"></div></div><div id="masthead-background" style="display: none; position: absolute; top: 33px; width: 100%; height: 100%; z-index: 1010"></div></div>'}});var b=Backbone.View.extend({options:{id:"galaxy-icon",icon:"fa-cog",tooltip:"galaxy-icon",with_number:false,on_click:function(){alert("clicked")},on_unload:null,visible:true},mastheadLocation:"iconbar",initialize:function(f){if(f){this.options=_.defaults(f,this.options)}this.setElement($(this._template(this.options)));var e=this;$(this.el).find(".icon").tooltip({title:this.options.tooltip,placement:"bottom"}).on("mouseup",e.options.on_click);if(!this.options.visible){this.hide()}},show:function(){$(this.el).css({visibility:"visible"})},hide:function(){$(this.el).css({visibility:"hidden"})},icon:function(e){$(this.el).find(".icon").removeClass(this.options.icon).addClass(e);this.options.icon=e},toggle:function(){$(this.el).addClass("toggle")},untoggle:function(){$(this.el).removeClass("toggle")},number:function(e){$(this.el).find(".number").text(e)},_template:function(f){var e="<div id="+f.id+' class="symbol"><div class="icon fa fa-2x '+f.icon+'"></div>';if(f.with_number){e+='<div class="number"></div>'}e+="</div>";return e}});var d=Backbone.View.extend({options:{id:"",title:"Title",target:"_parent",content:"",type:"url",scratchbook:false,on_unload:null,visible:true},mastheadLocation:"navbar",$menu:null,menuVisible:false,events:{"click .head":"_eventClickHead"},initialize:function(e){if(e){this.options=_.defaults(e,this.options)}if(this.options.content&&this.options.content.indexOf("//")===-1){this.options.content=galaxy_config.root+this.options.content}this.setElement($(this._template(this.options)));if(!this.options.visible){this.hide()}},show:function(){$(this.el).css({visibility:"visible"})},hide:function(){$(this.el).css({visibility:"hidden"})},addMenu:function(g){var h={title:"Title",content:"",type:"url",target:"_parent",scratchbook:false,divider:false};if(g){h=_.defaults(g,h)}if(h.content&&h.content.indexOf("//")===-1){h.content=galaxy_config.root+h.content}if(!this.$menu){$(this.el).find(".root").append(this._templateMenu());$(this.el).find(".symbol").addClass("caret");this.$menu=$(this.el).find(".menu")}var f=$(this._templateMenuItem(h));this.$menu.append(f);var e=this;f.on("click",function(i){i.preventDefault();e._hideMenu();if(e.options.target==="_blank"){return true}Galaxy.frame.add(g)});if(h.divider){this.$menu.append($(this._templateDivider()))}},mastheadReset:function(){this._hideMenu()},_hideMenu:function(){if(this.$menu&&this.menuVisible){this.$menu.hide();this.menuVisible=false}},_eventClickHead:function(f){f.preventDefault();if(this.$menu){if(!this.menuVisible){this.$menu.show();this.menuVisible=true}else{this.$menu.hide();this.menuVisible=false}}else{Galaxy.frame.add(this.options)}},_templateMenuItem:function(e){return'<li><a href="'+e.content+'" target="'+e.target+'">'+e.title+"</a></li>"},_templateMenu:function(){return'<ul class="menu dropdown-menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(f){var e='<ul class="nav navbar-nav" border="0" cellspacing="0"><li class="root dropdown" style=""><a class="head dropdown-toggle" data-toggle="dropdown" target="'+f.target+'" href="'+f.content+'">'+f.title+'<b class="symbol"></b></a></li></ul>';return e}});return{GalaxyMasthead:a,GalaxyMastheadTab:d,GalaxyMastheadIcon:b}});
\ No newline at end of file
+define(["utils/galaxy.utils"],function(c){var a=Backbone.View.extend({el_masthead:"#everything",options:null,$background:null,list:[],initialize:function(f){this.options=f;$("body").off();this.setElement($(this._template(f)));$(this.el_masthead).append($(this.el));this.$background=$(this.el).find("#masthead-background");var e=this;window.onbeforeunload=function(){var h="";for(key in e.list){if(e.list[key].options.on_unload){var g=e.list[key].options.on_unload();if(g){h+=g+" "}}}if(h!=""){return h}}},events:{click:"_click",mousedown:function(f){f.preventDefault()}},append:function(e){return this._add(e,true)},prepend:function(e){return this._add(e,false)},highlight:function(f){var e=$(this.el).find("#"+f+"> li");if(e){e.addClass("active")}},_add:function(h,f){var e=$(this.el).find("#"+h.location);if(e){var g=$(h.el);g.addClass("masthead-item");if(f){e.append(g)}else{e.prepend(g)}this.list.push(h)}return null},_click:function(h){var g=$(this.el).find(".popup");if(g){g.hide()}var f=$(h.target).closest(".masthead-item").find(".popup");if($(h.target).hasClass("head")){f.show();this.$background.show()}else{this.$background.hide()}},_template:function(e){return'<div><div id="masthead" class="navbar navbar-fixed-top navbar-inverse"><div style="position: relative; right: -50%; float: left;"><div id="navbar" style="display: block; position: relative; right: 50%;"></div></div><div class="navbar-brand"><a href="'+e.logo_url+'"><img border="0" src="'+galaxy_config.root+'static/images/galaxyIcon_noText.png"><span id="brand"> Galaxy '+e.brand+'</span></a></div><div class="quota-meter-container"></div><div id="iconbar" class="iconbar"></div></div><div id="masthead-background" style="display: none; position: absolute; top: 33px; width: 100%; height: 100%; z-index: 1010"></div></div>'}});var b=Backbone.View.extend({options:{id:"",icon:"fa-cog",tooltip:"",with_number:false,on_click:function(){alert("clicked")},on_unload:null,visible:true},location:"iconbar",initialize:function(f){if(f){this.options=_.defaults(f,this.options)}this.setElement($(this._template(this.options)));var e=this;$(this.el).find(".icon").tooltip({title:this.options.tooltip,placement:"bottom"}).on("mouseup",e.options.on_click);if(!this.options.visible){this.hide()}},show:function(){$(this.el).css({visibility:"visible"})},hide:function(){$(this.el).css({visibility:"hidden"})},icon:function(e){$(this.el).find(".icon").removeClass(this.options.icon).addClass(e);this.options.icon=e},toggle:function(){$(this.el).addClass("toggle")},untoggle:function(){$(this.el).removeClass("toggle")},number:function(e){$(this.el).find(".number").text(e)},_template:function(f){var e='<div id="'+f.id+'" class="symbol"><div class="icon fa fa-2x '+f.icon+'"></div>';if(f.with_number){e+='<div class="number"></div>'}e+="</div>";return e}});var d=Backbone.View.extend({options:{id:"",title:"",target:"_parent",content:"",type:"url",scratchbook:false,on_unload:null,visible:true},location:"navbar",$menu:null,events:{"click .head":"_head"},initialize:function(e){if(e){this.options=_.defaults(e,this.options)}if(this.options.content&&this.options.content.indexOf("//")===-1){this.options.content=galaxy_config.root+this.options.content}this.setElement($(this._template(this.options)));if(!this.options.visible){this.hide()}},show:function(){$(this.el).css({visibility:"visible"})},hide:function(){$(this.el).css({visibility:"hidden"})},add:function(g){var h={title:"Title",content:"",type:"url",target:"_parent",scratchbook:false,divider:false};if(g){h=_.defaults(g,h)}if(h.content&&h.content.indexOf("//")===-1){h.content=galaxy_config.root+h.content}if(!this.$menu){$(this.el).find(".root").append(this._templateMenu());$(this.el).find(".symbol").addClass("caret");this.$menu=$(this.el).find(".popup")}var f=$(this._templateMenuItem(h));this.$menu.append(f);var e=this;f.on("click",function(i){i.preventDefault();if(e.options.target==="_blank"){return true}Galaxy.frame.add(g)});if(h.divider){this.$menu.append($(this._templateDivider()))}},_head:function(f){f.preventDefault();if(!this.$menu){Galaxy.frame.add(this.options)}},_templateMenuItem:function(e){return'<li><a href="'+e.content+'" target="'+e.target+'">'+e.title+"</a></li>"},_templateMenu:function(){return'<ul class="popup dropdown-menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(f){var e='<ul id="'+f.id+'" class="nav navbar-nav" border="0" cellspacing="0"><li class="root dropdown" style=""><a class="head dropdown-toggle" data-toggle="dropdown" target="'+f.target+'" href="'+f.content+'">'+f.title+'<b class="symbol"></b></a></li></ul>';return e}});return{GalaxyMasthead:a,GalaxyMastheadTab:d,GalaxyMastheadIcon:b}});
\ No newline at end of file
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/packed/galaxy.menu.js
--- a/static/scripts/packed/galaxy.menu.js
+++ b/static/scripts/packed/galaxy.menu.js
@@ -1,1 +1,1 @@
-define(["galaxy.masthead"],function(b){var a=Backbone.Model.extend({options:null,masthead:null,initialize:function(c){this.options=c.config;this.masthead=c.masthead;this.create()},create:function(){var d=new b.GalaxyMastheadTab({title:"Analyze Data",content:"root/index"});this.masthead.append(d);var c=new b.GalaxyMastheadTab({title:"Workflow",content:"workflow"});this.masthead.append(c);var g=new b.GalaxyMastheadTab({title:"Shared Data",content:"library/index"});g.addMenu({title:"Data Libraries",content:"library/index",divider:true});g.addMenu({title:"Published Histories",content:"history/list_published"});g.addMenu({title:"Published Workflows",content:"workflow/list_published"});g.addMenu({title:"Published Visualizations",content:"visualization/list_published"});g.addMenu({title:"Published Pages",content:"page/list_published"});this.masthead.append(g);if(this.options.user.requests){var h=new b.GalaxyMastheadTab({title:"Lab"});h.addMenu({title:"Sequencing Requests",content:"requests/index"});h.addMenu({title:"Find Samples",content:"requests/find_samples_index"});h.addMenu({title:"Help",content:this.options.lims_doc_url});this.masthead.append(h)}var k=new b.GalaxyMastheadTab({title:"Visualization",content:"visualization/list"});k.addMenu({title:"New Track Browser",content:"visualization/trackster",target:"_frame"});k.addMenu({title:"Saved Visualizations",content:"visualization/list",target:"_frame"});this.masthead.append(k);if(this.options.enable_cloud_launch){var e=new b.GalaxyMastheadTab({title:"Cloud",content:"cloudlaunch/index"});e.addMenu({title:"New Cloud Cluster",content:"cloudlaunch/index"});this.masthead.append(e)}if(this.options.is_admin_user){var f=new b.GalaxyMastheadTab({title:"Admin",content:"admin/index",extra_class:"admin-only"});this.masthead.append(f)}var j=new b.GalaxyMastheadTab({title:"Help"});if(this.options.biostar_url){j.addMenu({title:"Galaxy Q&A Site",content:this.options.biostar_url_redirect,target:"_blank"});j.addMenu({title:"Ask a question",content:"biostar/biostar_question_redirect",target:"_blank"})}j.addMenu({title:"Support",content:this.options.support_url,target:"_blank"});j.addMenu({title:"Search",content:this.options.search_url,target:"_blank"});j.addMenu({title:"Mailing Lists",content:this.options.mailing_lists,target:"_blank"});j.addMenu({title:"Videos",content:this.options.screencasts_url,target:"_blank"});j.addMenu({title:"Wiki",content:this.options.wiki_url,target:"_blank"});j.addMenu({title:"How to Cite Galaxy",content:this.options.citation_url,target:"_blank"});if(!this.options.terms_url){j.addMenu({title:"Terms and Conditions",content:this.options.terms_url,target:"_blank"})}this.masthead.append(j);if(!this.options.user.valid){var i=new b.GalaxyMastheadTab({title:"User",extra_class:"loggedout-only"});i.addMenu({title:"Login",content:"user/login",target:"galaxy_main"});if(this.options.allow_user_creation){i.addMenu({title:"Register",content:"user/create",target:"galaxy_main"})}this.masthead.append(i)}else{var i=new b.GalaxyMastheadTab({title:"User",extra_class:"loggedin-only"});i.addMenu({title:"Logged in as "+this.options.user.email});if(this.options.use_remote_user&&this.options.remote_user_logout_href){i.addMenu({title:"Logout",content:this.options.remote_user_logout_href,target:"_top"})}else{i.addMenu({title:"Preferences",content:"user?cntrller=user",target:"galaxy_main"});i.addMenu({title:"Custom Builds",content:"user/dbkeys",target:"galaxy_main"});i.addMenu({title:"Logout",content:"user/logout",target:"_top",divider:true})}i.addMenu({title:"Saved Histories",content:"history/list",target:"galaxy_main"});i.addMenu({title:"Saved Datasets",content:"dataset/list",target:"galaxy_main"});i.addMenu({title:"Saved Pages",content:"page/list",target:"_top"});i.addMenu({title:"API Keys",content:"user/api_keys?cntrller=user",target:"galaxy_main"});if(this.options.use_remote_user){i.addMenu({title:"Public Name",content:"user/edit_username?cntrller=user",target:"galaxy_main"})}this.masthead.append(i)}}});return{GalaxyMenu:a}});
\ No newline at end of file
+define(["galaxy.masthead"],function(b){var a=Backbone.Model.extend({options:null,masthead:null,initialize:function(c){this.options=c.config;this.masthead=c.masthead;this.create()},create:function(){var d=new b.GalaxyMastheadTab({id:"analysis",title:"Analyze Data",content:"root/index"});this.masthead.append(d);var c=new b.GalaxyMastheadTab({id:"workflow",title:"Workflow",content:"workflow"});this.masthead.append(c);var g=new b.GalaxyMastheadTab({id:"shared",title:"Shared Data",content:"library/index"});g.add({title:"Data Libraries",content:"library/index",divider:true});g.add({title:"Published Histories",content:"history/list_published"});g.add({title:"Published Workflows",content:"workflow/list_published"});g.add({title:"Published Visualizations",content:"visualization/list_published"});g.add({title:"Published Pages",content:"page/list_published"});this.masthead.append(g);if(this.options.user.requests){var h=new b.GalaxyMastheadTab({id:"lab",title:"Lab"});h.add({title:"Sequencing Requests",content:"requests/index"});h.add({title:"Find Samples",content:"requests/find_samples_index"});h.add({title:"Help",content:this.options.lims_doc_url});this.masthead.append(h)}var k=new b.GalaxyMastheadTab({id:"visualization",title:"Visualization",content:"visualization/list"});k.add({title:"New Track Browser",content:"visualization/trackster",target:"_frame"});k.add({title:"Saved Visualizations",content:"visualization/list",target:"_frame"});this.masthead.append(k);if(this.options.enable_cloud_launch){var e=new b.GalaxyMastheadTab({id:"cloud",title:"Cloud",content:"cloudlaunch/index"});e.add({title:"New Cloud Cluster",content:"cloudlaunch/index"});this.masthead.append(e)}if(this.options.is_admin_user){var f=new b.GalaxyMastheadTab({id:"admin",title:"Admin",content:"admin/index",extra_class:"admin-only"});this.masthead.append(f)}var j=new b.GalaxyMastheadTab({id:"help",title:"Help"});if(this.options.biostar_url){j.add({title:"Galaxy Q&A Site",content:this.options.biostar_url_redirect,target:"_blank"});j.add({title:"Ask a question",content:"biostar/biostar_question_redirect",target:"_blank"})}j.add({title:"Support",content:this.options.support_url,target:"_blank"});j.add({title:"Search",content:this.options.search_url,target:"_blank"});j.add({title:"Mailing Lists",content:this.options.mailing_lists,target:"_blank"});j.add({title:"Videos",content:this.options.screencasts_url,target:"_blank"});j.add({title:"Wiki",content:this.options.wiki_url,target:"_blank"});j.add({title:"How to Cite Galaxy",content:this.options.citation_url,target:"_blank"});if(!this.options.terms_url){j.add({title:"Terms and Conditions",content:this.options.terms_url,target:"_blank"})}this.masthead.append(j);if(!this.options.user.valid){var i=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedout-only"});i.add({title:"Login",content:"user/login",target:"galaxy_main"});if(this.options.allow_user_creation){i.add({title:"Register",content:"user/create",target:"galaxy_main"})}this.masthead.append(i)}else{var i=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedin-only"});i.add({title:"Logged in as "+this.options.user.email});if(this.options.use_remote_user&&this.options.remote_user_logout_href){i.add({title:"Logout",content:this.options.remote_user_logout_href,target:"_top"})}else{i.add({title:"Preferences",content:"user?cntrller=user",target:"galaxy_main"});i.add({title:"Custom Builds",content:"user/dbkeys",target:"galaxy_main"});i.add({title:"Logout",content:"user/logout",target:"_top",divider:true})}i.add({title:"Saved Histories",content:"history/list",target:"galaxy_main"});i.add({title:"Saved Datasets",content:"dataset/list",target:"galaxy_main"});i.add({title:"Saved Pages",content:"page/list",target:"_top"});i.add({title:"API Keys",content:"user/api_keys?cntrller=user",target:"galaxy_main"});if(this.options.use_remote_user){i.add({title:"Public Name",content:"user/edit_username?cntrller=user",target:"galaxy_main"})}this.masthead.append(i)}if(this.options.active_view){this.masthead.highlight(this.options.active_view)}}});return{GalaxyMenu:a}});
\ No newline at end of file
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/packed/mvc/history/history-panel.js
--- a/static/scripts/packed/mvc/history/history-panel.js
+++ b/static/scripts/packed/mvc/history/history-panel.js
@@ -1,1 +1,1 @@
-define(["mvc/history/history-model","mvc/dataset/hda-base","mvc/dataset/hda-edit"],function(f,b,a){var c=SessionStorageModel.extend({defaults:{expandedHdas:{},show_deleted:false,show_hidden:false},addExpandedHda:function(g){this.save("expandedHdas",_.extend(this.get("expandedHdas"),_.object([g],[true])))},removeExpandedHda:function(g){this.save("expandedHdas",_.omit(this.get("expandedHdas"),g))},toString:function(){return"HistoryPanelPrefs("+this.id+")"}});c.historyStorageKey=function e(g){if(!g){throw new Error("HistoryPanelPrefs.historyStorageKey needs valid id: "+g)}return("history:"+g)};var d=Backbone.View.extend(LoggableMixin).extend({HDAView:a.HDAEditView,tagName:"div",className:"history-panel",fxSpeed:"fast",datasetsSelector:".datasets-list",emptyMsgSelector:".empty-history-message",msgsSelector:".message-container",initialize:function(g){g=g||{};if(g.logger){this.logger=g.logger}this.log(this+".initialize:",g);this._setUpListeners();this.hdaViews={};this.indicator=new LoadingIndicator(this.$el);this.filters=[];if(this.model){this._setUpWebStorage(g.initiallyExpanded,g.show_deleted,g.show_hidden);this._setUpModelEventHandlers()}if(g.onready){g.onready.call(this)}},_setUpListeners:function(){this.on("error",function(h,k,g,j,i){this.errorHandler(h,k,g,j,i)});this.on("loading-history",function(){this.showLoadingIndicator("loading history...")});this.on("loading-done",function(){this.hideLoadingIndicator()});this.once("rendered",function(){this.trigger("rendered:initial",this);return false});this.on("switched-history current-history new-history",function(){if(_.isEmpty(this.hdaViews)){this.trigger("empty-history",this)}});if(this.logger){this.on("all",function(g){this.log(this+"",arguments)},this)}},errorHandler:function(i,l,h,k,j){var g=this._parseErrorMessage(i,l,h,k,j);if(l&&l.status===0&&l.readyState===0){}else{if(l&&l.status===502){}else{if(!this.$el.find(this.msgsSelector).is(":visible")){this.once("rendered",function(){this.displayMessage("error",g.message,g.details)})}else{this.displayMessage("error",g.message,g.details)}}}},_parseErrorMessage:function(j,n,i,m,l){var h=Galaxy.currUser,g={message:this._bePolite(m),details:{user:(h instanceof User)?(h.toJSON()):(h+""),source:(j instanceof Backbone.Model)?(j.toJSON()):(j+""),xhr:n,options:(n)?(_.omit(i,"xhr")):(i)}};_.extend(g.details,l||{});if(n&&_.isFunction(n.getAllResponseHeaders)){var k=n.getAllResponseHeaders();k=_.compact(k.split("\n"));k=_.map(k,function(o){return o.split(": ")});g.details.xhr.responseHeaders=_.object(k)}return g},_bePolite:function(g){g=g||_l("An error occurred while getting updates from the server");return g+". "+_l("Please contact a Galaxy administrator if the problem persists.")},loadCurrentHistory:function(h){var g=this;return this.loadHistoryWithHDADetails("current",h).then(function(j,i){g.trigger("current-history",g)})},switchToHistory:function(j,i){var g=this,h=function(){return jQuery.post(galaxy_config.root+"api/histories/"+j+"/set_as_current")};return this.loadHistoryWithHDADetails(j,i,h).then(function(l,k){g.trigger("switched-history",g)})},createNewHistory:function(i){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",_l("You must be logged in to create histories"));return $.when()}var g=this,h=function(){return jQuery.post(galaxy_config.root+"api/histories",{current:true})};return this.loadHistory(undefined,i,h).then(function(k,j){g.trigger("new-history",g)})},loadHistoryWithHDADetails:function(j,i,h,l){var g=this,k=function(m){return g.getExpandedHdaIds(m.id)};return this.loadHistory(j,i,h,l,k)},loadHistory:function(j,i,h,m,k){this.trigger("loading-history",this);i=i||{};var g=this;var l=f.History.getHistoryData(j,{historyFn:h,hdaFn:m,hdaDetailIds:i.initiallyExpanded||k});return this._loadHistoryFromXHR(l,i).fail(function(p,n,o){g.trigger("error",g,p,i,_l("An error was encountered while "+n),{historyId:j,history:o||{}})}).always(function(){g.trigger("loading-done",g)})},_loadHistoryFromXHR:function(i,h){var g=this;i.then(function(j,k){g.setModel(j,k,h)});i.fail(function(k,j){g.render()});return i},setModel:function(i,g,h){h=h||{};if(this.model){this.model.clearUpdateTimeout();this.stopListening(this.model);this.stopListening(this.model.hdas)}this.hdaViews={};if(Galaxy&&Galaxy.currUser){i.user=Galaxy.currUser.toJSON()}this.model=new f.History(i,g,h);this._setUpWebStorage(h.initiallyExpanded,h.show_deleted,h.show_hidden);this._setUpModelEventHandlers();this.trigger("new-model",this);this.render();return this},refreshHdas:function(h,g){if(this.model){return this.model.refresh(h,g)}return $.when()},_setUpWebStorage:function(h,g,i){this.storage=new c({id:c.historyStorageKey(this.model.get("id"))});if(_.isObject(h)){this.storage.set("exandedHdas",h)}if(_.isBoolean(g)){this.storage.set("show_deleted",g)}if(_.isBoolean(i)){this.storage.set("show_hidden",i)}this.trigger("new-storage",this.storage,this);this.log(this+" (init'd) storage:",this.storage.get())},clearWebStorage:function(){for(var g in sessionStorage){if(g.indexOf("history:")===0){sessionStorage.removeItem(g)}}},getStoredOptions:function(h){if(!h||h==="current"){return(this.storage)?(this.storage.get()):({})}var g=sessionStorage.getItem(c.historyStorageKey(h));return(g===null)?({}):(JSON.parse(g))},getExpandedHdaIds:function(g){var h=this.getStoredOptions(g).expandedHdas;return((_.isEmpty(h))?([]):(_.keys(h)))},_setUpModelEventHandlers:function(){this.model.on("error error:hdas",function(h,j,g,i){this.errorHandler(h,j,g,i)},this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}this.model.hdas.on("add",this.addHdaView,this);this.model.hdas.on("change:deleted",this.handleHdaDeletionChange,this);this.model.hdas.on("change:visible",this.handleHdaVisibleChange,this);this.model.hdas.on("change:purged",function(g){this.model.fetch()},this);this.model.hdas.on("state:ready",function(h,i,g){if((!h.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(this.hdaViews[h.id])}},this)},addHdaView:function(j){this.log("add."+this,j);var h=this;if(!j.isVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"))){return}$({}).queue([function i(l){var k=h.$el.find(h.emptyMsgSelector);if(k.is(":visible")){k.fadeOut(h.fxSpeed,l)}else{l()}},function g(l){h.scrollToTop();var k=h.$el.find(h.datasetsSelector);h.createHdaView(j).$el.hide().prependTo(k).slideDown(h.fxSpeed)}])},createHdaView:function(i){var h=i.get("id"),g=this.storage.get("expandedHdas")[h],j=new this.HDAView({model:i,expanded:g,hasUser:this.model.hasUser(),logger:this.logger});this._setUpHdaListeners(j);this.hdaViews[h]=j;return j.render()},_setUpHdaListeners:function(h){var g=this;h.on("body-expanded",function(i){g.storage.addExpandedHda(i)});h.on("body-collapsed",function(i){g.storage.removeExpandedHda(i)});h.on("error",function(j,l,i,k){g.errorHandler(j,l,i,k)})},handleHdaDeletionChange:function(g){if(g.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[g.id])}},handleHdaVisibleChange:function(g){if(g.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[g.id])}},removeHdaView:function(h){if(!h){return}var g=this;h.$el.fadeOut(g.fxSpeed,function(){h.off();h.remove();delete g.hdaViews[h.model.id];if(_.isEmpty(g.hdaViews)){g.$el.find(g.emptyMsgSelector).fadeIn(g.fxSpeed,function(){g.trigger("empty-history",g)})}})},render:function(i,j){i=(i===undefined)?(this.fxSpeed):(i);var g=this,h;if(this.model){h=this.renderModel()}else{h=this.renderWithoutModel()}$(g).queue("fx",[function(k){if(i&&g.$el.is(":visible")){g.$el.fadeOut(i,k)}else{k()}},function(k){g.$el.empty();if(h){g.$el.append(h.children())}k()},function(k){if(i&&!g.$el.is(":visible")){g.$el.fadeIn(i,k)}else{k()}},function(k){if(j){j.call(this)}g.trigger("rendered",this);k()}]);return this},renderWithoutModel:function(){var g=$("<div/>"),h=$("<div/>").addClass("message-container").css({"margin-left":"4px","margin-right":"4px"});return g.append(h)},renderModel:function(){var g=$("<div/>");if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){g.append(d.templates.anonHistoryPanel(this.model.toJSON()))}else{g.append(d.templates.historyPanel(this.model.toJSON()));this._renderTags(g);this._renderAnnotation(g)}this._setUpBehaviours(g);this.renderHdas(g);return g},_renderTags:function(g){this.tagsEditor=new TagsEditor({model:this.model,el:g.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(g.find(".history-secondary-actions"))})},_renderAnnotation:function(g){this.annotationEditor=new AnnotationEditor({model:this.model,el:g.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(g.find(".history-secondary-actions"))})},_setUpBehaviours:function(g){g=g||this.$el;g.find("[title]").tooltip({placement:"bottom"});if(!this.model||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){return}var h=this;g.find(".history-name").make_text_editable({on_finish:function(i){g.find(".history-name").text(i);h.model.save({name:i}).fail(function(){g.find(".history-name").text(h.model.previous("name"))})}})},renderHdas:function(i){i=i||this.$el;this.hdaViews={};var h=this,g=i.find(this.datasetsSelector),j=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters);g.empty();if(j.length){j.each(function(k){g.prepend(h.createHdaView(k).$el)});i.find(this.emptyMsgSelector).hide()}else{i.find(this.emptyMsgSelector).show()}return this.hdaViews},events:{"click .message-container":"clearMessages"},updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},collapseAllHdaBodies:function(){_.each(this.hdaViews,function(g){g.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render();return this.storage.get("show_deleted")},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render();return this.storage.get("show_hidden")},renderSearchControls:function(){var g=this;g.model.hdas.fetchAllDetails({silent:true});function i(j){g.searchFor=j;g.filters=[function(k){return k.matchesAll(g.searchFor)}];g.trigger("search:searching",j,g);g.renderHdas()}function h(){g.searchFor="";g.filters=[];g.trigger("search:clear",g);g.renderHdas()}return searchInput({initialVal:g.searchFor,name:"history-search",placeholder:"search datasets",classes:"history-search",onsearch:i,onclear:h}).addClass("history-search-controls").css("padding","0px 0px 8px 0px")},toggleSearchControls:function(){var g=this.$el.find(".history-search-controls");if(!g.size()){g=this.renderSearchControls().hide();this.$el.find(".history-title").before(g)}g.slideToggle(this.fxSpeed)},showSelect:function(g){_.each(this.hdaViews,function(h){h.showSelect(g)})},hideSelect:function(g){_.each(this.hdaViews,function(h){h.hideSelect(g)})},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(g){return g.selected})},showLoadingIndicator:function(h,g,i){g=(g!==undefined)?(g):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent())}if(!this.$el.is(":visible")){this.indicator.show(0,i)}else{this.$el.fadeOut(g);this.indicator.show(h,g,i)}},hideLoadingIndicator:function(g,h){g=(g!==undefined)?(g):(this.fxSpeed);if(this.indicator){this.indicator.hide(g,h)}},displayMessage:function(l,m,k){var i=this;this.scrollToTop();var j=this.$el.find(this.msgsSelector),g=$("<div/>").addClass(l+"message").html(m);if(!_.isEmpty(k)){var h=$('<a href="javascript:void(0)">Details</a>').click(function(){Galaxy.modal.show(i.messageToModalOptions(l,m,k));return false});g.append(" ",h)}return j.html(g)},messageToModalOptions:function(k,m,j){var g=this,l=$("<div/>"),i={title:"Details"};function h(n){n=_.omit(n,_.functions(n));return["<table>",_.map(n,function(p,o){p=(_.isObject(p))?(h(p)):(p);return'<tr><td style="vertical-align: top; color: grey">'+o+'</td><td style="padding-left: 8px">'+p+"</td></tr>"}).join(""),"</table>"].join("")}if(_.isObject(j)){i.body=l.append(h(j))}else{i.body=l.html(j)}i.buttons={Ok:function(){Galaxy.modal.hide();g.clearMessages()}};return i},clearMessages:function(){var g=this.$el.find(this.msgsSelector);g.empty()},scrollPosition:function(){return this.$el.parent().scrollTop()},scrollTo:function(g){this.$el.parent().scrollTop(g)},scrollToTop:function(){this.$el.parent().scrollTop(0);return this},scrollIntoView:function(h,i){if(!i){this.$el.parent().parent().scrollTop(h);return this}var g=window,j=this.$el.parent().parent(),l=$(g).innerHeight(),k=(l/2)-(i/2);$(j).scrollTop(h-k);return this},scrollToId:function(h){if((!h)||(!this.hdaViews[h])){return this}var g=this.hdaViews[h].$el;this.scrollIntoView(g.offset().top,g.outerHeight());return this},scrollToHid:function(g){var h=this.model.hdas.getByHid(g);if(!h){return this}return this.scrollToId(h.id)},connectToQuotaMeter:function(g){if(!g){return this}this.listenTo(g,"quota:over",this.showQuotaMessage);this.listenTo(g,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(g&&g.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var g=this.$el.find(".quota-message");if(g.is(":hidden")){g.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var g=this.$el.find(".quota-message");if(!g.is(":hidden")){g.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(g){if(!g){return this}this.on("new-storage",function(i,h){if(g&&i){g.findItemByHtml(_l("Include Deleted Datasets")).checked=i.get("show_deleted");g.findItemByHtml(_l("Include Hidden Datasets")).checked=i.get("show_hidden")}});return this},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});d.templates={historyPanel:Handlebars.templates["template-history-historyPanel"],anonHistoryPanel:Handlebars.templates["template-history-historyPanel-anon"]};return{HistoryPanel:d}});
\ No newline at end of file
+define(["mvc/history/history-model","mvc/dataset/hda-base","mvc/dataset/hda-edit"],function(f,b,a){var c=SessionStorageModel.extend({defaults:{expandedHdas:{},show_deleted:false,show_hidden:false},addExpandedHda:function(g){this.save("expandedHdas",_.extend(this.get("expandedHdas"),_.object([g],[true])))},removeExpandedHda:function(g){this.save("expandedHdas",_.omit(this.get("expandedHdas"),g))},toString:function(){return"HistoryPanelPrefs("+this.id+")"}});c.historyStorageKey=function e(g){if(!g){throw new Error("HistoryPanelPrefs.historyStorageKey needs valid id: "+g)}return("history:"+g)};var d=Backbone.View.extend(LoggableMixin).extend({HDAView:a.HDAEditView,tagName:"div",className:"history-panel",fxSpeed:"fast",datasetsSelector:".datasets-list",emptyMsgSelector:".empty-history-message",msgsSelector:".message-container",initialize:function(g){g=g||{};if(g.logger){this.logger=g.logger}this.log(this+".initialize:",g);this._setUpListeners();this.hdaViews={};this.indicator=new LoadingIndicator(this.$el);this.filters=[];if(this.model){this._setUpWebStorage(g.initiallyExpanded,g.show_deleted,g.show_hidden);this._setUpModelEventHandlers()}if(g.onready){g.onready.call(this)}},_setUpListeners:function(){this.on("error",function(h,k,g,j,i){this.errorHandler(h,k,g,j,i)});this.on("loading-history",function(){this.showLoadingIndicator("loading history...")});this.on("loading-done",function(){this.hideLoadingIndicator()});this.once("rendered",function(){this.trigger("rendered:initial",this);return false});this.on("switched-history current-history new-history",function(){if(_.isEmpty(this.hdaViews)){this.trigger("empty-history",this)}});if(this.logger){this.on("all",function(g){this.log(this+"",arguments)},this)}},errorHandler:function(i,l,h,k,j){var g=this._parseErrorMessage(i,l,h,k,j);if(l&&l.status===0&&l.readyState===0){}else{if(l&&l.status===502){}else{if(!this.$el.find(this.msgsSelector).is(":visible")){this.once("rendered",function(){this.displayMessage("error",g.message,g.details)})}else{this.displayMessage("error",g.message,g.details)}}}},_parseErrorMessage:function(j,n,i,m,l){var h=Galaxy.currUser,g={message:this._bePolite(m),details:{user:(h instanceof User)?(h.toJSON()):(h+""),source:(j instanceof Backbone.Model)?(j.toJSON()):(j+""),xhr:n,options:(n)?(_.omit(i,"xhr")):(i)}};_.extend(g.details,l||{});if(n&&_.isFunction(n.getAllResponseHeaders)){var k=n.getAllResponseHeaders();k=_.compact(k.split("\n"));k=_.map(k,function(o){return o.split(": ")});g.details.xhr.responseHeaders=_.object(k)}return g},_bePolite:function(g){g=g||_l("An error occurred while getting updates from the server");return g+". "+_l("Please contact a Galaxy administrator if the problem persists.")},loadCurrentHistory:function(h){var g=this;return this.loadHistoryWithHDADetails("current",h).then(function(j,i){g.trigger("current-history",g)})},switchToHistory:function(j,i){var g=this,h=function(){return jQuery.post(galaxy_config.root+"api/histories/"+j+"/set_as_current")};return this.loadHistoryWithHDADetails(j,i,h).then(function(l,k){g.trigger("switched-history",g)})},createNewHistory:function(i){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",_l("You must be logged in to create histories"));return $.when()}var g=this,h=function(){return jQuery.post(galaxy_config.root+"api/histories",{current:true})};return this.loadHistory(undefined,i,h).then(function(k,j){g.trigger("new-history",g)})},loadHistoryWithHDADetails:function(j,i,h,l){var g=this,k=function(m){return g.getExpandedHdaIds(m.id)};return this.loadHistory(j,i,h,l,k)},loadHistory:function(j,i,h,m,k){this.trigger("loading-history",this);i=i||{};var g=this;var l=f.History.getHistoryData(j,{historyFn:h,hdaFn:m,hdaDetailIds:i.initiallyExpanded||k});return this._loadHistoryFromXHR(l,i).fail(function(p,n,o){g.trigger("error",g,p,i,_l("An error was encountered while "+n),{historyId:j,history:o||{}})}).always(function(){g.trigger("loading-done",g)})},_loadHistoryFromXHR:function(i,h){var g=this;i.then(function(j,k){g.setModel(j,k,h)});i.fail(function(k,j){g.render()});return i},setModel:function(i,g,h){h=h||{};if(this.model){this.model.clearUpdateTimeout();this.stopListening(this.model);this.stopListening(this.model.hdas)}this.hdaViews={};if(Galaxy&&Galaxy.currUser){i.user=Galaxy.currUser.toJSON()}this.model=new f.History(i,g,h);this._setUpWebStorage(h.initiallyExpanded,h.show_deleted,h.show_hidden);this._setUpModelEventHandlers();this.trigger("new-model",this);this.render();return this},refreshHdas:function(h,g){if(this.model){return this.model.refresh(h,g)}return $.when()},_setUpWebStorage:function(h,g,i){this.storage=new c({id:c.historyStorageKey(this.model.get("id"))});if(_.isObject(h)){this.storage.set("exandedHdas",h)}if(_.isBoolean(g)){this.storage.set("show_deleted",g)}if(_.isBoolean(i)){this.storage.set("show_hidden",i)}this.trigger("new-storage",this.storage,this);this.log(this+" (init'd) storage:",this.storage.get())},clearWebStorage:function(){for(var g in sessionStorage){if(g.indexOf("history:")===0){sessionStorage.removeItem(g)}}},getStoredOptions:function(h){if(!h||h==="current"){return(this.storage)?(this.storage.get()):({})}var g=sessionStorage.getItem(c.historyStorageKey(h));return(g===null)?({}):(JSON.parse(g))},getExpandedHdaIds:function(g){var h=this.getStoredOptions(g).expandedHdas;return((_.isEmpty(h))?([]):(_.keys(h)))},_setUpModelEventHandlers:function(){this.model.on("error error:hdas",function(h,j,g,i){this.errorHandler(h,j,g,i)},this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}this.model.hdas.on("add",this.addHdaView,this);this.model.hdas.on("change:deleted",this.handleHdaDeletionChange,this);this.model.hdas.on("change:visible",this.handleHdaVisibleChange,this);this.model.hdas.on("change:purged",function(g){this.model.fetch()},this);this.model.hdas.on("state:ready",function(h,i,g){if((!h.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(this.hdaViews[h.id])}},this)},addHdaView:function(j){this.log("add."+this,j);var h=this;if(!j.isVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"))){return}$({}).queue([function i(l){var k=h.$el.find(h.emptyMsgSelector);if(k.is(":visible")){k.fadeOut(h.fxSpeed,l)}else{l()}},function g(l){h.scrollToTop();var k=h.$el.find(h.datasetsSelector);h.createHdaView(j).$el.hide().prependTo(k).slideDown(h.fxSpeed)}])},createHdaView:function(i){var h=i.get("id"),g=this.storage.get("expandedHdas")[h],j=new this.HDAView({model:i,expanded:g,hasUser:this.model.hasUser(),logger:this.logger});this._setUpHdaListeners(j);this.hdaViews[h]=j;return j.render()},_setUpHdaListeners:function(h){var g=this;h.on("body-expanded",function(i){g.storage.addExpandedHda(i)});h.on("body-collapsed",function(i){g.storage.removeExpandedHda(i)});h.on("error",function(j,l,i,k){g.errorHandler(j,l,i,k)})},handleHdaDeletionChange:function(g){if(g.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[g.id])}},handleHdaVisibleChange:function(g){if(g.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[g.id])}},removeHdaView:function(h){if(!h){return}var g=this;h.$el.fadeOut(g.fxSpeed,function(){h.off();h.remove();delete g.hdaViews[h.model.id];if(_.isEmpty(g.hdaViews)){g.$el.find(g.emptyMsgSelector).fadeIn(g.fxSpeed,function(){g.trigger("empty-history",g)})}})},render:function(i,j){i=(i===undefined)?(this.fxSpeed):(i);var g=this,h;if(this.model){h=this.renderModel()}else{h=this.renderWithoutModel()}$(g).queue("fx",[function(k){if(i&&g.$el.is(":visible")){g.$el.fadeOut(i,k)}else{k()}},function(k){g.$el.empty();if(h){g.$el.append(h.children())}k()},function(k){if(i&&!g.$el.is(":visible")){g.$el.fadeIn(i,k)}else{k()}},function(k){if(j){j.call(this)}g.trigger("rendered",this);k()}]);return this},renderWithoutModel:function(){var g=$("<div/>"),h=$("<div/>").addClass("message-container").css({"margin-left":"4px","margin-right":"4px"});return g.append(h)},renderModel:function(){var g=$("<div/>");if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){g.append(d.templates.anonHistoryPanel(this.model.toJSON()))}else{g.append(d.templates.historyPanel(this.model.toJSON()));this._renderTags(g);this._renderAnnotation(g)}faIconButton({title:_l("Search datasets"),classes:"history-search-btn",faIcon:"fa-search"}).prependTo(g.find(".history-secondary-actions"));this._setUpBehaviours(g);this.renderHdas(g);return g},_renderTags:function(g){this.tagsEditor=new TagsEditor({model:this.model,el:g.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(g.find(".history-secondary-actions"))})},_renderAnnotation:function(g){this.annotationEditor=new AnnotationEditor({model:this.model,el:g.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(g.find(".history-secondary-actions"))})},_setUpBehaviours:function(g){g=g||this.$el;g.find("[title]").tooltip({placement:"bottom"});if(!this.model||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){return}var h=this;g.find(".history-name").make_text_editable({on_finish:function(i){g.find(".history-name").text(i);h.model.save({name:i}).fail(function(){g.find(".history-name").text(h.model.previous("name"))})}})},renderHdas:function(i){i=i||this.$el;this.hdaViews={};var h=this,g=i.find(this.datasetsSelector),j=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters);g.empty();if(j.length){j.each(function(k){g.prepend(h.createHdaView(k).$el)});i.find(this.emptyMsgSelector).hide()}else{i.find(this.emptyMsgSelector).show()}return this.hdaViews},events:{"click .message-container":"clearMessages","click .history-search-btn":"toggleSearchControls"},updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},collapseAllHdaBodies:function(){_.each(this.hdaViews,function(g){g.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render();return this.storage.get("show_deleted")},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render();return this.storage.get("show_hidden")},renderSearchControls:function(){var g=this;g.model.hdas.fetchAllDetails({silent:true});function i(j){g.searchFor=j;g.filters=[function(k){return k.matchesAll(g.searchFor)}];g.trigger("search:searching",j,g);g.renderHdas()}function h(){g.searchFor="";g.filters=[];g.trigger("search:clear",g);g.renderHdas()}return searchInput({initialVal:g.searchFor,name:"history-search",placeholder:"search datasets",classes:"history-search",onsearch:i,onclear:h}).addClass("history-search-controls").css("padding","0px 0px 8px 0px")},toggleSearchControls:function(){var g=this.$el.find(".history-search-controls");if(!g.size()){g=this.renderSearchControls().hide();this.$el.find(".history-title").before(g)}g.slideToggle(this.fxSpeed,function(){if($(this).is(":visible")){$(this).find("input").focus()}})},showSelect:function(g){_.each(this.hdaViews,function(h){h.showSelect(g)})},hideSelect:function(g){_.each(this.hdaViews,function(h){h.hideSelect(g)})},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(g){return g.selected})},showLoadingIndicator:function(h,g,i){g=(g!==undefined)?(g):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent())}if(!this.$el.is(":visible")){this.indicator.show(0,i)}else{this.$el.fadeOut(g);this.indicator.show(h,g,i)}},hideLoadingIndicator:function(g,h){g=(g!==undefined)?(g):(this.fxSpeed);if(this.indicator){this.indicator.hide(g,h)}},displayMessage:function(l,m,k){var i=this;this.scrollToTop();var j=this.$el.find(this.msgsSelector),g=$("<div/>").addClass(l+"message").html(m);if(!_.isEmpty(k)){var h=$('<a href="javascript:void(0)">Details</a>').click(function(){Galaxy.modal.show(i.messageToModalOptions(l,m,k));return false});g.append(" ",h)}return j.html(g)},messageToModalOptions:function(k,m,j){var g=this,l=$("<div/>"),i={title:"Details"};function h(n){n=_.omit(n,_.functions(n));return["<table>",_.map(n,function(p,o){p=(_.isObject(p))?(h(p)):(p);return'<tr><td style="vertical-align: top; color: grey">'+o+'</td><td style="padding-left: 8px">'+p+"</td></tr>"}).join(""),"</table>"].join("")}if(_.isObject(j)){i.body=l.append(h(j))}else{i.body=l.html(j)}i.buttons={Ok:function(){Galaxy.modal.hide();g.clearMessages()}};return i},clearMessages:function(){var g=this.$el.find(this.msgsSelector);g.empty()},scrollPosition:function(){return this.$el.parent().scrollTop()},scrollTo:function(g){this.$el.parent().scrollTop(g)},scrollToTop:function(){this.$el.parent().scrollTop(0);return this},scrollIntoView:function(h,i){if(!i){this.$el.parent().parent().scrollTop(h);return this}var g=window,j=this.$el.parent().parent(),l=$(g).innerHeight(),k=(l/2)-(i/2);$(j).scrollTop(h-k);return this},scrollToId:function(h){if((!h)||(!this.hdaViews[h])){return this}var g=this.hdaViews[h].$el;this.scrollIntoView(g.offset().top,g.outerHeight());return this},scrollToHid:function(g){var h=this.model.hdas.getByHid(g);if(!h){return this}return this.scrollToId(h.id)},connectToQuotaMeter:function(g){if(!g){return this}this.listenTo(g,"quota:over",this.showQuotaMessage);this.listenTo(g,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(g&&g.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var g=this.$el.find(".quota-message");if(g.is(":hidden")){g.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var g=this.$el.find(".quota-message");if(!g.is(":hidden")){g.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(g){if(!g){return this}this.on("new-storage",function(i,h){if(g&&i){g.findItemByHtml(_l("Include Deleted Datasets")).checked=i.get("show_deleted");g.findItemByHtml(_l("Include Hidden Datasets")).checked=i.get("show_hidden")}});return this},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});d.templates={historyPanel:Handlebars.templates["template-history-historyPanel"],anonHistoryPanel:Handlebars.templates["template-history-historyPanel-anon"]};return{HistoryPanel:d}});
\ No newline at end of file
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/packed/mvc/ui.js
--- a/static/scripts/packed/mvc/ui.js
+++ b/static/scripts/packed/mvc/ui.js
@@ -1,1 +1,1 @@
-var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b||$("<div/>");this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((a.target)?(' target="'+a.target+'"'):("")),' href="',((a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};var searchInput=function(k){var a=27,h=13,i=$("<div/>"),b={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onsearch:function(l){},minSearchLen:0,escWillClear:true,oninit:function(){}};if(jQuery.type(k)==="object"){k=jQuery.extend(true,b,k)}function d(l){var m=$(this).parent().children("input");m.val("");m.trigger("clear:searchInput");k.onclear()}function j(m,l){$(this).trigger("search:searchInput",l);k.onsearch(l)}function c(){return['<input type="text" name="',k.name,'" placeholder="',k.placeholder,'" ','class="search-query ',k.classes,'" ',"/>"].join("")}function g(){return $(c()).css({width:"100%","padding-right":"24px"}).focus(function(l){$(this).select()}).keyup(function(m){if(m.which===a&&k.escWillClear){d.call(this,m)}else{var l=$(this).val();if((m.which===h)||(k.minSearchLen&&l.length>=k.minSearchLen)){j.call(this,m,l)}else{if(!l.length){d.call(this,m)}}}}).val(k.initialVal)}function f(){return'<span class="search-clear fa fa-times-circle"></span>'}function e(){return $(f()).css({position:"absolute",right:"15px","font-size":"1.4em","line-height":"23px",color:"grey"}).click(function(l){d.call(this,l)})}return i.append([g(),e()])};function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b};
\ No newline at end of file
+var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b||$("<div/>");this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((a.target)?(' target="'+a.target+'"'):("")),' href="',((a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};var searchInput=function(k){var a=27,h=13,i=$("<div/>"),b={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onsearch:function(l){},minSearchLen:0,escWillClear:true,oninit:function(){}};if(jQuery.type(k)==="object"){k=jQuery.extend(true,b,k)}function d(l){var m=$(this).parent().children("input");m.val("");m.trigger("clear:searchInput");k.onclear()}function j(m,l){$(this).trigger("search:searchInput",l);k.onsearch(l)}function c(){return['<input type="text" name="',k.name,'" placeholder="',k.placeholder,'" ','class="search-query ',k.classes,'" ',"/>"].join("")}function g(){return $(c()).css({width:"100%","padding-right":"24px"}).focus(function(l){$(this).select()}).keyup(function(m){if(m.which===a&&k.escWillClear){d.call(this,m)}else{var l=$(this).val();if((m.which===h)||(k.minSearchLen&&l.length>=k.minSearchLen)){j.call(this,m,l)}else{if(!l.length){d.call(this,m)}}}}).val(k.initialVal)}function f(){return'<span class="search-clear fa fa-times-circle" title="'+_l("clear search (esc)")+'"></span>'}function e(){return $(f()).css({position:"absolute",right:"15px","font-size":"1.4em","line-height":"23px",color:"grey"}).tooltip({placement:"bottom"}).click(function(l){d.call(this,l)})}return i.append([g(),e()])};function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b};
\ No newline at end of file
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/packed/templates/compiled/history-templates.js
--- a/static/scripts/packed/templates/compiled/history-templates.js
+++ b/static/scripts/packed/templates/compiled/history-templates.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-body"]=b(function(g,r,p,k,z){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);z=z||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';if(B=p.body){B=B.call(D,{hash:{},data:C})}else{B=D.body;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+='\n </div>\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';return A}function m(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';B=p["if"].call(D,D.misc_blurb,{hash:{},inverse:o.noop,fn:o.program(4,l,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.data_type,{hash:{},inverse:o.noop,fn:o.program(6,j,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.metadata_dbkey,{hash:{},inverse:o.noop,fn:o.program(9,f,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.misc_info,{hash:{},inverse:o.noop,fn:o.program(12,x,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';B=p.unless.call(D,D.deleted,{hash:{},inverse:o.noop,fn:o.program(14,w,C),data:C});if(B||B===0){A+=B}A+="\n\n ";return A}function l(D,C){var A="",B;A+='\n <div class="dataset-blurb">\n <span class="value">';if(B=p.misc_blurb){B=B.call(D,{hash:{},data:C})}else{B=D.misc_blurb;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function j(E,D){var A="",C,B;A+='\n <div class="dataset-datatype">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(7,i,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">';if(C=p.data_type){C=C.call(E,{hash:{},data:D})}else{C=E.data_type;C=typeof C===e?C.apply(E):C}A+=d(C)+"</span>\n </div>\n ";return A}function i(B,A){return"format"}function f(E,D){var A="",C,B;A+='\n <div class="dataset-dbkey">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(10,y,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">\n ';if(C=p.metadata_dbkey){C=C.call(E,{hash:{},data:D})}else{C=E.metadata_dbkey;C=typeof C===e?C.apply(E):C}A+=d(C)+"\n </span>\n </div>\n ";return A}function y(B,A){return"database"}function x(D,C){var A="",B;A+='\n <div class="dataset-info">\n <span class="value">';if(B=p.misc_info){B=B.call(D,{hash:{},data:C})}else{B=D.misc_info;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function w(D,C){var A="",B;A+='\n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="dataset-display-applications">\n ';B=p.each.call(D,D.display_apps,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p.each.call(D,D.display_types,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-peek">\n ';B=p["if"].call(D,D.peek,{hash:{},inverse:o.noop,fn:o.program(19,s,C),data:C});if(B||B===0){A+=B}A+="\n </div>\n\n ";return A}function v(D,C){var A="",B;A+='\n <div class="display-application">\n <span class="display-application-location">';if(B=p.label){B=B.call(D,{hash:{},data:C})}else{B=D.label;B=typeof B===e?B.apply(D):B}A+=d(B)+'</span>\n <span class="display-application-links">\n ';B=p.each.call(D,D.links,{hash:{},inverse:o.noop,fn:o.program(16,u,C),data:C});if(B||B===0){A+=B}A+="\n </span>\n </div>\n ";return A}function u(E,D){var A="",C,B;A+='\n <a target="';if(C=p.target){C=C.call(E,{hash:{},data:D})}else{C=E.target;C=typeof C===e?C.apply(E):C}A+=d(C)+'" href="';if(C=p.href){C=C.call(E,{hash:{},data:D})}else{C=E.href;C=typeof C===e?C.apply(E):C}A+=d(C)+'">';B={hash:{},inverse:o.noop,fn:o.program(17,t,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+="</a>\n ";return A}function t(C,B){var A;if(A=p.text){A=A.call(C,{hash:{},data:B})}else{A=C.text;A=typeof A===e?A.apply(C):A}return d(A)}function s(D,C){var A="",B;A+='\n <pre class="peek">';if(B=p.peek){B=B.call(D,{hash:{},data:C})}else{B=D.peek;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+="</pre>\n ";return A}q+='<div class="dataset-body">\n ';h=p["if"].call(r,r.body,{hash:{},inverse:o.program(3,m,z),fn:o.program(1,n,z),data:z});if(h||h===0){q+=h}q+="\n</div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-skeleton"]=b(function(f,r,p,k,w){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,f.helpers);w=w||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(B,A){var x="",z,y;x+='\n <div class="errormessagesmall">\n ';y={hash:{},inverse:o.noop,fn:o.program(2,m,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+=":\n ";y={hash:{},inverse:o.noop,fn:o.program(4,l,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </div>\n ";return x}function m(y,x){return"There was an error getting the data for this dataset"}function l(z,y){var x;if(x=p.error){x=x.call(z,{hash:{},data:y})}else{x=z.error;x=typeof x===e?x.apply(z):x}return d(x)}function j(A,z){var x="",y;x+="\n ";y=p["if"].call(A,A.purged,{hash:{},inverse:o.program(10,v,z),fn:o.program(7,i,z),data:z});if(y||y===0){x+=y}x+="\n ";return x}function i(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(8,g,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n\n ";return x}function g(y,x){return"This dataset has been deleted and removed from disk."}function v(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(11,u,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n \n Click <a href="javascript:void(0);" class="dataset-undelete">here</a> to undelete it\n or <a href="javascript:void(0);" class="dataset-purge">here</a> to immediately remove it from disk\n </strong></div>\n ';return x}function u(y,x){return"This dataset has been deleted."}function t(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(14,s,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n Click <a href="javascript:void(0);" class="dataset-unhide">here</a> to unhide it\n </strong></div>\n ';return x}function s(y,x){return"This dataset has been hidden."}q+='<div class="dataset hda">\n <div class="dataset-warnings">\n ';h=p["if"].call(r,r.error,{hash:{},inverse:o.noop,fn:o.program(1,n,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p["if"].call(r,r.deleted,{hash:{},inverse:o.noop,fn:o.program(6,j,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p.unless.call(r,r.visible,{hash:{},inverse:o.noop,fn:o.program(13,t,w),data:w});if(h||h===0){q+=h}q+='\n </div>\n\n <div class="dataset-selector"><span class="fa fa-2x fa-square-o"></span></div>\n <div class="dataset-primary-actions"></div>\n <div class="dataset-title-bar clear">\n <span class="dataset-state-icon state-icon"></span>\n <div class="dataset-title">\n <span class="hda-hid">';if(h=p.hid){h=h.call(r,{hash:{},data:w})}else{h=r.hid;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n <span class="dataset-name">';if(h=p.name){h=h.call(r,{hash:{},data:w})}else{h=r.name;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n </div>\n </div>\n\n <div class="dataset-body"></div>\n</div>';return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(g,r,p,k,u){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);u=u||{};var q="",i,f,o=this,e="function",c=p.blockHelperMissing,d=this.escapeExpression;function n(z,y){var v="",x,w;v+='\n <div class="history-name" title="';w={hash:{},inverse:o.noop,fn:o.program(2,m,y),data:y};if(x=p.local){x=x.call(z,w)}else{x=z.local;x=typeof x===e?x.apply(z):x}if(!p.local){x=c.call(z,x,w)}if(x||x===0){v+=x}v+='">\n ';if(x=p.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===e?x.apply(z):x}v+=d(x)+"\n </div>\n ";return v}function m(w,v){return"You must be logged in to edit your history name"}function l(y,x){var v="",w;v+='\n <div class="history-size">';if(w=p.nice_size){w=w.call(y,{hash:{},data:x})}else{w=y.nice_size;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function j(y,x){var v="",w;v+='\n \n <div class="';if(w=p.status){w=w.call(y,{hash:{},data:x})}else{w=y.status;w=typeof w===e?w.apply(y):w}v+=d(w)+'message">';if(w=p.message){w=w.call(y,{hash:{},data:x})}else{w=y.message;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function h(w,v){return"You are over your disk quota"}function t(w,v){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(w,v){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(4,l,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(6,j,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(8,h,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(10,t,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(12,s,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(h,s,q,l,w){this.compilerInfo=[4,">= 1.0.0"];q=this.merge(q,h.helpers);w=w||{};var r="",i,f,p=this,e="function",c=q.blockHelperMissing,d=this.escapeExpression;function o(B,A){var x="",z,y;x+='\n <div class="history-name" title="';y={hash:{},inverse:p.noop,fn:p.program(2,n,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='">\n ';if(z=q.name){z=z.call(B,{hash:{},data:A})}else{z=B.name;z=typeof z===e?z.apply(B):z}x+=d(z)+"\n </div>\n ";return x}function n(y,x){return"Click to rename history"}function m(A,z){var x="",y;x+='\n <div class="history-size">';if(y=q.nice_size){y=y.call(A,{hash:{},data:z})}else{y=A.nice_size;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function k(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:p.noop,fn:p.program(7,j,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n ";return x}function j(y,x){return"You are currently viewing a deleted history!"}function g(A,z){var x="",y;x+='\n \n <div class="';if(y=q.status){y=y.call(A,{hash:{},data:z})}else{y=A.status;y=typeof y===e?y.apply(A):y}x+=d(y)+'message">';if(y=q.message){y=y.call(A,{hash:{},data:z})}else{y=A.message;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function v(y,x){return"You are over your disk quota"}function u(y,x){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function t(y,x){return"Your history is empty. Click 'Get Data' on the left pane to start"}r+='<div class="history-controls">\n\n <div class="history-title">\n ';i=q["if"].call(s,s.name,{hash:{},inverse:p.noop,fn:p.program(1,o,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=q["if"].call(s,s.nice_size,{hash:{},inverse:p.noop,fn:p.program(4,m,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="history-secondary-actions">\n </div>\n </div>\n\n ';i=q["if"].call(s,s.deleted,{hash:{},inverse:p.noop,fn:p.program(6,k,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="message-container">\n ';i=q["if"].call(s,s.message,{hash:{},inverse:p.noop,fn:p.program(9,g,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:p.noop,fn:p.program(11,v,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+=".\n ";f={hash:{},inverse:p.noop,fn:p.program(13,u,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:p.noop,fn:p.program(15,t,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+="\n </div>";return r})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-body"]=b(function(g,r,p,k,z){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);z=z||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';if(B=p.body){B=B.call(D,{hash:{},data:C})}else{B=D.body;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+='\n </div>\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';return A}function m(D,C){var A="",B;A+='\n <div class="dataset-summary">\n ';B=p["if"].call(D,D.misc_blurb,{hash:{},inverse:o.noop,fn:o.program(4,l,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.data_type,{hash:{},inverse:o.noop,fn:o.program(6,j,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.metadata_dbkey,{hash:{},inverse:o.noop,fn:o.program(9,f,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p["if"].call(D,D.misc_info,{hash:{},inverse:o.noop,fn:o.program(12,x,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-actions clear">\n <div class="left"></div>\n <div class="right"></div>\n </div>\n\n ';B=p.unless.call(D,D.deleted,{hash:{},inverse:o.noop,fn:o.program(14,w,C),data:C});if(B||B===0){A+=B}A+="\n\n ";return A}function l(D,C){var A="",B;A+='\n <div class="dataset-blurb">\n <span class="value">';if(B=p.misc_blurb){B=B.call(D,{hash:{},data:C})}else{B=D.misc_blurb;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function j(E,D){var A="",C,B;A+='\n <div class="dataset-datatype">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(7,i,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">';if(C=p.data_type){C=C.call(E,{hash:{},data:D})}else{C=E.data_type;C=typeof C===e?C.apply(E):C}A+=d(C)+"</span>\n </div>\n ";return A}function i(B,A){return"format"}function f(E,D){var A="",C,B;A+='\n <div class="dataset-dbkey">\n <label class="prompt">';B={hash:{},inverse:o.noop,fn:o.program(10,y,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+='</label>\n <span class="value">\n ';if(C=p.metadata_dbkey){C=C.call(E,{hash:{},data:D})}else{C=E.metadata_dbkey;C=typeof C===e?C.apply(E):C}A+=d(C)+"\n </span>\n </div>\n ";return A}function y(B,A){return"database"}function x(D,C){var A="",B;A+='\n <div class="dataset-info">\n <span class="value">';if(B=p.misc_info){B=B.call(D,{hash:{},data:C})}else{B=D.misc_info;B=typeof B===e?B.apply(D):B}A+=d(B)+"</span>\n </div>\n ";return A}function w(D,C){var A="",B;A+='\n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n <div class="dataset-display-applications">\n ';B=p.each.call(D,D.display_apps,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+="\n\n ";B=p.each.call(D,D.display_types,{hash:{},inverse:o.noop,fn:o.program(15,v,C),data:C});if(B||B===0){A+=B}A+='\n </div>\n\n <div class="dataset-peek">\n ';B=p["if"].call(D,D.peek,{hash:{},inverse:o.noop,fn:o.program(19,s,C),data:C});if(B||B===0){A+=B}A+="\n </div>\n\n ";return A}function v(D,C){var A="",B;A+='\n <div class="display-application">\n <span class="display-application-location">';if(B=p.label){B=B.call(D,{hash:{},data:C})}else{B=D.label;B=typeof B===e?B.apply(D):B}A+=d(B)+'</span>\n <span class="display-application-links">\n ';B=p.each.call(D,D.links,{hash:{},inverse:o.noop,fn:o.program(16,u,C),data:C});if(B||B===0){A+=B}A+="\n </span>\n </div>\n ";return A}function u(E,D){var A="",C,B;A+='\n <a target="';if(C=p.target){C=C.call(E,{hash:{},data:D})}else{C=E.target;C=typeof C===e?C.apply(E):C}A+=d(C)+'" href="';if(C=p.href){C=C.call(E,{hash:{},data:D})}else{C=E.href;C=typeof C===e?C.apply(E):C}A+=d(C)+'">';B={hash:{},inverse:o.noop,fn:o.program(17,t,D),data:D};if(C=p.local){C=C.call(E,B)}else{C=E.local;C=typeof C===e?C.apply(E):C}if(!p.local){C=c.call(E,C,B)}if(C||C===0){A+=C}A+="</a>\n ";return A}function t(C,B){var A;if(A=p.text){A=A.call(C,{hash:{},data:B})}else{A=C.text;A=typeof A===e?A.apply(C):A}return d(A)}function s(D,C){var A="",B;A+='\n <pre class="peek">';if(B=p.peek){B=B.call(D,{hash:{},data:C})}else{B=D.peek;B=typeof B===e?B.apply(D):B}if(B||B===0){A+=B}A+="</pre>\n ";return A}q+='<div class="dataset-body">\n ';h=p["if"].call(r,r.body,{hash:{},inverse:o.program(3,m,z),fn:o.program(1,n,z),data:z});if(h||h===0){q+=h}q+="\n</div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-hda-skeleton"]=b(function(f,r,p,k,w){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,f.helpers);w=w||{};var q="",h,e="function",d=this.escapeExpression,o=this,c=p.blockHelperMissing;function n(B,A){var x="",z,y;x+='\n <div class="errormessagesmall">\n ';y={hash:{},inverse:o.noop,fn:o.program(2,m,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+=":\n ";y={hash:{},inverse:o.noop,fn:o.program(4,l,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </div>\n ";return x}function m(y,x){return"There was an error getting the data for this dataset"}function l(z,y){var x;if(x=p.error){x=x.call(z,{hash:{},data:y})}else{x=z.error;x=typeof x===e?x.apply(z):x}return d(x)}function j(A,z){var x="",y;x+="\n ";y=p["if"].call(A,A.purged,{hash:{},inverse:o.program(10,v,z),fn:o.program(7,i,z),data:z});if(y||y===0){x+=y}x+="\n ";return x}function i(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(8,g,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n\n ";return x}function g(y,x){return"This dataset has been deleted and removed from disk."}function v(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(11,u,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n \n Click <a href="javascript:void(0);" class="dataset-undelete">here</a> to undelete it\n or <a href="javascript:void(0);" class="dataset-purge">here</a> to immediately remove it from disk\n </strong></div>\n ';return x}function u(y,x){return"This dataset has been deleted."}function t(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:o.noop,fn:o.program(14,s,A),data:A};if(z=p.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!p.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='\n \n Click <a href="javascript:void(0);" class="dataset-unhide">here</a> to unhide it\n </strong></div>\n ';return x}function s(y,x){return"This dataset has been hidden."}q+='<div class="dataset hda">\n <div class="dataset-warnings">\n ';h=p["if"].call(r,r.error,{hash:{},inverse:o.noop,fn:o.program(1,n,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p["if"].call(r,r.deleted,{hash:{},inverse:o.noop,fn:o.program(6,j,w),data:w});if(h||h===0){q+=h}q+="\n\n ";h=p.unless.call(r,r.visible,{hash:{},inverse:o.noop,fn:o.program(13,t,w),data:w});if(h||h===0){q+=h}q+='\n </div>\n\n <div class="dataset-selector"><span class="fa fa-2x fa-square-o"></span></div>\n <div class="dataset-primary-actions"></div>\n <div class="dataset-title-bar clear">\n <span class="dataset-state-icon state-icon"></span>\n <div class="dataset-title">\n <span class="hda-hid">';if(h=p.hid){h=h.call(r,{hash:{},data:w})}else{h=r.hid;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n <span class="dataset-name">';if(h=p.name){h=h.call(r,{hash:{},data:w})}else{h=r.name;h=typeof h===e?h.apply(r):h}q+=d(h)+'</span>\n </div>\n </div>\n\n <div class="dataset-body"></div>\n</div>';return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel-anon"]=b(function(g,r,p,k,u){this.compilerInfo=[4,">= 1.0.0"];p=this.merge(p,g.helpers);u=u||{};var q="",i,f,o=this,e="function",c=p.blockHelperMissing,d=this.escapeExpression;function n(z,y){var v="",x,w;v+='\n <div class="history-name" title="';w={hash:{},inverse:o.noop,fn:o.program(2,m,y),data:y};if(x=p.local){x=x.call(z,w)}else{x=z.local;x=typeof x===e?x.apply(z):x}if(!p.local){x=c.call(z,x,w)}if(x||x===0){v+=x}v+='">\n ';if(x=p.name){x=x.call(z,{hash:{},data:y})}else{x=z.name;x=typeof x===e?x.apply(z):x}v+=d(x)+"\n </div>\n ";return v}function m(w,v){return"You must be logged in to edit your history name"}function l(y,x){var v="",w;v+='\n <div class="history-size">';if(w=p.nice_size){w=w.call(y,{hash:{},data:x})}else{w=y.nice_size;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function j(y,x){var v="",w;v+='\n \n <div class="';if(w=p.status){w=w.call(y,{hash:{},data:x})}else{w=y.status;w=typeof w===e?w.apply(y):w}v+=d(w)+'message">';if(w=p.message){w=w.call(y,{hash:{},data:x})}else{w=y.message;w=typeof w===e?w.apply(y):w}v+=d(w)+"</div>\n ";return v}function h(w,v){return"You are over your disk quota"}function t(w,v){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function s(w,v){return"Your history is empty. Click 'Get Data' on the left pane to start"}q+='<div class="history-controls">\n\n <div class="history-title">\n \n ';i=p["if"].call(r,r.name,{hash:{},inverse:o.noop,fn:o.program(1,n,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=p["if"].call(r,r.nice_size,{hash:{},inverse:o.noop,fn:o.program(4,l,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="message-container">\n ';i=p["if"].call(r,r.message,{hash:{},inverse:o.noop,fn:o.program(6,j,u),data:u});if(i||i===0){q+=i}q+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:o.noop,fn:o.program(8,h,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+=".\n ";f={hash:{},inverse:o.noop,fn:o.program(10,t,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+='.\n </div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:o.noop,fn:o.program(12,s,u),data:u};if(i=p.local){i=i.call(r,f)}else{i=r.local;i=typeof i===e?i.apply(r):i}if(!p.local){i=c.call(r,i,f)}if(i||i===0){q+=i}q+="\n </div>";return q})})();(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(h,s,q,l,w){this.compilerInfo=[4,">= 1.0.0"];q=this.merge(q,h.helpers);w=w||{};var r="",i,f,p=this,e="function",c=q.blockHelperMissing,d=this.escapeExpression;function o(B,A){var x="",z,y;x+='\n <div class="history-name" title="';y={hash:{},inverse:p.noop,fn:p.program(2,n,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='">\n ';if(z=q.name){z=z.call(B,{hash:{},data:A})}else{z=B.name;z=typeof z===e?z.apply(B):z}x+=d(z)+"\n </div>\n ";return x}function n(y,x){return"Click to rename history"}function m(A,z){var x="",y;x+='\n <div class="history-size">';if(y=q.nice_size){y=y.call(A,{hash:{},data:z})}else{y=A.nice_size;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function k(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:p.noop,fn:p.program(7,j,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n ";return x}function j(y,x){return"You are currently viewing a deleted history!"}function g(A,z){var x="",y;x+='\n \n <div class="';if(y=q.status){y=y.call(A,{hash:{},data:z})}else{y=A.status;y=typeof y===e?y.apply(A):y}x+=d(y)+'message">';if(y=q.message){y=y.call(A,{hash:{},data:z})}else{y=A.message;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function v(y,x){return"You are over your disk quota"}function u(y,x){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function t(y,x){return"Your history is empty. Click 'Get Data' on the left pane to start"}r+='<div class="history-controls">\n\n <div class="history-title">\n ';i=q["if"].call(s,s.name,{hash:{},inverse:p.noop,fn:p.program(1,o,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=q["if"].call(s,s.nice_size,{hash:{},inverse:p.noop,fn:p.program(4,m,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n ';i=q["if"].call(s,s.deleted,{hash:{},inverse:p.noop,fn:p.program(6,k,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="message-container">\n ';i=q["if"].call(s,s.message,{hash:{},inverse:p.noop,fn:p.program(9,g,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:p.noop,fn:p.program(11,v,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+=".\n ";f={hash:{},inverse:p.noop,fn:p.program(13,u,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:p.noop,fn:p.program(15,t,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+="\n </div>";return r})})();
\ No newline at end of file
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/packed/templates/compiled/template-history-historyPanel.js
--- a/static/scripts/packed/templates/compiled/template-history-historyPanel.js
+++ b/static/scripts/packed/templates/compiled/template-history-historyPanel.js
@@ -1,1 +1,1 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(h,s,q,l,w){this.compilerInfo=[4,">= 1.0.0"];q=this.merge(q,h.helpers);w=w||{};var r="",i,f,p=this,e="function",c=q.blockHelperMissing,d=this.escapeExpression;function o(B,A){var x="",z,y;x+='\n <div class="history-name" title="';y={hash:{},inverse:p.noop,fn:p.program(2,n,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='">\n ';if(z=q.name){z=z.call(B,{hash:{},data:A})}else{z=B.name;z=typeof z===e?z.apply(B):z}x+=d(z)+"\n </div>\n ";return x}function n(y,x){return"Click to rename history"}function m(A,z){var x="",y;x+='\n <div class="history-size">';if(y=q.nice_size){y=y.call(A,{hash:{},data:z})}else{y=A.nice_size;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function k(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:p.noop,fn:p.program(7,j,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n ";return x}function j(y,x){return"You are currently viewing a deleted history!"}function g(A,z){var x="",y;x+='\n \n <div class="';if(y=q.status){y=y.call(A,{hash:{},data:z})}else{y=A.status;y=typeof y===e?y.apply(A):y}x+=d(y)+'message">';if(y=q.message){y=y.call(A,{hash:{},data:z})}else{y=A.message;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function v(y,x){return"You are over your disk quota"}function u(y,x){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function t(y,x){return"Your history is empty. Click 'Get Data' on the left pane to start"}r+='<div class="history-controls">\n\n <div class="history-title">\n ';i=q["if"].call(s,s.name,{hash:{},inverse:p.noop,fn:p.program(1,o,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=q["if"].call(s,s.nice_size,{hash:{},inverse:p.noop,fn:p.program(4,m,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="history-secondary-actions">\n </div>\n </div>\n\n ';i=q["if"].call(s,s.deleted,{hash:{},inverse:p.noop,fn:p.program(6,k,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="message-container">\n ';i=q["if"].call(s,s.message,{hash:{},inverse:p.noop,fn:p.program(9,g,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:p.noop,fn:p.program(11,v,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+=".\n ";f={hash:{},inverse:p.noop,fn:p.program(13,u,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:p.noop,fn:p.program(15,t,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+="\n </div>";return r})})();
\ No newline at end of file
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(h,s,q,l,w){this.compilerInfo=[4,">= 1.0.0"];q=this.merge(q,h.helpers);w=w||{};var r="",i,f,p=this,e="function",c=q.blockHelperMissing,d=this.escapeExpression;function o(B,A){var x="",z,y;x+='\n <div class="history-name" title="';y={hash:{},inverse:p.noop,fn:p.program(2,n,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+='">\n ';if(z=q.name){z=z.call(B,{hash:{},data:A})}else{z=B.name;z=typeof z===e?z.apply(B):z}x+=d(z)+"\n </div>\n ";return x}function n(y,x){return"Click to rename history"}function m(A,z){var x="",y;x+='\n <div class="history-size">';if(y=q.nice_size){y=y.call(A,{hash:{},data:z})}else{y=A.nice_size;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function k(B,A){var x="",z,y;x+='\n <div class="warningmessagesmall"><strong>\n ';y={hash:{},inverse:p.noop,fn:p.program(7,j,A),data:A};if(z=q.local){z=z.call(B,y)}else{z=B.local;z=typeof z===e?z.apply(B):z}if(!q.local){z=c.call(B,z,y)}if(z||z===0){x+=z}x+="\n </strong></div>\n ";return x}function j(y,x){return"You are currently viewing a deleted history!"}function g(A,z){var x="",y;x+='\n \n <div class="';if(y=q.status){y=y.call(A,{hash:{},data:z})}else{y=A.status;y=typeof y===e?y.apply(A):y}x+=d(y)+'message">';if(y=q.message){y=y.call(A,{hash:{},data:z})}else{y=A.message;y=typeof y===e?y.apply(A):y}x+=d(y)+"</div>\n ";return x}function v(y,x){return"You are over your disk quota"}function u(y,x){return"Tool execution is on hold until your disk usage drops below your allocated quota"}function t(y,x){return"Your history is empty. Click 'Get Data' on the left pane to start"}r+='<div class="history-controls">\n\n <div class="history-title">\n ';i=q["if"].call(s,s.name,{hash:{},inverse:p.noop,fn:p.program(1,o,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="history-subtitle clear">\n ';i=q["if"].call(s,s.nice_size,{hash:{},inverse:p.noop,fn:p.program(4,m,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="history-secondary-actions"></div>\n </div>\n\n ';i=q["if"].call(s,s.deleted,{hash:{},inverse:p.noop,fn:p.program(6,k,w),data:w});if(i||i===0){r+=i}r+='\n\n <div class="message-container">\n ';i=q["if"].call(s,s.message,{hash:{},inverse:p.noop,fn:p.program(9,g,w),data:w});if(i||i===0){r+=i}r+='\n </div>\n\n <div class="quota-message errormessage">\n ';f={hash:{},inverse:p.noop,fn:p.program(11,v,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+=".\n ";f={hash:{},inverse:p.noop,fn:p.program(13,u,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+='.\n </div>\n \n <div class="tags-display"></div>\n <div class="annotation-display"></div>\n\n </div>\n\n \n <div class="datasets-list"></div>\n\n <div class="empty-history-message infomessagesmall">\n ';f={hash:{},inverse:p.noop,fn:p.program(15,t,w),data:w};if(i=q.local){i=i.call(s,f)}else{i=s.local;i=typeof i===e?i.apply(s):i}if(!q.local){i=c.call(s,i,f)}if(i||i===0){r+=i}r+="\n </div>";return r})})();
\ No newline at end of file
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/packed/viz/trackster/tracks.js
--- a/static/scripts/packed/viz/trackster/tracks.js
+++ b/static/scripts/packed/viz/trackster/tracks.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","viz/trackster/filters","mvc/data","mvc/tools"],function(ab,y,l,u,L,i,X,R){var q=ab.extend;var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(".track,.group"),am=n[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();var ar=n[ai.attr("id")];if(ap.offsetY<aq){$(this).insertBefore(ai);ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}n[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};var F=20,B=100,I=12000,S=400,K=5000,x=100,o="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",G="No data for this chrom/contig.",w="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",z="Tool cannot be rerun: ",b="Loading data...",U="Ready for display",Q=10,H=20,C=["Histogram","Line","Filled","Intensity"];function V(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.view=ad;this.container=ac;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.config=new j({params:this.config_params,onchange:this.config_onchange,saved_values:af.prefs});this.prefs=this.config.get("values");if(!this.prefs.name){this.prefs.name=af.name}if(this.config_onchange){this.config.on("change:values",this.config_onchange,this)}this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").css("float","left").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.prefs.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.prefs.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.prefs.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"gear",on_click_fn:function(ad){var ac=new a({model:ad.config});ac.render()}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".tooltip").remove();ac.remove()}}];q(r.prototype,{config_params:[{key:"name",label:"Name",type:"text",default_value:""},{key:"content_visible",type:"bool",default_value:true,hidden:true}],config_onchange:function(){this.track.set_name(this.track.config.get("values").name)},init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.prefs.content_visible){return true}return false},request_draw:function(){},_draw:function(ac){},to_dict:function(){},set_name:function(ac){this.old_name=this.prefs.name;this.prefs.name=ac;this.name_div.text(this.prefs.name)},revert_name:function(){if(this.old_name){this.prefs.name=this.old_name;this.name_div.text(this.prefs.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var A=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(A.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(ac){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad]._draw(ac)}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(af){var ac=this.drawables.slice(0),ad=[],ae;while(ac.length!==0){ae=ac.shift();if(ae instanceof af){ad.push(ae)}else{if(ae.drawables){ac=ac.concat(ae.drawables)}}}return ad}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});A.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,A.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw({clear_tile_cache:true})}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.prefs.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof d){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ad=new f(this.view,this.view,{name:this.prefs.name,drawables:this.drawables});var ac=this.container.replace_drawable(this,ad,true);ad.request_draw()},add_drawable:function(ac){A.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){A.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(A.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac){ab.each(this.drawables,function(ad){ad.request_draw(ac)})}});var Y=Backbone.View.extend({initialize:function(ac){q(ac,{obj_type:"View"});A.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new y.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new j({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"}],saved_values:ac.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){y.select_datasets(galaxy_config.root+"visualization/list_current_history_datasets",galaxy_config.root+"api/datasets",{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_tracks(d),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div/>").addClass("zoom-area").css("height",ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ac){return this.config.get("values")[ac.toLowerCase()+"_color"]||this.config.get("values").n_color}});q(Y.prototype,A.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=x;var ac=this,ad=$.Deferred();$.ajax({url:galaxy_config.root+"api/genomes/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){var ah=new D(ac);ac.add_label_track(ah);ac.reference_track=ah}ac.chrom_data=ag.chrom_info;var ak='<option value="">Select Chrom/Contig</option>';for(var aj=0,af=ac.chrom_data.length;aj<af;aj++){var ai=ac.chrom_data[aj].chrom;ak+='<option value="'+ai+'">'+ai+"</option>"}if(ag.prev_chroms){ak+='<option value="previous">Previous '+x+"</option>"}if(ag.next_chroms){ak+='<option value="next">Next '+x+"</option>"}ac.chrom_select.html(ak);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey: "+ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-x});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+x});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad&&aj){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/,/g,"");ag=ag.replace(/:|\-/g," ");var ad=ag.split(/\s+/),af=ad[0],ae=(ad[1]?parseInt(ad[1],10):null),ac=(ad[2]?parseInt(ad[2],10):null);if(!ac){ae=ae-15;ac=ae+15}this.change_chrom(af,ae,ac)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ac.request_redraw()},200);var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){A.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){A.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ad,ae){var ac=this,af=(ae?[ae]:ac.drawables);ab.each(af,function(ag){var ah=ab.find(ac.tracks_to_be_redrawn,function(ai){return ai[0]===ag});if(ah){ah[1]=ad}else{ac.tracks_to_be_redrawn.push([ag,ad])}});if(!this.requested_redraw){requestAnimationFrame(function(){ac._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ac=this.low,ag=this.high;if(ac<this.max_low){ac=this.max_low}if(ag>this.max_high){ag=this.max_high}var ad=this.high-this.low;if(this.high!==0&&ad<this.min_separation){ag=ac+this.min_separation}this.low=Math.floor(ac);this.high=Math.ceil(ag);this.update_location(this.low,this.high);this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var af=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ah=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:af,width:Math.max(ae,ah)}).show();if(ah<ae){this.overview_box.css("left",af-(ae-ah)/2)}if(this.overview_highlight){this.overview_highlight.css({left:af,width:ah})}ab.each(this.tracks_to_be_redrawn,function(ak){var ai=ak[0],aj=ak[1];if(ai){ai._draw(aj)}});this.tracks_to_be_redrawn=[];ab.each(this.label_tracks,function(ai){ai._draw()})},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset.id===ae.dataset.id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=R.Tool.extend({defaults:{track:null},initialize:function(ac){R.Tool.prototype.initialize.call(this,ac);var ad=true;if(ac.tool_state!==undefined&&ac.tool_state.hidden!==undefined){ad=ac.tool_state.hidden}this.set("hidden",ad);this.remove_inputs(["data","hidden_data","conditional"])},state_dict:function(ac){return ab.extend(this.get_inputs_dict(),{hidden:!this.is_visible()})}});var v=Backbone.View.extend({events:{"change input":"update_value"},render:function(){var ae=this.$el.addClass("param-row"),af=this.model;var ac=$("<div>").addClass("param-label").text(af.get("label")).appendTo(ae);var ad=$("<div/>").addClass("param-input").html(af.get("html")).appendTo(ae);ad.find(":input").val(af.get("value"));$("<div style='clear: both;'/>").appendTo(ae)},update_value:function(ac){this.model.set_value($(ac.target).val())}});var aa=Backbone.View.extend({initialize:function(ac){this.model.on("change:hidden",this.set_visible,this)},render:function(){var ad=this;tool=this.model,parent_div=this.$el.addClass("dynamic-tool").hide();parent_div.bind("drag",function(ah){ah.stopPropagation()}).click(function(ah){ah.stopPropagation()}).bind("dblclick",function(ah){ah.stopPropagation()}).keydown(function(ah){ah.stopPropagation()});var ae=$("<div class='tool-name'>").appendTo(parent_div).text(tool.get("name"));tool.get("inputs").each(function(ai){var ah=new v({model:ai});ah.render();parent_div.append(ah.$el)});parent_div.find("input").click(function(){$(this).select()});var af=$("<div>").addClass("param-row").appendTo(parent_div);var ag=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(af);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(af);ac.click(function(){ad.run_on_region()});ag.click(function(){ad.run_on_dataset()});if(tool.is_visible()){this.$el.show()}},set_visible:function(){if(this.model.is_visible()){this.$el.show()}else{this.$el.hide()}},update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},run_on_dataset:function(){var ac=this.model;this.run({target_dataset_id:this.model.get("track").dataset.id,action:"rerun",tool_id:ac.id},null,function(ad){Galaxy.modal.show({title:ac.get("name")+" is Running",body:ac.get("name")+" is running on the complete dataset. Tool outputs are in dataset's history.",buttons:{Close:function(){Galaxy.modal.hide()}}})})},run_on_region:function(){var ad=this.model.get("track"),ag=this.model,ai=new y.GenomeRegion({chrom:ad.view.chrom,start:ad.view.low,end:ad.view.high}),aj={target_dataset_id:ad.dataset.id,action:"rerun",tool_id:ag.id,regions:[ai.toJSON()]},ah=ad,al=ag.get("name")+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ak=new P(view,view,{name:ad.prefs.name});var af=ah.container.replace_drawable(ah,ak,false);ak.container_div.insertBefore(ah.view.content_div.children()[af]);ak.add_drawable(ah);ah.container_div.appendTo(ak.content_div);ac=ak}else{ac=ah.container}var ae=new ah.constructor(view,ac,{name:al,hda_ldda:"hda"});ae.init_for_tool_data();ae.change_mode(ah.mode);ae.set_filters_manager(ah.filters_manager.copy(ae));ae.update_icons();ac.add_drawable(ae);ae.tiles_div.text("Starting job.");this.run(aj,ae,function(am){ae.set_dataset(new X.Dataset(am));ae.tiles_div.text("Running job.");ae.init()})},run:function(ac,ae,af){ac.inputs=this.model.get_inputs_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_config.root+"api/tools",data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(z+ag.message)}else{af(ag)}}})}});var E=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};E.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var j=Backbone.Model.extend({initialize:function(ad){var ac={};ab.each(ad.params,function(ae){ac[ae.key]=(ae.type==="color"&&!ae.default_value?l.get_random_color():ae.default_value)});if(ad.saved_values){ab.each(this.get("params"),function(ae){if(ae.key in ad.saved_values){ac[ae.key]=ad.saved_values[ae.key]}})}this.set("values",ac)},set_param_default_value:function(ad,ac){var ae=ab.find(this.get("params"),function(af){return af.key===ad});if(ae){ae.default_value=ac}},set_param_value:function(ac,ad){var ae=ab.find(this.get("params"),function(af){return af.key===ac});if(ae){if(typeof ad==="string"||ad instanceof String){if(ad.trim()===""){ad=ae.default_value}else{if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad,10)}}}}}if(this.get("values")[ac]!==ad){this.get("values")[ac]=ad;this.trigger("change:values");return true}else{return false}}});var a=Backbone.View.extend({render:function(){var aj=this.model;var ac=$("<div/>").keydown(function(ak){ak.stopPropagation()});var ai;function ah(ao,ak){for(var at=0;at<ao.length;at++){ai=ao[at];if(ai.hidden){continue}var am="param_"+at;var ax=aj.get("values")[ai.key];var az=$("<div class='form-row' />").appendTo(ak);az.append($("<label />").attr("for",am).text(ai.label+":"));if(ai.type==="bool"){az.append($('<input type="checkbox" />').attr("id",am).attr("name",am).attr("checked",ax))}else{if(ai.type==="text"){az.append($('<input type="text"/>').attr("id",am).val(ax).click(function(){$(this).select()}))}else{if(ai.type==="select"){var av=$("<select />").attr("id",am);for(var aq=0;aq<ai.options.length;aq++){$("<option/>").text(ai.options[aq].label).attr("value",ai.options[aq].value).appendTo(av)}av.val(ax);az.append(av)}else{if(ai.type==="color"){var ay=$("<div/>").appendTo(az),au=$("<input />").attr("id",am).attr("name",am).val(ax).css("float","left").appendTo(ay).click(function(aB){$(".tooltip").removeClass("in");var aA=$(this).siblings(".tooltip").addClass("in");aA.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top+Galaxy.modal.scrollTop()-($(aA).height()/2)+($(this).height()/2)}).show();aA.click(function(aC){aC.stopPropagation()});$(document).bind("click.color-picker",function(){aA.hide();$(document).unbind("click.color-picker")});aB.stopPropagation()}),ar=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(ay).attr("title","Set new random color").tooltip(),aw=$("<div class='tooltip right' style='position: absolute;' />").appendTo(ay).hide(),an=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(aw),al=$("<div class='tooltip-arrow'></div>").appendTo(aw),ap=$.farbtastic(an,{width:100,height:100,callback:au,color:ax});ay.append($("<div/>").css("clear","both"));(function(aA){ar.click(function(){aA.setColor(l.get_random_color())})})(ap)}else{az.append($("<input />").attr("id",am).attr("name",am).val(ax))}}}}if(ai.help){az.append($("<div class='help'/>").text(ai.help))}}}ah(aj.get("params"),ac);var ad=this,ag=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ae=function(){ad.update_from_form($(Galaxy.modal.el));Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},af=function(ak){if((ak.keyCode||ak.which)===27){ag()}else{if((ak.keyCode||ak.which)===13){ae()}}};$(window).bind("keypress.check_enter_esc",af);Galaxy.modal.show({title:"Configure",body:ac,buttons:{Cancel:ag,Ok:ae}})},update_from_form:function(ac){var ad=this.model;var ae=false;ab.each(ad.get("params"),function(ah,af){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}ae=ad.set_param_value(ah.key,ag)||ae}})}});var c=function(ac,af,ag,ad,ae){this.track=ac;this.region=af;this.low=af.get("start");this.high=af.get("end");this.w_scale=ag;this.canvas=ad;this.html_elt=$("<div class='track-tile'/>").append(ad);this.data=ae;this.stale=false};c.prototype.predisplay_actions=function(){};var M=function(ac,af,ag,ad,ae){c.call(this,ac,af,ag,ad,ae)};M.prototype.predisplay_actions=function(){};var O=function(af,am,ao,ae,ah,ai,ap,ad,al){c.call(this,af,am,ao,ae,ah);this.mode=ai;this.all_slotted=ad;this.feature_mapper=al;this.has_icons=false;if(ap){this.has_icons=true;var aj=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:F,width:ae.width}).prependTo(this.html_elt);var ak=new y.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),an=ah.length,ag=$("<a/>").addClass("icon more-down").attr("title","For speed, only the first "+an+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a/>").addClass("icon more-across").attr("title","For speed, only the first "+an+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ag.click(function(){aj.stale=true;af.data_manager.get_more_data(ak,af.mode,1/aj.w_scale,{},af.data_manager.DEEP_DATA_REQ);$(".tooltip").hide();af.request_draw()}).dblclick(function(aq){aq.stopPropagation()});ac.click(function(){aj.stale=true;af.data_manager.get_more_data(ak,af.mode,1/aj.w_scale,{},af.data_manager.BROAD_DATA_REQ);$(".tooltip").hide();af.request_draw()}).dblclick(function(aq){aq.stopPropagation()})}};q(O.prototype,c.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}af=$("<div/>").attr("id",ak).addClass("feature-popup");var au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?V(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"),10)-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"),10)+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=null;if(ae.dataset){this.dataset=(ae.dataset instanceof Backbone.Model?ae.dataset:new X.Dataset(ae.dataset))}this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new y.GenomeDataManager({dataset:this.dataset,genome:new y.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=this.prefs.height;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"application-dock-270",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"ui-slider-050",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.tool.toggle();if(ac.tool.is_visible()){ac.set_name(ac.prefs.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.get("name") %><br/><strong>Dataset</strong>: <%= track.prefs.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new y.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new y.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}Galaxy.modal.hide();window.location.href=galaxy_config.root+"visualization/sweepster?"+$.param({dataset_id:ac.dataset.id,hda_ldda:ac.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};Galaxy.modal.show({title:"Visualize tool parameter space and output from different parameter settings?",body:ae,buttons:{No:ah,Yes:ad}})}},r.prototype.action_icons_def[2]],can_draw:function(){return this.dataset&&r.prototype.can_draw.call(this)},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.prefs.name).attr("id",this.prefs.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},set_dataset:function(ac){this.dataset=ac;this.data_manager.set("dataset",ac)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.prefs.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.get("values").height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.get("values").mode?this.config.get("values").mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof W){return"LabelTrack"}else{if(this instanceof D){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Z){return"VariantTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof d){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.tiles_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset.id){return}var ac=$.Deferred(),af={hda_ldda:ad.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.content_div.text(o);if(ag.message){ad.content_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){Galaxy.modal.show({title:"Trackster Error",body:"<pre>"+ag.message+"</pre>",buttons:{Close:function(){Galaxy.modal.hide()}}})}));ad.content_div.append($("<span/>").text(" "));ad.content_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(G)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(w);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when.apply($,ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(af&&af.min&&af.max){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.config.set_param_default_value("min_value",ae);ac.config.set_param_default_value("max_value",ag);ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},get_drawables:function(){return this}});var N=function(ae,ad,ag){g.call(this,ae,ad,ag);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in ag?ag.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=(ag.tool?new s(ab.extend(ag.tool,{track:this,tool_state:ag.tool_state})):null);this.tile_cache=new y.Cache(Q);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){var af=new aa({model:this.tool});af.render();this.dynamic_tool_div=af.$el;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);if(!this.prefs.content_visible){this.tiles_div.hide()}this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(ag.mode){this.change_mode(ag.mode)}};q(N.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.get("values").mode=ad;if(ad==="Auto"){this.data_manager.clear()}ac.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ac){if(ac&&ac.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ac,this)},before_draw:function(){this.max_height_px=0},_draw:function(aq){if(!this.can_draw()){return}var an=aq&&aq.clear_after,al=this.view.low,ag=this.view.high,aj=ag-al,ad=this.view.container.width(),ap=this.view.resolution_px_b,af=1/ap;if(this.is_overview){al=this.view.max_low;ag=this.view.max_high;ap=ad/(view.max_high-view.max_low);af=1/ap}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(af*S)),ak,am,ah,ai=[],ao=[];while((ac*S*af)<ag){ak=Math.floor(ac*S*af);am=new y.GenomeRegion({chrom:this.view.chrom,start:ak,end:Math.min(ak+Math.ceil(S*af),this.view.max_high)});ah=this.draw_helper(am,ap,aq);ai.push(ah);$.when(ah).then(function(ar){ao.push(ar)});ac+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var ae=this;$.when.apply($,ai).then(function(){ae.tiles_div.children(".remove").remove();ao=ab.filter(ao,function(ar){return ar!==null});if(ao.length!==0){ae.postdraw_actions(ao,ad,ap,an)}})},_add_yaxis_label:function(af,ah){var ad=this,ag=(af==="max"?"top":"bottom"),ai=(af==="max"?"max":"min"),ac=(af==="max"?"max_value":"min_value"),ae=this.container_div.find(".yaxislabel."+ag);ah=ah||function(){ad.request_draw({clear_tile_cache:true})};if(ae.length!==0){ae.text(ad.prefs[ac])}else{ae=$("<div/>").text(ad.prefs[ac]).make_text_editable({num_cols:12,on_finish:function(aj){$(".tooltip").remove();ad.config.set_param_value(ac,aj);ah()},help_text:"Set "+ai+" value"}).addClass("yaxislabel "+ag).css("color",this.prefs.label_color);this.container_div.prepend(ae)}},postdraw_actions:function(af,ag,ai,ac){var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length>0){this.max_height_px=0;var ad=this;ab.each(af,function(aj){if(!(aj instanceof M)){aj.html_elt.remove();ad.draw_helper(aj.region,ai,{force:true,mode:"Coverage"})}});ad._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ah=ab.find(af,function(aj){return aj.has_icons});if(ah){ab.each(af,function(aj){if(!aj.has_icons){aj.html_elt.css("padding-top",F)}})}}},get_mode:function(ac){return this.mode},update_auto_mode:function(ac){},_get_drawables:function(){return[this]},draw_helper:function(al,an,ao){if(!ao){ao={}}var ad=ao.force,ai=ao.mode||this.mode,af=1/an,ae=this,ag=this._get_drawables(),am=this._gen_tile_cache_key(an,al),ah=function(ap){return(ap&&"track" in ap)};var aj=(ad?undefined:ae.tile_cache.get_elt(am));if(aj){if(ah(aj)){ae.show_tile(aj,an)}return aj}if(ao.data_fetch===false){return null}var ak=function(){var ap=(ab.find(C,function(ar){return ar===ai})?"Coverage":ai);var aq=ab.map(ag,function(ar){return ar.data_manager.get_data(al,ap,af,ae.data_url_extra_params)});if(view.reference_track){aq.push(view.reference_track.data_manager.get_data(al,ai,af,view.reference_track.data_url_extra_params))}return aq};var ac=$.Deferred();ae.tile_cache.set_elt(am,ac);$.when.apply($,ak()).then(function(){var ap=ak(),av=ap,aB;if(view.reference_track){aB=view.reference_track.data_manager.subset_entry(ap.pop(),al)}var aw=[],at=[];ab.each(ag,function(aG,aD){var aF=aG.mode,aE=av[aD];if(aF==="Auto"){aF=aG.get_mode(aE);aG.update_auto_mode(aF)}aw.push(aF);at.push(aG.get_canvas_height(aE,aF,an,aq))});var au=ae.view.canvas_manager.new_canvas(),ax=al.get("start"),aC=al.get("end"),ar=0,aq=Math.ceil((aC-ax)*an)+ae.left_offset,az=ab.max(at),ay;au.width=aq;au.height=(ao.height||az);var aA=au.getContext("2d");aA.translate(ae.left_offset,0);if(ag.length>1){aA.globalAlpha=0.5;aA.globalCompositeOperation="source-over"}ab.each(ag,function(aE,aD){ay=aE.draw_tile(av[aD],aA,aw[aD],al,an,aB)});if(ay!==undefined){ae.tile_cache.set_elt(am,ay);ae.show_tile(ay,an)}ac.resolve(ay)});return ac},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},_draw_line_track_tile:function(ac,ae,ah,ag,ai){var af=ae.canvas,ad=new L.LinePainter(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah);ad.draw(ae,af.width,af.height,ai);return new M(this,ag,ai,af,ac.data)},draw_tile:function(ac,ad,ag,af,ah,ae){},show_tile:function(ae,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){ag-=this.left_offset}ac.css("left",ag);if(ac.hasClass("remove")){ac.removeClass("remove")}else{this.tiles_div.append(ac)}ac.css("height","auto");this.max_height_px=Math.max(this.max_height_px,ac.height()-2);ac.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},tool_region_and_parameters_str:function(af){var ac=this,ae=(af!==undefined?af.toString():"all"),ad=ab.values(ac.tool.get_inputs_dict()).join(", ");return" - region=["+ae+"], parameters=["+ad+"]"},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="bigwig"}else{if(ac.dataset_type==="bigwig"||ac.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ac){if(ac.message||ac.extra_info==="no_detail"){return false}else{if(ac.dataset_type==="bigwig"){return(ac.data[1][0]-ac.data[0][0]===1)}}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state"}});var W=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(W.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ag){var ae=this.view,af=ae.high-ae.low,aj=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/aj)*aj,ah=this.view.container.width(),ad=$("<div/>").addClass("label-container");while(ac<ae.high){var ai=(ac-ae.low)/af*ah;ad.append($("<div/>").addClass("label").text(commatize(ac)).css({left:ai}));ac+=aj}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){N.call(this,ad,ac,ag);this.drawables=[];if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}ab.each(this.drawables,function(ah){if(ah instanceof d||ah instanceof T){ah.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,N.prototype,{display_modes:C,action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".tooltip").remove();ac.show_group()}}].concat(N.prototype.action_icons_def),to_dict:A.prototype.to_dict,add_drawable:A.prototype.add_drawable,unpack_drawables:A.prototype.unpack_drawables,change_mode:function(ac){N.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var af=new P(this.view,this.container,{name:this.prefs.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ad=ab.min(ab.map(this.drawables,function(ae){return ae.prefs.min_value})),ac=ab.max(ab.map(this.drawables,function(ae){return ae.prefs.max_value}));this.prefs.min_value=ad;this.prefs.max_value=ac;ab.each(this.drawables,function(ae){ae.prefs.min_value=ad;ae.prefs.max_value=ac})},update_all_min_max:function(){var ac=this;ab.each(this.drawables,function(ad){ad.prefs.min_value=ac.prefs.min_value;ad.prefs.max_value=ac.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ai,ac,al,ah){N.prototype.postdraw_actions.call(this,ai,ac,al,ah);var ag=-1,ae;for(ae=0;ae<ai.length;ae++){var aj=ai[ae].html_elt.find("canvas").height();if(aj>ag){ag=aj}}for(ae=0;ae<ai.length;ae++){var af=ai[ae];if(af.html_elt.find("canvas").height()!==ag){this.draw_helper(af.region,al,{force:true,height:ag});af.html_elt.remove()}}var ad=this,ak=function(){ad.update_all_min_max()};this._add_yaxis_label("min",ak);this._add_yaxis_label("max",ak)}});var D=function(ac){N.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});this.left_offset=ac.canvas_manager.char_width_px;this.container_div.addClass("reference-track");this.data_url=galaxy_config.root+"api/genomes/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new y.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};q(D.prototype,r.prototype,N.prototype,{config_params:ab.union(r.prototype.config_params,[{key:"height",type:"int",default_value:13,hidden:true}]),build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:r.prototype.can_draw,draw_helper:function(ad,ae,ac){if(ae>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,ad,ae,ac)}else{this.tiles_div.hide();return null}},can_subset:function(ac){return true},draw_tile:function(ae,ak,af,ah,al){var ad=this.data_manager.subset_entry(ae,ah),aj=ad.data;var ac=ak.canvas;ak.font=ak.canvas.manager.default_font;ak.textAlign="center";for(var ag=0,ai=aj.length;ag<ai;ag++){ak.fillStyle=this.view.get_base_color(aj[ag]);ak.fillText(aj[ag],Math.floor(ag*al),10)}return new c(this,ah,al,ac,ad)}});var h=function(ad,ac,ae){this.mode="Histogram";N.call(this,ad,ac,ae)};q(h.prototype,r.prototype,N.prototype,{display_modes:C,config_params:ab.union(r.prototype.config_params,[{key:"color",label:"Color",type:"color"},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:30,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},before_draw:function(){},draw_tile:function(ac,ad,af,ae,ag){return this._draw_line_track_tile(ac,ad,af,ae,ag)},can_subset:function(ac){return(ac.data[1][0]-ac.data[0][0]===1)},postdraw_actions:function(ad,ae,af,ac){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var t=function(ad,ac,ae){this.mode="Heatmap";N.call(this,ad,ac,ae)};q(t.prototype,r.prototype,N.prototype,{display_modes:["Heatmap"],config_params:ab.union(r.prototype.config_params,[{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},draw_tile:function(ac,ae,ah,ag,ai){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah);ad.draw(ae,af.width,af.height,ai);return new c(this,ag,ai,af,ac.data)}});var d=function(ad,ac,ae){N.call(this,ad,ac,ae);this.container_div.addClass("feature-track");this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(d.prototype,r.prototype,N.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:ab.union(r.prototype.config_params,[{key:"block_color",label:"Block color",type:"color"},{key:"reverse_strand_color",label:"Antisense strand color",type:"color"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.set_painter_from_config();this.request_draw({clear_tile_cache:true})},set_painter_from_config:function(){if(this.config.get("values").connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(am,ae,an,al){N.prototype.postdraw_actions.call(this,am,ae,an,al);var ag=this,ah;if(ag.filters_manager){var af=ag.filters_manager.filters,aj;for(aj=0;aj<af.length;aj++){af[aj].update_ui_elt()}var ai=false,ak,ad;for(ah=0;ah<am.length;ah++){if(am[ah].data.length){ak=am[ah].data[0];for(aj=0;aj<af.length;aj++){ad=af[aj];if(ad.applies_to(ak)&&ad.min!==ad.max){ai=true;break}}}}if(ag.filters_available!==ai){ag.filters_available=ai;if(!ag.filters_available){ag.filters_manager.hide()}ag.update_icons()}}if(am[0] instanceof O){var ac=true;for(ah=0;ah<am.length;ah++){if(!am[ah].all_slotted){ac=false;break}}if(!ac){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,B,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="Coverage"||ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(this.min_height_px,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,af,aj,ae){var ap=this,ad=aq.canvas,ax=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(am.dataset_type==="bigwig"){return this._draw_line_track_tile(am,aq,ao,af,aj)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var ar=0,au=am.data.length;ar<au;ar++){var ah=am.data[ar];var at=false;var al;for(var aw=0,aB=ak.length;aw<aB;aw++){al=ak[aw];al.update_attrs(ah);if(!al.keep(ah)){at=true;break}}if(!at){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aA=(this.filters_manager.alpha_filter?new E(this.filters_manager.alpha_filter):null),ay=(this.filters_manager.height_filter?new E(this.filters_manager.height_filter):null),az=new (this.painter)(ai,ax,ac,this.prefs,ao,aA,ay,ae,function(aC){return ap.view.get_base_color(aC)});var av=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){av=az.draw(aq,ad.width,ad.height,aj,an);av.translation=-ag}return new O(ap,af,aj,ad,am.data,ao,am.message,all_slotted,av)}});var Z=function(ad,ac,ae){N.call(this,ad,ac,ae);this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};q(Z.prototype,r.prototype,N.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:ab.union(r.prototype.config_params,[{key:"color",label:"Histogram color",type:"color"},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},draw_tile:function(ac,af,ah,ag,ai){if(ac.dataset_type==="bigwig"){return this._draw_line_track_tile(ac,af,"Histogram",ag,ai)}else{var ae=this.view,ad=new (this.painter)(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah,function(aj){return ae.get_base_color(aj)});ad.draw(af,af.canvas.width,af.canvas.height,ai);return new c(this,ag,ai,af.canvas,ac.data)}},get_canvas_height:function(ac,ag,ah,ae){if(ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var ad=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ad===0&&ac.data.length!==0){ad=ac.data[0][7].match(/,/g);if(ad===null){ad=1}else{ad=ad.length+1}}var af=new (this.painter)(null,null,null,this.prefs,ag);return af.get_required_height(ad)}},predraw_init:function(){var ac=[g.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ac.push(this.dataset.fetch())}return ac},postdraw_actions:function(ag,ah,aj,ad){N.prototype.postdraw_actions.call(this,ag,ah,aj,ad);var af=ab.filter(ag,function(ak){return(ak instanceof M)});var ae=this.dataset.get_metadata("sample_names");if(af.length===0&&this.prefs.show_labels&&ae&&ae.length>1){var ac;if(this.container_div.find(".yaxislabel.variant").length===0){ac=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ac+"px",top:(this.prefs.summary_height-ac)/2+"px"}));if(this.prefs.show_sample_data){var ai=ae.join("<br/>");this.tiles_div.prepend($("<div/>").html(ai).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height,}))}}ac=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ac,"line-height":ac});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(ad,ac,ae){d.call(this,ad,ac,ae);this.painter=(ad.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};q(T.prototype,r.prototype,N.prototype,d.prototype,{config_params:ab.union(r.prototype.config_params,[{key:"block_color",label:"Block and sense strand color",type:"color"},{key:"reverse_strand_color",label:"Antisense strand color",type:"color"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})}});var e={CompositeTrack:f,DrawableGroup:P,DiagonalHeatmapTrack:t,FeatureTrack:d,LineTrack:h,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new e[af](ad,ac,ae)}};return{TracksterView:Y,DrawableGroup:P,LineTrack:h,FeatureTrack:d,DiagonalHeatmapTrack:t,ReadTrack:T,VariantTrack:Z,CompositeTrack:f,object_from_template:p}});
\ No newline at end of file
+define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","viz/trackster/filters","mvc/data","mvc/tools"],function(ab,y,l,u,L,i,X,R){var q=ab.extend;var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ad,af,ae){af=".group";n[ac.attr("id")]=ae;ac.bind("drag",{handle:"."+ad,relative:true},function(an,ao){var am=$(this),ar=$(this).parent(),aj=ar.children(".track,.group"),al=n[$(this).attr("id")],ai,ah,ap,ag,ak;ah=$(this).parents(af);if(ah.length!==0){ap=ah.position().top;ag=ap+ah.outerHeight();var aq=n[ah.attr("id")];if(ao.offsetY<ap){$(this).insertBefore(ah);aq.remove_drawable(al);aq.container.add_drawable_before(al,aq);return}else{if(ao.offsetY>ag){$(this).insertAfter(ah);aq.remove_drawable(al);aq.container.add_drawable(al);return}}}ah=null;for(ak=0;ak<aj.length;ak++){ai=$(aj.get(ak));ap=ai.position().top;ag=ap+ai.outerHeight();if(ai.is(af)&&this!==ai.get(0)&&ao.offsetY>=ap&&ao.offsetY<=ag){if(ao.offsetY-ap<ag-ao.offsetY){ai.find(".content-div").prepend(this)}else{ai.find(".content-div").append(this)}if(al.container){al.container.remove_drawable(al)}n[ai.attr("id")].add_drawable(al);return}}for(ak=0;ak<aj.length;ak++){ai=$(aj.get(ak));if(ao.offsetY<ai.position().top&&!(ai.hasClass("reference-track")||ai.hasClass("intro"))){break}}if(ak===aj.length){if(this!==aj.get(ak-1)){ar.append(this);n[ar.attr("id")].move_drawable(al,ak)}}else{if(this!==aj.get(ak)){$(this).insertBefore(aj.get(ak));n[ar.attr("id")].move_drawable(al,(ao.deltaY>0?ak-1:ak))}}}).bind("dragstart",function(){$(this).addClass("dragging")}).bind("dragend",function(){$(this).removeClass("dragging")})};var F=20,B=100,I=12000,S=400,K=5000,x=100,o="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",G="No data for this chrom/contig.",w="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",z="Tool cannot be rerun: ",b="Loading data...",U="Ready for display",Q=10,H=20,C=["Histogram","Line","Filled","Intensity"];function V(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.view=ad;this.container=ac;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.config=new j({params:this.config_params,onchange:this.config_onchange,saved_values:af.prefs});this.prefs=this.config.get("values");if(!this.prefs.name){this.prefs.name=af.name}if(this.config_onchange){this.config.on("change:values",this.config_onchange,this)}this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").addClass("track-icons").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.prefs.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.prefs.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.prefs.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"gear",on_click_fn:function(ad){var ac=new a({model:ad.config});ac.render()}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".tooltip").remove();ac.remove()}}];q(r.prototype,{config_params:[{key:"name",label:"Name",type:"text",default_value:""},{key:"content_visible",type:"bool",default_value:true,hidden:true}],config_onchange:function(){this.track.set_name(this.track.config.get("values").name)},init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.prefs.content_visible){return true}return false},request_draw:function(){},_draw:function(ac){},to_dict:function(){},set_name:function(ac){this.old_name=this.prefs.name;this.prefs.name=ac;this.name_div.text(this.prefs.name)},revert_name:function(){if(this.old_name){this.prefs.name=this.old_name;this.name_div.text(this.prefs.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var A=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(A.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(ac){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad]._draw(ac)}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(af){var ac=this.drawables.slice(0),ad=[],ae;while(ac.length!==0){ae=ac.shift();if(ae instanceof af){ad.push(ae)}else{if(ae.drawables){ac=ac.concat(ae.drawables)}}}return ad}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});A.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,A.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw({clear_tile_cache:true})}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.prefs.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof d){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ad=new f(this.view,this.view,{name:this.prefs.name,drawables:this.drawables});var ac=this.container.replace_drawable(this,ad,true);ad.request_draw()},add_drawable:function(ac){A.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){A.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(A.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac){ab.each(this.drawables,function(ad){ad.request_draw(ac)})}});var Y=Backbone.View.extend({initialize:function(ac){q(ac,{obj_type:"View"});A.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new y.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new j({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"}],saved_values:ac.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){y.select_datasets(galaxy_config.root+"visualization/list_current_history_datasets",galaxy_config.root+"api/datasets",{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).addClass("chrom-nav").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_tracks(d),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div/>").addClass("zoom-area").css("height",ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ac){return this.config.get("values")[ac.toLowerCase()+"_color"]||this.config.get("values").n_color}});q(Y.prototype,A.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=x;var ac=this,ad=$.Deferred();$.ajax({url:galaxy_config.root+"api/genomes/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){var ah=new D(ac);ac.add_label_track(ah);ac.reference_track=ah}ac.chrom_data=ag.chrom_info;var ak='<option value="">Select Chrom/Contig</option>';for(var aj=0,af=ac.chrom_data.length;aj<af;aj++){var ai=ac.chrom_data[aj].chrom;ak+='<option value="'+ai+'">'+ai+"</option>"}if(ag.prev_chroms){ak+='<option value="previous">Previous '+x+"</option>"}if(ag.next_chroms){ak+='<option value="next">Next '+x+"</option>"}ac.chrom_select.html(ak);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey: "+ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-x});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+x});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad&&aj){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/,/g,"");ag=ag.replace(/:|\-/g," ");var ad=ag.split(/\s+/),af=ad[0],ae=(ad[1]?parseInt(ad[1],10):null),ac=(ad[2]?parseInt(ad[2],10):null);if(!ac){ae=ae-15;ac=ae+15}this.change_chrom(af,ae,ac)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ac.request_redraw()},200);var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){A.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){A.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ad,ae){var ac=this,af=(ae?[ae]:ac.drawables);ab.each(af,function(ag){var ah=ab.find(ac.tracks_to_be_redrawn,function(ai){return ai[0]===ag});if(ah){ah[1]=ad}else{ac.tracks_to_be_redrawn.push([ag,ad])}});if(!this.requested_redraw){requestAnimationFrame(function(){ac._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ac=this.low,ag=this.high;if(ac<this.max_low){ac=this.max_low}if(ag>this.max_high){ag=this.max_high}var ad=this.high-this.low;if(this.high!==0&&ad<this.min_separation){ag=ac+this.min_separation}this.low=Math.floor(ac);this.high=Math.ceil(ag);this.update_location(this.low,this.high);this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var af=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ah=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:af,width:Math.max(ae,ah)}).show();if(ah<ae){this.overview_box.css("left",af-(ae-ah)/2)}if(this.overview_highlight){this.overview_highlight.css({left:af,width:ah})}ab.each(this.tracks_to_be_redrawn,function(ak){var ai=ak[0],aj=ak[1];if(ai){ai._draw(aj)}});this.tracks_to_be_redrawn=[];ab.each(this.label_tracks,function(ai){ai._draw()})},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset.id===ae.dataset.id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=R.Tool.extend({defaults:{track:null},initialize:function(ac){R.Tool.prototype.initialize.call(this,ac);var ad=true;if(ac.tool_state!==undefined&&ac.tool_state.hidden!==undefined){ad=ac.tool_state.hidden}this.set("hidden",ad);this.remove_inputs(["data","hidden_data","conditional"])},state_dict:function(ac){return ab.extend(this.get_inputs_dict(),{hidden:!this.is_visible()})}});var v=Backbone.View.extend({events:{"change input":"update_value"},render:function(){var ae=this.$el.addClass("param-row"),af=this.model;var ac=$("<div>").addClass("param-label").text(af.get("label")).appendTo(ae);var ad=$("<div/>").addClass("param-input").html(af.get("html")).appendTo(ae);ad.find(":input").val(af.get("value"));$("<div style='clear: both;'/>").appendTo(ae)},update_value:function(ac){this.model.set_value($(ac.target).val())}});var aa=Backbone.View.extend({initialize:function(ac){this.model.on("change:hidden",this.set_visible,this)},render:function(){var ad=this;tool=this.model,parent_div=this.$el.addClass("dynamic-tool").hide();parent_div.bind("drag",function(ah){ah.stopPropagation()}).click(function(ah){ah.stopPropagation()}).bind("dblclick",function(ah){ah.stopPropagation()}).keydown(function(ah){ah.stopPropagation()});var ae=$("<div class='tool-name'>").appendTo(parent_div).text(tool.get("name"));tool.get("inputs").each(function(ai){var ah=new v({model:ai});ah.render();parent_div.append(ah.$el)});parent_div.find("input").click(function(){$(this).select()});var af=$("<div>").addClass("param-row").appendTo(parent_div);var ag=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(af);var ac=$("<input type='submit'>").attr("value","Run on visible region").appendTo(af);ac.click(function(){ad.run_on_region()});ag.click(function(){ad.run_on_dataset()});if(tool.is_visible()){this.$el.show()}},set_visible:function(){if(this.model.is_visible()){this.$el.show()}else{this.$el.hide()}},update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},run_on_dataset:function(){var ac=this.model;this.run({target_dataset_id:this.model.get("track").dataset.id,action:"rerun",tool_id:ac.id},null,function(ad){Galaxy.modal.show({title:ac.get("name")+" is Running",body:ac.get("name")+" is running on the complete dataset. Tool outputs are in dataset's history.",buttons:{Close:function(){Galaxy.modal.hide()}}})})},run_on_region:function(){var ad=this.model.get("track"),ag=this.model,ai=new y.GenomeRegion({chrom:ad.view.chrom,start:ad.view.low,end:ad.view.high}),aj={target_dataset_id:ad.dataset.id,action:"rerun",tool_id:ag.id,regions:[ai.toJSON()]},ah=ad,al=ag.get("name")+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ak=new P(view,view,{name:ad.prefs.name});var af=ah.container.replace_drawable(ah,ak,false);ak.container_div.insertBefore(ah.view.content_div.children()[af]);ak.add_drawable(ah);ah.container_div.appendTo(ak.content_div);ac=ak}else{ac=ah.container}var ae=new ah.constructor(view,ac,{name:al,hda_ldda:"hda"});ae.init_for_tool_data();ae.change_mode(ah.mode);ae.set_filters_manager(ah.filters_manager.copy(ae));ae.update_icons();ac.add_drawable(ae);ae.tiles_div.text("Starting job.");this.run(aj,ae,function(am){ae.set_dataset(new X.Dataset(am));ae.tiles_div.text("Running job.");ae.init()})},run:function(ac,ae,af){ac.inputs=this.model.get_inputs_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_config.root+"api/tools",data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(z+ag.message)}else{af(ag)}}})}});var E=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};E.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var j=Backbone.Model.extend({initialize:function(ad){var ac={};ab.each(ad.params,function(ae){ac[ae.key]=(ae.type==="color"&&!ae.default_value?l.get_random_color():ae.default_value)});if(ad.saved_values){ab.each(this.get("params"),function(ae){if(ae.key in ad.saved_values){ac[ae.key]=ad.saved_values[ae.key]}})}this.set("values",ac)},set_param_default_value:function(ad,ac){var ae=ab.find(this.get("params"),function(af){return af.key===ad});if(ae){ae.default_value=ac}},set_param_value:function(ac,ad){var ae=ab.find(this.get("params"),function(af){return af.key===ac});if(ae){if(typeof ad==="string"||ad instanceof String){if(ad.trim()===""){ad=ae.default_value}else{if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad,10)}}}}}if(this.get("values")[ac]!==ad){this.get("values")[ac]=ad;this.trigger("change:values");return true}else{return false}}});var a=Backbone.View.extend({render:function(){var aj=this.model;var ac=$("<div/>").keydown(function(ak){ak.stopPropagation()});var ai;function ah(ao,ak){for(var at=0;at<ao.length;at++){ai=ao[at];if(ai.hidden){continue}var am="param_"+at;var ax=aj.get("values")[ai.key];var az=$("<div class='form-row' />").appendTo(ak);az.append($("<label />").attr("for",am).text(ai.label+":"));if(ai.type==="bool"){az.append($('<input type="checkbox" />').attr("id",am).attr("name",am).attr("checked",ax))}else{if(ai.type==="text"){az.append($('<input type="text"/>').attr("id",am).val(ax).click(function(){$(this).select()}))}else{if(ai.type==="select"){var av=$("<select />").attr("id",am);for(var aq=0;aq<ai.options.length;aq++){$("<option/>").text(ai.options[aq].label).attr("value",ai.options[aq].value).appendTo(av)}av.val(ax);az.append(av)}else{if(ai.type==="color"){var ay=$("<div/>").appendTo(az),au=$("<input/>").attr({id:am,name:am}).val(ax).addClass("color-input").appendTo(ay).click(function(aB){$(".tooltip").removeClass("in");var aA=$(this).siblings(".tooltip").addClass("in");aA.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top+Galaxy.modal.scrollTop()-($(aA).height()/2)+($(this).height()/2)}).show();aA.click(function(aC){aC.stopPropagation()});$(document).bind("click.color-picker",function(){aA.hide();$(document).unbind("click.color-picker")});aB.stopPropagation()}),ar=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(ay).attr("title","Set new random color").tooltip(),aw=$("<div class='tooltip right' style='position: absolute;' />").appendTo(ay).hide(),an=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(aw),al=$("<div class='tooltip-arrow'></div>").appendTo(aw),ap=$.farbtastic(an,{width:100,height:100,callback:au,color:ax});ay.append($("<div/>").css("clear","both"));(function(aA){ar.click(function(){aA.setColor(l.get_random_color())})})(ap)}else{az.append($("<input />").attr("id",am).attr("name",am).val(ax))}}}}if(ai.help){az.append($("<div class='help'/>").text(ai.help))}}}ah(aj.get("params"),ac);var ad=this,ag=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ae=function(){ad.update_from_form($(Galaxy.modal.el));Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},af=function(ak){if((ak.keyCode||ak.which)===27){ag()}else{if((ak.keyCode||ak.which)===13){ae()}}};$(window).bind("keypress.check_enter_esc",af);Galaxy.modal.show({title:"Configure",body:ac,buttons:{Cancel:ag,Ok:ae}})},update_from_form:function(ac){var ad=this.model;var ae=false;ab.each(ad.get("params"),function(ah,af){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}ae=ad.set_param_value(ah.key,ag)||ae}})}});var c=function(ac,af,ag,ad,ae){this.track=ac;this.region=af;this.low=af.get("start");this.high=af.get("end");this.w_scale=ag;this.canvas=ad;this.html_elt=$("<div class='track-tile'/>").append(ad);this.data=ae;this.stale=false};c.prototype.predisplay_actions=function(){};var M=function(ac,af,ag,ad,ae){c.call(this,ac,af,ag,ad,ae)};M.prototype.predisplay_actions=function(){};var O=function(af,am,ao,ae,ah,ai,ap,ad,al){c.call(this,af,am,ao,ae,ah);this.mode=ai;this.all_slotted=ad;this.feature_mapper=al;this.has_icons=false;if(ap){this.has_icons=true;var aj=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:F,width:ae.width}).prependTo(this.html_elt);var ak=new y.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),an=ah.length,ag=$("<a/>").addClass("icon more-down").attr("title","For speed, only the first "+an+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a/>").addClass("icon more-across").attr("title","For speed, only the first "+an+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ag.click(function(){aj.stale=true;af.data_manager.get_more_data(ak,af.mode,1/aj.w_scale,{},af.data_manager.DEEP_DATA_REQ);$(".tooltip").hide();af.request_draw()}).dblclick(function(aq){aq.stopPropagation()});ac.click(function(){aj.stale=true;af.data_manager.get_more_data(ak,af.mode,1/aj.w_scale,{},af.data_manager.BROAD_DATA_REQ);$(".tooltip").hide();af.request_draw()}).dblclick(function(aq){aq.stopPropagation()})}};q(O.prototype,c.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}af=$("<div/>").attr("id",ak).addClass("feature-popup");var au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?V(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"),10)-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"),10)+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=null;if(ae.dataset){this.dataset=(ae.dataset instanceof Backbone.Model?ae.dataset:new X.Dataset(ae.dataset))}this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new y.GenomeDataManager({dataset:this.dataset,genome:new y.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=this.prefs.height;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"application-dock-270",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"ui-slider-050",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.tool.toggle();if(ac.tool.is_visible()){ac.set_name(ac.prefs.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.get("name") %><br/><strong>Dataset</strong>: <%= track.prefs.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new y.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new y.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}Galaxy.modal.hide();window.location.href=galaxy_config.root+"visualization/sweepster?"+$.param({dataset_id:ac.dataset.id,hda_ldda:ac.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};Galaxy.modal.show({title:"Visualize tool parameter space and output from different parameter settings?",body:ae,buttons:{No:ah,Yes:ad}})}},r.prototype.action_icons_def[2]],can_draw:function(){return this.dataset&&r.prototype.can_draw.call(this)},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id)},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.prefs.name).attr("id",this.prefs.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},set_dataset:function(ac){this.dataset=ac;this.data_manager.set("dataset",ac)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.prefs.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.get("values").height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.get("values").mode?this.config.get("values").mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof W){return"LabelTrack"}else{if(this instanceof D){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Z){return"VariantTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof d){return"FeatureTrack"}}}}}}}return""},show_message:function(ac){this.tiles_div.remove();return $("<span/>").addClass("message").html(ac).appendTo(this.content_div)},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.content_div.children().remove();ad.container_div.removeClass("nodata error pending");ad.tiles_div=$("<div/>").addClass("tiles").appendTo(ad.content_div);if(!ad.dataset.id){return}var ac=$.Deferred(),af={hda_ldda:ad.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");var ah=ad.show_message(o);if(ag.message){ah.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){Galaxy.modal.show({title:"Trackster Error",body:"<pre>"+ag.message+"</pre>",buttons:{Close:function(){Galaxy.modal.hide()}}})}));ah.append($("<span/>").text(" "));ah.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.show_message(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.show_message(G)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.show_message(w);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when.apply($,ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(af&&af.min&&af.max){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.config.set_param_default_value("min_value",ae);ac.config.set_param_default_value("max_value",ag);ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},get_drawables:function(){return this}});var N=function(ae,ad,ag){g.call(this,ae,ad,ag);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in ag?ag.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=(ag.tool?new s(ab.extend(ag.tool,{track:this,tool_state:ag.tool_state})):null);this.tile_cache=new y.Cache(Q);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){var af=new aa({model:this.tool});af.render();this.dynamic_tool_div=af.$el;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);if(!this.prefs.content_visible){this.tiles_div.hide()}this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(ag.mode){this.change_mode(ag.mode)}};q(N.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.get("values").mode=ad;if(ad==="Auto"){this.data_manager.clear()}ac.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ac){if(ac&&ac.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ac,this)},before_draw:function(){this.max_height_px=0},_draw:function(aq){if(!this.can_draw()){return}var an=aq&&aq.clear_after,al=this.view.low,ag=this.view.high,aj=ag-al,ad=this.view.container.width(),ap=this.view.resolution_px_b,af=1/ap;if(this.is_overview){al=this.view.max_low;ag=this.view.max_high;ap=ad/(view.max_high-view.max_low);af=1/ap}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(af*S)),ak,am,ah,ai=[],ao=[];while((ac*S*af)<ag){ak=Math.floor(ac*S*af);am=new y.GenomeRegion({chrom:this.view.chrom,start:ak,end:Math.min(ak+Math.ceil(S*af),this.view.max_high)});ah=this.draw_helper(am,ap,aq);ai.push(ah);$.when(ah).then(function(ar){ao.push(ar)});ac+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var ae=this;$.when.apply($,ai).then(function(){ae.tiles_div.children(".remove").remove();ao=ab.filter(ao,function(ar){return ar!==null});if(ao.length!==0){ae.postdraw_actions(ao,ad,ap,an)}})},_add_yaxis_label:function(af,ah){var ad=this,ag=(af==="max"?"top":"bottom"),ai=(af==="max"?"max":"min"),ac=(af==="max"?"max_value":"min_value"),ae=this.container_div.find(".yaxislabel."+ag);ah=ah||function(){ad.request_draw({clear_tile_cache:true})};if(ae.length!==0){ae.text(ad.prefs[ac])}else{ae=$("<div/>").text(ad.prefs[ac]).make_text_editable({num_cols:12,on_finish:function(aj){$(".tooltip").remove();ad.config.set_param_value(ac,aj);ah()},help_text:"Set "+ai+" value"}).addClass("yaxislabel "+ag).css("color",this.prefs.label_color);this.container_div.prepend(ae)}},postdraw_actions:function(af,ag,ai,ac){var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length>0){this.max_height_px=0;var ad=this;ab.each(af,function(aj){if(!(aj instanceof M)){aj.html_elt.remove();ad.draw_helper(aj.region,ai,{force:true,mode:"Coverage"})}});ad._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ah=ab.find(af,function(aj){return aj.has_icons});if(ah){ab.each(af,function(aj){if(!aj.has_icons){aj.html_elt.css("padding-top",F)}})}}},get_mode:function(ac){return this.mode},update_auto_mode:function(ac){},_get_drawables:function(){return[this]},draw_helper:function(al,an,ao){if(!ao){ao={}}var ad=ao.force,ai=ao.mode||this.mode,af=1/an,ae=this,ag=this._get_drawables(),am=this._gen_tile_cache_key(an,al),ah=function(ap){return(ap&&"track" in ap)};var aj=(ad?undefined:ae.tile_cache.get_elt(am));if(aj){if(ah(aj)){ae.show_tile(aj,an)}return aj}if(ao.data_fetch===false){return null}var ak=function(){var ap=(ab.find(C,function(ar){return ar===ai})?"Coverage":ai);var aq=ab.map(ag,function(ar){return ar.data_manager.get_data(al,ap,af,ae.data_url_extra_params)});if(view.reference_track){aq.push(view.reference_track.data_manager.get_data(al,ai,af,view.reference_track.data_url_extra_params))}return aq};var ac=$.Deferred();ae.tile_cache.set_elt(am,ac);$.when.apply($,ak()).then(function(){var ap=ak(),av=ap,aB;if(view.reference_track){aB=view.reference_track.data_manager.subset_entry(ap.pop(),al)}var aw=[],at=[];ab.each(ag,function(aG,aD){var aF=aG.mode,aE=av[aD];if(aF==="Auto"){aF=aG.get_mode(aE);aG.update_auto_mode(aF)}aw.push(aF);at.push(aG.get_canvas_height(aE,aF,an,aq))});var au=ae.view.canvas_manager.new_canvas(),ax=al.get("start"),aC=al.get("end"),ar=0,aq=Math.ceil((aC-ax)*an)+ae.left_offset,az=ab.max(at),ay;au.width=aq;au.height=(ao.height||az);var aA=au.getContext("2d");aA.translate(ae.left_offset,0);if(ag.length>1){aA.globalAlpha=0.5;aA.globalCompositeOperation="source-over"}ab.each(ag,function(aE,aD){ay=aE.draw_tile(av[aD],aA,aw[aD],al,an,aB)});if(ay!==undefined){ae.tile_cache.set_elt(am,ay);ae.show_tile(ay,an)}ac.resolve(ay)});return ac},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},_draw_line_track_tile:function(ac,ae,ah,ag,ai){var af=ae.canvas,ad=new L.LinePainter(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah);ad.draw(ae,af.width,af.height,ai);return new M(this,ag,ai,af,ac.data)},draw_tile:function(ac,ad,ag,af,ah,ae){},show_tile:function(ae,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){ag-=this.left_offset}ac.css("left",ag);if(ac.hasClass("remove")){ac.removeClass("remove")}else{this.tiles_div.append(ac)}ac.css("height","auto");this.max_height_px=Math.max(this.max_height_px,ac.height()-2);ac.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},tool_region_and_parameters_str:function(af){var ac=this,ae=(af!==undefined?af.toString():"all"),ad=ab.values(ac.tool.get_inputs_dict()).join(", ");return" - region=["+ae+"], parameters=["+ad+"]"},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="bigwig"}else{if(ac.dataset_type==="bigwig"||ac.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ac){if(ac.message||ac.extra_info==="no_detail"){return false}else{if(ac.dataset_type==="bigwig"){return(ac.data[1][0]-ac.data[0][0]===1)}}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state"}});var W=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(W.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ag){var ae=this.view,af=ae.high-ae.low,aj=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/aj)*aj,ah=this.view.container.width(),ad=$("<div/>").addClass("label-container");while(ac<ae.high){var ai=(ac-ae.low)/af*ah;ad.append($("<div/>").addClass("label").text(commatize(ac)).css({left:ai}));ac+=aj}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){N.call(this,ad,ac,ag);this.drawables=[];if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}ab.each(this.drawables,function(ah){if(ah instanceof d||ah instanceof T){ah.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,N.prototype,{display_modes:C,action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".tooltip").remove();ac.show_group()}}].concat(N.prototype.action_icons_def),to_dict:A.prototype.to_dict,add_drawable:A.prototype.add_drawable,unpack_drawables:A.prototype.unpack_drawables,change_mode:function(ac){N.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var af=new P(this.view,this.container,{name:this.prefs.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ad=ab.min(ab.map(this.drawables,function(ae){return ae.prefs.min_value})),ac=ab.max(ab.map(this.drawables,function(ae){return ae.prefs.max_value}));this.prefs.min_value=ad;this.prefs.max_value=ac;ab.each(this.drawables,function(ae){ae.prefs.min_value=ad;ae.prefs.max_value=ac})},update_all_min_max:function(){var ac=this;ab.each(this.drawables,function(ad){ad.prefs.min_value=ac.prefs.min_value;ad.prefs.max_value=ac.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ai,ac,al,ah){N.prototype.postdraw_actions.call(this,ai,ac,al,ah);var ag=-1,ae;for(ae=0;ae<ai.length;ae++){var aj=ai[ae].html_elt.find("canvas").height();if(aj>ag){ag=aj}}for(ae=0;ae<ai.length;ae++){var af=ai[ae];if(af.html_elt.find("canvas").height()!==ag){this.draw_helper(af.region,al,{force:true,height:ag});af.html_elt.remove()}}var ad=this,ak=function(){ad.update_all_min_max()};this._add_yaxis_label("min",ak);this._add_yaxis_label("max",ak)}});var D=function(ac){N.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});this.left_offset=ac.canvas_manager.char_width_px;this.container_div.addClass("reference-track");this.data_url=galaxy_config.root+"api/genomes/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new y.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};q(D.prototype,r.prototype,N.prototype,{config_params:ab.union(r.prototype.config_params,[{key:"height",type:"int",default_value:13,hidden:true}]),build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:r.prototype.can_draw,draw_helper:function(ad,ae,ac){if(ae>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,ad,ae,ac)}else{this.tiles_div.hide();return null}},can_subset:function(ac){return true},draw_tile:function(ae,ak,af,ah,al){var ad=this.data_manager.subset_entry(ae,ah),aj=ad.data;var ac=ak.canvas;ak.font=ak.canvas.manager.default_font;ak.textAlign="center";for(var ag=0,ai=aj.length;ag<ai;ag++){ak.fillStyle=this.view.get_base_color(aj[ag]);ak.fillText(aj[ag],Math.floor(ag*al),10)}return new c(this,ah,al,ac,ad)}});var h=function(ad,ac,ae){this.mode="Histogram";N.call(this,ad,ac,ae)};q(h.prototype,r.prototype,N.prototype,{display_modes:C,config_params:ab.union(r.prototype.config_params,[{key:"color",label:"Color",type:"color"},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:30,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},before_draw:function(){},draw_tile:function(ac,ad,af,ae,ag){return this._draw_line_track_tile(ac,ad,af,ae,ag)},can_subset:function(ac){return(ac.data[1][0]-ac.data[0][0]===1)},postdraw_actions:function(ad,ae,af,ac){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var t=function(ad,ac,ae){this.mode="Heatmap";N.call(this,ad,ac,ae)};q(t.prototype,r.prototype,N.prototype,{display_modes:["Heatmap"],config_params:ab.union(r.prototype.config_params,[{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},draw_tile:function(ac,ae,ah,ag,ai){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah);ad.draw(ae,af.width,af.height,ai);return new c(this,ag,ai,af,ac.data)}});var d=function(ad,ac,ae){N.call(this,ad,ac,ae);this.container_div.addClass("feature-track");this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(d.prototype,r.prototype,N.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:ab.union(r.prototype.config_params,[{key:"block_color",label:"Block color",type:"color"},{key:"reverse_strand_color",label:"Antisense strand color",type:"color"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.set_painter_from_config();this.request_draw({clear_tile_cache:true})},set_painter_from_config:function(){if(this.config.get("values").connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(am,ae,an,al){N.prototype.postdraw_actions.call(this,am,ae,an,al);var ag=this,ah;if(ag.filters_manager){var af=ag.filters_manager.filters,aj;for(aj=0;aj<af.length;aj++){af[aj].update_ui_elt()}var ai=false,ak,ad;for(ah=0;ah<am.length;ah++){if(am[ah].data.length){ak=am[ah].data[0];for(aj=0;aj<af.length;aj++){ad=af[aj];if(ad.applies_to(ak)&&ad.min!==ad.max){ai=true;break}}}}if(ag.filters_available!==ai){ag.filters_available=ai;if(!ag.filters_available){ag.filters_manager.hide()}ag.update_icons()}}if(am[0] instanceof O){var ac=true;for(ah=0;ah<am.length;ah++){if(!am[ah].all_slotted){ac=false;break}}if(!ac){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,B,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="Coverage"||ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(this.min_height_px,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,af,aj,ae){var ap=this,ad=aq.canvas,ax=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(am.dataset_type==="bigwig"){return this._draw_line_track_tile(am,aq,ao,af,aj)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var ar=0,au=am.data.length;ar<au;ar++){var ah=am.data[ar];var at=false;var al;for(var aw=0,aB=ak.length;aw<aB;aw++){al=ak[aw];al.update_attrs(ah);if(!al.keep(ah)){at=true;break}}if(!at){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aA=(this.filters_manager.alpha_filter?new E(this.filters_manager.alpha_filter):null),ay=(this.filters_manager.height_filter?new E(this.filters_manager.height_filter):null),az=new (this.painter)(ai,ax,ac,this.prefs,ao,aA,ay,ae,function(aC){return ap.view.get_base_color(aC)});var av=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){av=az.draw(aq,ad.width,ad.height,aj,an);av.translation=-ag}return new O(ap,af,aj,ad,am.data,ao,am.message,all_slotted,av)}});var Z=function(ad,ac,ae){N.call(this,ad,ac,ae);this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};q(Z.prototype,r.prototype,N.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:ab.union(r.prototype.config_params,[{key:"color",label:"Histogram color",type:"color"},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},draw_tile:function(ac,af,ah,ag,ai){if(ac.dataset_type==="bigwig"){return this._draw_line_track_tile(ac,af,"Histogram",ag,ai)}else{var ae=this.view,ad=new (this.painter)(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah,function(aj){return ae.get_base_color(aj)});ad.draw(af,af.canvas.width,af.canvas.height,ai);return new c(this,ag,ai,af.canvas,ac.data)}},get_canvas_height:function(ac,ag,ah,ae){if(ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var ad=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ad===0&&ac.data.length!==0){ad=ac.data[0][7].match(/,/g);if(ad===null){ad=1}else{ad=ad.length+1}}var af=new (this.painter)(null,null,null,this.prefs,ag);return af.get_required_height(ad)}},predraw_init:function(){var ac=[g.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ac.push(this.dataset.fetch())}return ac},postdraw_actions:function(ag,ah,aj,ad){N.prototype.postdraw_actions.call(this,ag,ah,aj,ad);var af=ab.filter(ag,function(ak){return(ak instanceof M)});var ae=this.dataset.get_metadata("sample_names");if(af.length===0&&this.prefs.show_labels&&ae&&ae.length>1){var ac;if(this.container_div.find(".yaxislabel.variant").length===0){ac=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ac+"px",top:(this.prefs.summary_height-ac)/2+"px"}));if(this.prefs.show_sample_data){var ai=ae.join("<br/>");this.tiles_div.prepend($("<div/>").html(ai).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height,}))}}ac=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ac,"line-height":ac});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(ad,ac,ae){d.call(this,ad,ac,ae);this.painter=(ad.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};q(T.prototype,r.prototype,N.prototype,d.prototype,{config_params:ab.union(r.prototype.config_params,[{key:"block_color",label:"Block and sense strand color",type:"color"},{key:"reverse_strand_color",label:"Antisense strand color",type:"color"},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})}});var e={CompositeTrack:f,DrawableGroup:P,DiagonalHeatmapTrack:t,FeatureTrack:d,LineTrack:h,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new e[af](ad,ac,ae)}};return{TracksterView:Y,DrawableGroup:P,LineTrack:h,FeatureTrack:d,DiagonalHeatmapTrack:t,ReadTrack:T,VariantTrack:Z,CompositeTrack:f,object_from_template:p}});
\ No newline at end of file
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/templates/compiled/history-templates.js
--- a/static/scripts/templates/compiled/history-templates.js
+++ b/static/scripts/templates/compiled/history-templates.js
@@ -507,7 +507,7 @@
buffer += "\n </div>\n\n <div class=\"history-subtitle clear\">\n ";
stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n\n <div class=\"history-secondary-actions\">\n </div>\n </div>\n\n ";
+ buffer += "\n\n <div class=\"history-secondary-actions\"></div>\n </div>\n\n ";
stack1 = helpers['if'].call(depth0, depth0.deleted, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n <div class=\"message-container\">\n ";
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/templates/compiled/template-history-historyPanel.js
--- a/static/scripts/templates/compiled/template-history-historyPanel.js
+++ b/static/scripts/templates/compiled/template-history-historyPanel.js
@@ -96,7 +96,7 @@
buffer += "\n </div>\n\n <div class=\"history-subtitle clear\">\n ";
stack1 = helpers['if'].call(depth0, depth0.nice_size, {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n\n <div class=\"history-secondary-actions\">\n </div>\n </div>\n\n ";
+ buffer += "\n\n <div class=\"history-secondary-actions\"></div>\n </div>\n\n ";
stack1 = helpers['if'].call(depth0, depth0.deleted, {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
if(stack1 || stack1 === 0) { buffer += stack1; }
buffer += "\n\n <div class=\"message-container\">\n ";
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/scripts/templates/history-templates.html
--- a/static/scripts/templates/history-templates.html
+++ b/static/scripts/templates/history-templates.html
@@ -16,8 +16,7 @@
<div class="history-size">{{nice_size}}</div>
{{/if}}
- <div class="history-secondary-actions">
- </div>
+ <div class="history-secondary-actions"></div></div>
{{#if deleted}}
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1507,9 +1507,10 @@
.icon-button.link{background:url(../images/silk/link.png) no-repeat;cursor:pointer;float:none;display:inline-block;margin-left:10px}
.icon-button.link-broken{background:url(../images/silk/link_break.png) no-repeat;cursor:pointer;float:none;display:inline-block;margin-left:10px}
.workflow-invocation-complete{border:solid 1px #6A6;border-left-width:5px;margin:10px 0;padding-left:5px}
-.icon-btn{display:inline-block;height:20px;width:20px;text-align:center;line-height:17px;border-radius:3px;border:1px solid rgba(0,0,0,0.1);background-color:rgba(0,0,0,0.05);color:#555;font-size:1.2em;cursor:pointer}
+.icon-btn{display:inline-block;height:20px;width:20px;text-align:center;line-height:17px;font-size:1.2em;border-radius:3px;border:1px solid rgba(0,0,0,0.1);background-color:rgba(0,0,0,0.05);color:#555;cursor:pointer}
.icon-btn:hover{background-color:white;color:maroon}
.icon-btn.disabled{background-color:transparent;color:rgba(0,0,0,0.05)}
+#history-refresh-button,#history-options-button{display:inline-block;height:20px;width:20px;text-align:center;line-height:17px;font-size:1.2em;padding:0px}
.history-panel [class$="messagesmall"]{margin:0px}
.history-panel .editable-text{border:solid transparent 1px}
.history-panel .editable-text:hover{cursor:pointer;border:1px dotted #999999}
diff -r f166886d97a0e7dcb926c2e5f83db8f52982748f -r a6044ab1ffe717adc08eb6e43eb1febdc8a265f3 static/style/src/less/history.less
--- a/static/style/src/less/history.less
+++ b/static/style/src/less/history.less
@@ -34,13 +34,14 @@
// center the icon
text-align: center;
line-height: @icon-btn-size - 3;
+ font-size: 1.2em;
+
// colors and borders
border-radius: 3px;
border: 1px solid @icon-btn-border;
background-color: @icon-btn-bg;
color : @icon-btn-color;
- font-size: 1.2em;
cursor: pointer;
// tweaks
@@ -59,6 +60,19 @@
color: @icon-btn-bg;
}
+// ---------------------------------------------------------------------------- panel header buttons
+#history-refresh-button,
+#history-options-button {
+ display : inline-block;
+ height : @icon-btn-size;
+ width : @icon-btn-size;
+ text-align : center;
+ line-height : @icon-btn-size - 3;
+ font-size : 1.2em;
+
+ padding: 0px;
+}
+
// ---------------------------------------------------------------------------- history
.history-panel {
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Another attempt to fix nosetests' handling of rods.py.
by commits-noreply@bitbucket.org 03 Dec '13
by commits-noreply@bitbucket.org 03 Dec '13
03 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/f166886d97a0/
Changeset: f166886d97a0
User: jmchilton
Date: 2013-12-03 19:59:35
Summary: Another attempt to fix nosetests' handling of rods.py.
Further dirtying @dannon's code :(, sorry.
Affected #: 1 file
diff -r 1d75d75f9f82b9f9e7c19ef7d9d5df5e1565c962 -r f166886d97a0e7dcb926c2e5f83db8f52982748f lib/galaxy/objectstore/rods.py
--- a/lib/galaxy/objectstore/rods.py
+++ b/lib/galaxy/objectstore/rods.py
@@ -18,6 +18,9 @@
try:
import galaxy.eggs
galaxy.eggs.require( 'PyRods' )
+except Exception:
+ pass
+try:
import irods
except ImportError:
irods = None
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Remove unused get_missing_tool_dependencies in install_and_test_tool_shed_repositories/base/test_db_util.py.
by commits-noreply@bitbucket.org 03 Dec '13
by commits-noreply@bitbucket.org 03 Dec '13
03 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1d75d75f9f82/
Changeset: 1d75d75f9f82
User: jmchilton
Date: 2013-12-03 18:54:56
Summary: Remove unused get_missing_tool_dependencies in install_and_test_tool_shed_repositories/base/test_db_util.py.
Looks to have been replaced by method with same name in install_and_test_tool_shed_repositories/functional_tests.py and would throw a NameError on repository_id if ever used.
Affected #: 1 file
diff -r 34d18fc63a7c9232dc23184094fef3f022e12036 -r 1d75d75f9f82b9f9e7c19ef7d9d5df5e1565c962 test/install_and_test_tool_shed_repositories/base/test_db_util.py
--- a/test/install_and_test_tool_shed_repositories/base/test_db_util.py
+++ b/test/install_and_test_tool_shed_repositories/base/test_db_util.py
@@ -30,11 +30,6 @@
model.ToolShedRepository.table.c.installed_changeset_revision == changeset_revision ) ) \
.one()
-def get_missing_tool_dependencies( repository ):
- return sa_session.query( model.ToolDependency ) \
- .filter( and_( model.ToolDependency.table.c.tool_shed_repository_id == repository_id,
- model.ToolDependency.table.c.status != model.ToolDependency.installation_status.INSTALLED ) ) \
- .all()
def get_private_role( user ):
for role in user.all_roles():
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5dbfdeb3295f/
Changeset: 5dbfdeb3295f
User: jmchilton
Date: 2013-12-02 22:15:16
Summary: Delay problems with fluent logger dependencies until fluent logger used.
Affected #: 1 file
diff -r ef33472f0aa296e55fd811357e09366f9cee5467 -r 5dbfdeb3295f23eea643f74c100d3549c6ddafb7 lib/galaxy/util/log/fluent_log.py
--- a/lib/galaxy/util/log/fluent_log.py
+++ b/lib/galaxy/util/log/fluent_log.py
@@ -5,15 +5,23 @@
import time
import threading
-import galaxy.eggs
-galaxy.eggs.require( "fluent-logger" )
-galaxy.eggs.require( "msgpack_python" )
+try:
+ import galaxy.eggs
+ galaxy.eggs.require( "fluent-logger" )
+ galaxy.eggs.require( "msgpack_python" )
+except Exception:
+ pass
-from fluent.sender import FluentSender
+try:
+ from fluent.sender import FluentSender
+except ImportError:
+ FluentSender = None
class FluentTraceLogger( object ):
def __init__( self, name, host='localhost', port=24224 ):
+ if FluentSender is None:
+ raise Exception("Attempted to use FluentTraceLogger with not Fluent dependency available.")
self.lock = threading.Lock()
self.thread_local = threading.local()
self.name = name
@@ -36,4 +44,4 @@
if hasattr( self.thread_local, 'context' ):
kwargs.update( self.thread_local.context )
self.lock.release()
- self.sender.emit_with_time( label, int(time.time()), kwargs )
\ No newline at end of file
+ self.sender.emit_with_time( label, int(time.time()), kwargs )
https://bitbucket.org/galaxy/galaxy-central/commits/34d18fc63a7c/
Changeset: 34d18fc63a7c
User: jmchilton
Date: 2013-12-03 17:39:21
Summary: Merged in jmchilton/galaxy-central-fork-1 (pull request #270)
Delay potential problems with fluent logger dependencies until fluent logger used.
Affected #: 1 file
diff -r 5667c340ef5de4254e1c591bf1e20c10a078b2c1 -r 34d18fc63a7c9232dc23184094fef3f022e12036 lib/galaxy/util/log/fluent_log.py
--- a/lib/galaxy/util/log/fluent_log.py
+++ b/lib/galaxy/util/log/fluent_log.py
@@ -5,15 +5,23 @@
import time
import threading
-import galaxy.eggs
-galaxy.eggs.require( "fluent-logger" )
-galaxy.eggs.require( "msgpack_python" )
+try:
+ import galaxy.eggs
+ galaxy.eggs.require( "fluent-logger" )
+ galaxy.eggs.require( "msgpack_python" )
+except Exception:
+ pass
-from fluent.sender import FluentSender
+try:
+ from fluent.sender import FluentSender
+except ImportError:
+ FluentSender = None
class FluentTraceLogger( object ):
def __init__( self, name, host='localhost', port=24224 ):
+ if FluentSender is None:
+ raise Exception("Attempted to use FluentTraceLogger with not Fluent dependency available.")
self.lock = threading.Lock()
self.thread_local = threading.local()
self.name = name
@@ -36,4 +44,4 @@
if hasattr( self.thread_local, 'context' ):
kwargs.update( self.thread_local.context )
self.lock.release()
- self.sender.emit_with_time( label, int(time.time()), kwargs )
\ No newline at end of file
+ self.sender.emit_with_time( label, int(time.time()), kwargs )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Code cleanup for rendering the tool test results container in the tool shed.
by commits-noreply@bitbucket.org 03 Dec '13
by commits-noreply@bitbucket.org 03 Dec '13
03 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5667c340ef5d/
Changeset: 5667c340ef5d
User: greg
Date: 2013-12-03 17:32:00
Summary: Code cleanup for rendering the tool test results container in the tool shed.
Affected #: 1 file
diff -r a540510a3091ad7cfe3c4680c8bb04a20679e44f -r 5667c340ef5de4254e1c591bf1e20c10a078b2c1 lib/tool_shed/util/container_util.py
--- a/lib/tool_shed/util/container_util.py
+++ b/lib/tool_shed/util/container_util.py
@@ -1052,7 +1052,6 @@
"""Return a folder hierarchy containing tool dependencies."""
# This container is displayed only in the tool shed.
if tool_test_results_dicts:
- test_results_dict_id = 0
folder_id += 1
tool_test_results_root_folder = Folder( id=folder_id, key='root', label='root', parent=None )
multiple_tool_test_results_dicts = len( tool_test_results_dicts ) > 1
@@ -1061,9 +1060,29 @@
test_runs_folder = Folder( id=folder_id, key='test_runs', label='Test runs', parent=tool_test_results_root_folder )
tool_test_results_root_folder.folders.append( test_runs_folder )
for index, tool_test_results_dict in enumerate( tool_test_results_dicts ):
+ if len( tool_test_results_dict ) < 2:
+ # Skip tool test results that have only a 'test_environment' entry since this implies that only the preparation
+ # script check_repositories_for_functional_tests.py has run for that entry.
+ continue
+ # We have a dictionary that looks something like this:
+ # {'missing_test_components': [],
+ # 'failed_tests': [],
+ # 'passed_tests':
+ # [{'tool_id': 'effectiveT3',
+ # 'test_id': 'test_tool_000000 (functional.test_toolbox.TestForTool_testtoolshed.g2.bx.psu.edu/repos/...)',
+ # 'tool_version': '0.0.12'},
+ # {'tool_id': 'effectiveT3',
+ # 'test_id': 'test_tool_000001 (functional.test_toolbox.TestForTool_testtoolshed.g2.bx.psu.edu/repos/...)',
+ # 'tool_version': '0.0.12'}],
+ # 'test_environment':
+ # {'python_version': '2.7.4', 'tool_shed_mercurial_version': '2.2.3', 'system': 'Linux 3.8.0-30-generic',
+ # 'tool_shed_database_version': 21, 'architecture': 'x86_64', 'galaxy_revision': '11573:a62c54ddbe2a',
+ # 'galaxy_database_version': 117, 'time_tested': '2013-12-03 09:11:48', 'tool_shed_revision': '11556:228156daa575'},
+ # 'installation_errors':
+ # {'current_repository': [], 'repository_dependencies': [], 'tool_dependencies': []}},
test_environment_dict = tool_test_results_dict.get( 'test_environment', None )
if test_environment_dict is None:
- # the test environment entry will exist only if the preparation script check_re;ositories_for_functional_tests.py
+ # The test environment entry will exist only if the preparation script check_repositories_for_functional_tests.py
# was executed prior to the ~/install_and_test_repositories/functional_tests.py script. If that did not occur,
# we'll display test result, but the test_environment entries will not be complete.
test_environment_dict = {}
@@ -1074,10 +1093,9 @@
test_runs_folder.folders.append( containing_folder )
else:
containing_folder = tool_test_results_root_folder
- test_results_dict_id += 1
folder_id += 1
- folder = Folder( id=folder_id, key='test_environment', label='Automated test environment', parent=containing_folder )
- containing_folder.folders.append( folder )
+ test_environment_folder = Folder( id=folder_id, key='test_environment', label='Automated test environment', parent=containing_folder )
+ containing_folder.folders.append( test_environment_folder )
architecture = test_environment_dict.get( 'architecture', '' )
galaxy_database_version = test_environment_dict.get( 'galaxy_database_version', '' )
galaxy_revision = test_environment_dict.get( 'galaxy_revision', '' )
@@ -1096,21 +1114,21 @@
tool_shed_database_version=tool_shed_database_version,
tool_shed_mercurial_version=tool_shed_mercurial_version,
tool_shed_revision=tool_shed_revision )
- folder.test_environments.append( test_environment )
+ test_environment_folder.test_environments.append( test_environment )
not_tested_dict = tool_test_results_dict.get( 'not_tested', {} )
if not_tested_dict:
folder_id += 1
- folder = Folder( id=folder_id, key='not_tested', label='Not tested', parent=containing_folder )
- containing_folder.folders.append( folder )
+ not_tested_folder = Folder( id=folder_id, key='not_tested', label='Not tested', parent=containing_folder )
+ containing_folder.folders.append( not_tested_folder )
not_tested_id = 0
not_tested = NotTested( id=not_tested_id,
reason=not_tested_dict.get( 'reason', '' ) )
- folder.not_tested.append( not_tested )
+ not_tested_folder.not_tested.append( not_tested )
passed_tests_dicts = tool_test_results_dict.get( 'passed_tests', [] )
if passed_tests_dicts:
folder_id += 1
- folder = Folder( id=folder_id, key='passed_tests', label='Tests that passed successfully', parent=containing_folder )
- containing_folder.folders.append( folder )
+ passed_tests_folder = Folder( id=folder_id, key='passed_tests', label='Tests that passed successfully', parent=containing_folder )
+ containing_folder.folders.append( passed_tests_folder )
passed_test_id = 0
for passed_tests_dict in passed_tests_dicts:
passed_test_id += 1
@@ -1118,12 +1136,12 @@
test_id=passed_tests_dict.get( 'test_id' '' ),
tool_id=passed_tests_dict.get( 'tool_id', '' ),
tool_version=passed_tests_dict.get( 'tool_version', '' ) )
- folder.passed_tests.append( passed_test )
+ passed_tests_folder.passed_tests.append( passed_test )
failed_tests_dicts = tool_test_results_dict.get( 'failed_tests', [] )
if failed_tests_dicts:
folder_id += 1
- folder = Folder( id=folder_id, key='failed_tests', label='Tests that failed', parent=containing_folder )
- containing_folder.folders.append( folder )
+ failed_tests_folder = Folder( id=folder_id, key='failed_tests', label='Tests that failed', parent=containing_folder )
+ containing_folder.folders.append( failed_tests_folder )
failed_test_id = 0
for failed_tests_dict in failed_tests_dicts:
# TODO: Remove this when invalid test data is eliminated.
@@ -1136,12 +1154,15 @@
tool_id=failed_tests_dict.get( 'tool_id', '' ),
tool_version=failed_tests_dict.get( 'tool_version', '' ),
traceback=failed_tests_dict.get( 'traceback', '' ) )
- folder.failed_tests.append( failed_test )
+ failed_tests_folder.failed_tests.append( failed_test )
missing_test_components_dicts = tool_test_results_dict.get( 'missing_test_components', [] )
if missing_test_components_dicts:
folder_id += 1
- folder = Folder( id=folder_id, key='missing_test_components', label='Tools missing tests or test data', parent=containing_folder )
- containing_folder.folders.append( folder )
+ missing_test_components_folder = Folder( id=folder_id,
+ key='missing_test_components',
+ label='Tools missing tests or test data',
+ parent=containing_folder )
+ containing_folder.folders.append( missing_test_components_folder )
missing_test_component_id = 0
for missing_test_components_dict in missing_test_components_dicts:
missing_test_component_id += 1
@@ -1150,7 +1171,7 @@
tool_guid=missing_test_components_dict.get( 'tool_guid', '' ),
tool_id=missing_test_components_dict.get( 'tool_id', '' ),
tool_version=missing_test_components_dict.get( 'tool_version', '' ) )
- folder.missing_test_components.append( missing_test_component )
+ missing_test_components_folder.missing_test_components.append( missing_test_component )
installation_error_dicts = tool_test_results_dict.get( 'installation_errors', {} )
if installation_error_dicts:
current_repository_errors = installation_error_dicts.get( 'current_repository', [] )
@@ -1165,54 +1186,57 @@
containing_folder.installation_errors.append( installation_error_base_folder )
if current_repository_errors:
folder_id += 1
- subfolder = Folder( id=folder_id,
- key='current_repository_errors',
- label='This repository',
- parent=installation_error_base_folder )
+ current_repository_folder = Folder( id=folder_id,
+ key='current_repository_errors',
+ label='This repository',
+ parent=installation_error_base_folder )
repository_error_id = 0
for repository_error_dict in current_repository_errors:
repository_error_id += 1
- repository_installation_error = RepositoryInstallationError( id=repository_error_id,
- tool_shed=repository_error_dict.get( 'tool_shed', '' ),
- name=repository_error_dict.get( 'name', '' ),
- owner=repository_error_dict.get( 'owner', '' ),
- changeset_revision=repository_error_dict.get( 'changeset_revision', '' ),
- error_message=repository_error_dict.get( 'error_message', '' ) )
- subfolder.current_repository_installation_errors.append( repository_installation_error )
- installation_error_base_folder.folders.append( subfolder )
+ repository_installation_error = \
+ RepositoryInstallationError( id=repository_error_id,
+ tool_shed=repository_error_dict.get( 'tool_shed', '' ),
+ name=repository_error_dict.get( 'name', '' ),
+ owner=repository_error_dict.get( 'owner', '' ),
+ changeset_revision=repository_error_dict.get( 'changeset_revision', '' ),
+ error_message=repository_error_dict.get( 'error_message', '' ) )
+ current_repository_folder.current_repository_installation_errors.append( repository_installation_error )
+ installation_error_base_folder.folders.append( current_repository_folder )
if repository_dependency_errors:
folder_id += 1
- subfolder = Folder( id=folder_id,
- key='repository_dependency_errors',
- label='Repository dependencies',
- parent=installation_error_base_folder )
+ repository_dependencies_folder = Folder( id=folder_id,
+ key='repository_dependency_errors',
+ label='Repository dependencies',
+ parent=installation_error_base_folder )
repository_error_id = 0
for repository_error_dict in repository_dependency_errors:
repository_error_id += 1
- repository_installation_error = RepositoryInstallationError( id=repository_error_id,
- tool_shed=repository_error_dict.get( 'tool_shed', '' ),
- name=repository_error_dict.get( 'name', '' ),
- owner=repository_error_dict.get( 'owner', '' ),
- changeset_revision=repository_error_dict.get( 'changeset_revision', '' ),
- error_message=repository_error_dict.get( 'error_message', '' ) )
- subfolder.repository_installation_errors.append( repository_installation_error )
- installation_error_base_folder.folders.append( subfolder )
+ repository_installation_error = \
+ RepositoryInstallationError( id=repository_error_id,
+ tool_shed=repository_error_dict.get( 'tool_shed', '' ),
+ name=repository_error_dict.get( 'name', '' ),
+ owner=repository_error_dict.get( 'owner', '' ),
+ changeset_revision=repository_error_dict.get( 'changeset_revision', '' ),
+ error_message=repository_error_dict.get( 'error_message', '' ) )
+ repository_dependencies_folder.repository_installation_errors.append( repository_installation_error )
+ installation_error_base_folder.folders.append( repository_dependencies_folder )
if tool_dependency_errors:
folder_id += 1
- subfolder = Folder( id=folder_id,
- key='tool_dependency_errors',
- label='Tool dependencies',
- parent=installation_error_base_folder )
+ tool_dependencies_folder = Folder( id=folder_id,
+ key='tool_dependency_errors',
+ label='Tool dependencies',
+ parent=installation_error_base_folder )
tool_dependency_error_id = 0
for tool_dependency_error_dict in tool_dependency_errors:
tool_dependency_error_id += 1
- tool_dependency_installation_error = ToolDependencyInstallationError( id=tool_dependency_error_id,
- type=tool_dependency_error_dict.get( 'type', '' ),
- name=tool_dependency_error_dict.get( 'name', '' ),
- version=tool_dependency_error_dict.get( 'version', '' ),
- error_message=tool_dependency_error_dict.get( 'error_message', '' ) )
- subfolder.tool_dependency_installation_errors.append( tool_dependency_installation_error )
- installation_error_base_folder.folders.append( subfolder )
+ tool_dependency_installation_error = \
+ ToolDependencyInstallationError( id=tool_dependency_error_id,
+ type=tool_dependency_error_dict.get( 'type', '' ),
+ name=tool_dependency_error_dict.get( 'name', '' ),
+ version=tool_dependency_error_dict.get( 'version', '' ),
+ error_message=tool_dependency_error_dict.get( 'error_message', '' ) )
+ tool_dependencies_folder.tool_dependency_installation_errors.append( tool_dependency_installation_error )
+ installation_error_base_folder.folders.append( tool_dependencies_folder )
else:
tool_test_results_root_folder = None
return folder_id, tool_test_results_root_folder
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
10 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/fe2c12b2eb22/
Changeset: fe2c12b2eb22
User: jmchilton
Date: 2013-12-02 02:07:03
Summary: Refactor directory_hash_id into its own module.
Also add PEP-8 cleanup and unit tests. This eliminates explicit dependency between galaxy.objectstore and galaxy.model - with the ultimate goal of being able to utilize all object store functionality except dataset creation from a remote LWR instance without a database connection.
Affected #: 4 files
diff -r 752929cea6d37423c14f46f317ef3815cfc3c3d0 -r fe2c12b2eb22a5cab876629593e91079e27f2492 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -29,6 +29,7 @@
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.util.directory_hash import directory_hash_id
from galaxy.web.framework.helpers import to_unicode
from galaxy.web.form_builder import (AddressField, CheckboxField, HistoryField,
PasswordField, SelectField, TextArea, TextField, WorkflowField,
@@ -4029,18 +4030,3 @@
self.repository_id = repository_id
self.repository_path = repository_path
self.version = version
-
-## ---- Utility methods -------------------------------------------------------
-
-def directory_hash_id( id ):
- s = str( id )
- l = len( s )
- # Shortcut -- ids 0-999 go under ../000/
- if l < 4:
- return [ "000" ]
- # Pad with zeros until a multiple of three
- padded = ( ( 3 - len( s ) % 3 ) * "0" ) + s
- # Drop the last three digits -- 1000 files per directory
- padded = padded[:-3]
- # Break into chunks of three
- return [ padded[i*3:(i+1)*3] for i in range( len( padded ) // 3 ) ]
diff -r 752929cea6d37423c14f46f317ef3815cfc3c3d0 -r fe2c12b2eb22a5cab876629593e91079e27f2492 lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -13,7 +13,7 @@
from galaxy import util
from galaxy.exceptions import ObjectInvalid, ObjectNotFound
from galaxy.jobs import Sleeper
-from galaxy.model import directory_hash_id
+from galaxy.util.directory_hash import directory_hash_id
from galaxy.util.odict import odict
from sqlalchemy.orm import object_session
diff -r 752929cea6d37423c14f46f317ef3815cfc3c3d0 -r fe2c12b2eb22a5cab876629593e91079e27f2492 lib/galaxy/objectstore/s3.py
--- a/lib/galaxy/objectstore/s3.py
+++ b/lib/galaxy/objectstore/s3.py
@@ -12,7 +12,7 @@
from galaxy import util
from galaxy.jobs import Sleeper
-from galaxy.model import directory_hash_id
+from galaxy.util.directory_hash import directory_hash_id
from galaxy.objectstore import ObjectStore, convert_bytes
from galaxy.exceptions import ObjectNotFound
diff -r 752929cea6d37423c14f46f317ef3815cfc3c3d0 -r fe2c12b2eb22a5cab876629593e91079e27f2492 lib/galaxy/util/directory_hash.py
--- /dev/null
+++ b/lib/galaxy/util/directory_hash.py
@@ -0,0 +1,23 @@
+
+
+def directory_hash_id( id ):
+ """
+
+ >>> directory_hash_id( 100 )
+ ['000']
+ >>> directory_hash_id( "90000" )
+ ['090']
+ >>> directory_hash_id("777777777")
+ ['000', '777', '777']
+ """
+ s = str( id )
+ l = len( s )
+ # Shortcut -- ids 0-999 go under ../000/
+ if l < 4:
+ return [ "000" ]
+ # Pad with zeros until a multiple of three
+ padded = ( ( 3 - len( s ) % 3 ) * "0" ) + s
+ # Drop the last three digits -- 1000 files per directory
+ padded = padded[:-3]
+ # Break into chunks of three
+ return [ padded[ i * 3 : (i + 1 ) * 3 ] for i in range( len( padded ) // 3 ) ]
https://bitbucket.org/galaxy/galaxy-central/commits/433d5f4f5c66/
Changeset: 433d5f4f5c66
User: jmchilton
Date: 2013-12-02 02:07:04
Summary: PEP-8 fixes for object store module.
Affected #: 3 files
diff -r fe2c12b2eb22a5cab876629593e91079e27f2492 -r 433d5f4f5c66c17701d84b08185ca2b733664d6b lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -358,7 +358,7 @@
def get_store_usage_percent(self):
st = os.statvfs(self.file_path)
- return (float(st.f_blocks - st.f_bavail)/st.f_blocks) * 100
+ return ( float( st.f_blocks - st.f_bavail ) / st.f_blocks ) * 100
class CachingObjectStore(ObjectStore):
@@ -428,7 +428,7 @@
return store.__getattribute__(method)(obj, **kwargs)
if default_is_exception:
raise default( 'objectstore, __call_method failed: %s on %s, kwargs: %s'
- %( method, str( obj ), str( kwargs ) ) )
+ % ( method, str( obj ), str( kwargs ) ) )
else:
return default
@@ -462,7 +462,7 @@
self.filesystem_monitor_thread.start()
log.info("Filesystem space monitor started")
- def __parse_distributed_config(self, config, config_xml = None):
+ def __parse_distributed_config(self, config, config_xml=None):
if not config_xml:
tree = util.parse_xml(self.distributed_config)
root = tree.getroot()
@@ -512,7 +512,7 @@
if pct > maxpct:
new_weighted_backend_ids = filter(lambda x: x != id, new_weighted_backend_ids)
self.weighted_backend_ids = new_weighted_backend_ids
- self.sleeper.sleep(120) # Test free space every 2 minutes
+ self.sleeper.sleep(120) # Test free space every 2 minutes
def create(self, obj, **kwargs):
"""
@@ -524,7 +524,7 @@
obj.object_store_id = random.choice(self.weighted_backend_ids)
except IndexError:
raise ObjectInvalid( 'objectstore.create, could not generate obj.object_store_id: %s, kwargs: %s'
- %( str( obj ), str( kwargs ) ) )
+ % ( str( obj ), str( kwargs ) ) )
object_session( obj ).add( obj )
object_session( obj ).flush()
log.debug("Selected backend '%s' for creation of %s %s" % (obj.object_store_id, obj.__class__.__name__, obj.id))
@@ -538,7 +538,7 @@
return self.backends[object_store_id].__getattribute__(method)(obj, **kwargs)
if default_is_exception:
raise default( 'objectstore, __call_method failed: %s on %s, kwargs: %s'
- %( method, str( obj ), str( kwargs ) ) )
+ % ( method, str( obj ), str( kwargs ) ) )
else:
return default
@@ -625,6 +625,7 @@
else:
log.error("Unrecognized object store definition: {0}".format(store))
+
def local_extra_dirs( func ):
""" A decorator for non-local plugins to utilize local directories for their extra_dirs (job_working_directory and temp).
"""
@@ -638,6 +639,7 @@
raise Exception( "Could not call DiskObjectStore's %s method, does your Object Store plugin inherit from DiskObjectStore?" % func.__name__ )
return wraps
+
def convert_bytes(bytes):
""" A helper function used for pretty printing disk usage """
if bytes is None:
diff -r fe2c12b2eb22a5cab876629593e91079e27f2492 -r 433d5f4f5c66c17701d84b08185ca2b733664d6b lib/galaxy/objectstore/rods.py
--- a/lib/galaxy/objectstore/rods.py
+++ b/lib/galaxy/objectstore/rods.py
@@ -146,7 +146,7 @@
doi = irods.dataObjInp_t()
doi.objPath = rods_path
doi.createMode = 0640
- doi.dataSize = 0 # 0 actually means "unknown", although literally 0 would be preferable
+ doi.dataSize = 0 # 0 actually means "unknown", although literally 0 would be preferable
irods.addKeyVal( doi.condInput, irods.DEST_RESC_NAME_KW, self.default_resource )
status = irods.rcDataObjCreate( self.rods_conn, doi )
assert status >= 0, 'create(): rcDataObjCreate() failed: %s: %s: %s' % ( rods_path, status, irods.strerror( status ) )
@@ -237,7 +237,7 @@
incoming_path = os.path.join( os.path.dirname( cached_path ), "__incoming_%s" % os.path.basename( cached_path ) )
doi = irods.dataObjInp_t()
doi.objPath = self.__get_rods_path( obj, **kwargs )
- doi.dataSize = 0 # TODO: does this affect performance? should we get size?
+ doi.dataSize = 0 # TODO: does this affect performance? should we get size?
doi.numThreads = 0
# TODO: might want to VERIFY_CHKSUM_KW
log.debug( 'get_filename(): caching %s to %s', doi.objPath, incoming_path )
@@ -296,6 +296,7 @@
def get_store_usage_percent(self):
return 0.0
+
# monkeypatch an strerror method into the irods module
def _rods_strerror( errno ):
"""
@@ -311,6 +312,7 @@
irods.strerror = _rods_strerror
+
def rods_connect():
"""
A basic iRODS connection mechanism that connects using the current iRODS
diff -r fe2c12b2eb22a5cab876629593e91079e27f2492 -r 433d5f4f5c66c17701d84b08185ca2b733664d6b lib/galaxy/objectstore/s3.py
--- a/lib/galaxy/objectstore/s3.py
+++ b/lib/galaxy/objectstore/s3.py
@@ -24,7 +24,7 @@
from boto.exception import S3ResponseError
log = logging.getLogger( __name__ )
-logging.getLogger('boto').setLevel(logging.INFO) # Otherwise boto is quite noisy
+logging.getLogger('boto').setLevel(logging.INFO) # Otherwise boto is quite noisy
class S3ObjectStore(ObjectStore):
@@ -82,7 +82,7 @@
raise
def __cache_monitor(self):
- time.sleep(2) # Wait for things to load before starting the monitor
+ time.sleep(2) # Wait for things to load before starting the monitor
while self.running:
total_size = 0
# Is this going to be too expensive of an operation to be done frequently?
@@ -110,7 +110,7 @@
# For now, delete enough to leave at least 10% of the total cache free
delete_this_much = total_size - cache_limit
self.__clean_cache(file_list, delete_this_much)
- self.sleeper.sleep(30) # Test cache size every 30 seconds?
+ self.sleeper.sleep(30) # Test cache size every 30 seconds?
def __clean_cache(self, file_list, delete_this_much):
""" Keep deleting files from the file_list until the size of the deleted
@@ -154,7 +154,7 @@
log.debug("Using cloud object store with bucket '%s'" % bucket.name)
return bucket
except S3ResponseError:
- log.debug("Could not get bucket '%s', attempt %s/5" % (bucket_name, i+1))
+ log.debug("Could not get bucket '%s', attempt %s/5" % (bucket_name, i + 1))
time.sleep(2)
# All the attempts have been exhausted and connection was not established,
# raise error
@@ -283,7 +283,7 @@
return True
else:
log.debug("Pulled key '%s' into cache to %s" % (rel_path, self._get_cache_path(rel_path)))
- self.transfer_progress = 0 # Reset transfer progress counter
+ self.transfer_progress = 0 # Reset transfer progress counter
key.get_contents_to_filename(self._get_cache_path(rel_path), cb=self._transfer_cb, num_cb=10)
return True
except S3ResponseError, ex:
@@ -315,14 +315,14 @@
mb_size = os.path.getsize(source_file) / 1e6
#DBTODO Hack, refactor this logic.
if mb_size < 60 or type(self) == SwiftObjectStore:
- self.transfer_progress = 0 # Reset transfer progress counter
+ self.transfer_progress = 0 # Reset transfer progress counter
key.set_contents_from_filename(source_file, reduced_redundancy=self.use_rr,
cb=self._transfer_cb, num_cb=10)
else:
multipart_upload(self.bucket, key.name, source_file, mb_size, use_rr=self.use_rr)
end_time = datetime.now()
# print "+ Push ended at '%s'; %s bytes transfered in %ssec" % (end_time, os.path.getsize(source_file), end_time-start_time)
- log.debug("Pushed cache file '%s' to key '%s' (%s bytes transfered in %s sec)" % (source_file, rel_path, os.path.getsize(source_file), end_time-start_time))
+ log.debug("Pushed cache file '%s' to key '%s' (%s bytes transfered in %s sec)" % (source_file, rel_path, os.path.getsize(source_file), end_time - start_time))
return True
else:
log.error("Tried updating key '%s' from source file '%s', but source file does not exist."
@@ -408,7 +408,7 @@
return bool(self.size(obj, **kwargs) > 0)
else:
raise ObjectNotFound( 'objectstore.empty, object does not exist: %s, kwargs: %s'
- %( str( obj ), str( kwargs ) ) )
+ % ( str( obj ), str( kwargs ) ) )
def size(self, obj, **kwargs):
rel_path = self._construct_path(obj, **kwargs)
@@ -484,7 +484,7 @@
return cache_path
# Check if the file exists in persistent storage and, if it does, pull it into cache
elif self.exists(obj, **kwargs):
- if dir_only: # Directories do not get pulled into cache
+ if dir_only: # Directories do not get pulled into cache
return cache_path
else:
if self._pull_into_cache(rel_path):
@@ -494,7 +494,7 @@
# if dir_only:
# return cache_path
raise ObjectNotFound( 'objectstore.get_filename, no cache_path: %s, kwargs: %s'
- %( str( obj ), str( kwargs ) ) )
+ % ( str( obj ), str( kwargs ) ) )
# return cache_path # Until the upload tool does not explicitly create the dataset, return expected path
def update_from_file(self, obj, file_name=None, create=False, **kwargs):
@@ -520,14 +520,14 @@
self._push_to_os(rel_path, source_file)
else:
raise ObjectNotFound( 'objectstore.update_from_file, object does not exist: %s, kwargs: %s'
- %( str( obj ), str( kwargs ) ) )
+ % ( str( obj ), str( kwargs ) ) )
def get_object_url(self, obj, **kwargs):
if self.exists(obj, **kwargs):
rel_path = self._construct_path(obj, **kwargs)
try:
key = Key(self.bucket, rel_path)
- return key.generate_url(expires_in = 86400) # 24hrs
+ return key.generate_url(expires_in=86400) # 24hrs
except S3ResponseError, ex:
log.warning("Trouble generating URL for dataset '%s': %s" % (rel_path, ex))
return None
@@ -552,4 +552,3 @@
port=self.port,
calling_format=boto.s3.connection.OrdinaryCallingFormat(),
path=self.conn_path)
-
https://bitbucket.org/galaxy/galaxy-central/commits/1f62ef450cd7/
Changeset: 1f62ef450cd7
User: jmchilton
Date: 2013-12-02 02:07:04
Summary: Refactor jobs.Sleeper into its own module.
This eliminates explicit dependency between galaxy.objectstore and galaxy.job - with the ultimate goal of being able to utilize all object store functionality except dataset creation from a remote LWR instance with minimal dependencies.
Affected #: 6 files
diff -r 433d5f4f5c66c17701d84b08185ca2b733664d6b -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -14,7 +14,6 @@
import shutil
import subprocess
import sys
-import threading
import traceback
from galaxy import model, util
from galaxy.datatypes import metadata
@@ -39,21 +38,6 @@
# and should eventually become API'd
TOOL_PROVIDED_JOB_METADATA_FILE = 'galaxy.json'
-class Sleeper( object ):
- """
- Provides a 'sleep' method that sleeps for a number of seconds *unless*
- the notify method is called (from a different thread).
- """
- def __init__( self ):
- self.condition = threading.Condition()
- def sleep( self, seconds ):
- self.condition.acquire()
- self.condition.wait( seconds )
- self.condition.release()
- def wake( self ):
- self.condition.acquire()
- self.condition.notify()
- self.condition.release()
class JobDestination( Bunch ):
"""
diff -r 433d5f4f5c66c17701d84b08185ca2b733664d6b -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -11,7 +11,8 @@
from sqlalchemy.sql.expression import and_, or_, select, func
from galaxy import model
-from galaxy.jobs import Sleeper, JobWrapper, TaskWrapper, JobDestination
+from galaxy.util.sleeper import Sleeper
+from galaxy.jobs import JobWrapper, TaskWrapper, JobDestination
log = logging.getLogger( __name__ )
diff -r 433d5f4f5c66c17701d84b08185ca2b733664d6b -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 lib/galaxy/jobs/manager.py
--- a/lib/galaxy/jobs/manager.py
+++ b/lib/galaxy/jobs/manager.py
@@ -11,7 +11,8 @@
from Queue import Empty, Queue
from galaxy import model
-from galaxy.jobs import handler, JobWrapper, NoopQueue, Sleeper
+from galaxy.util.sleeper import Sleeper
+from galaxy.jobs import handler, JobWrapper, NoopQueue
from galaxy.util.json import from_json_string
log = logging.getLogger( __name__ )
diff -r 433d5f4f5c66c17701d84b08185ca2b733664d6b -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -12,7 +12,7 @@
from galaxy import util
from galaxy.exceptions import ObjectInvalid, ObjectNotFound
-from galaxy.jobs import Sleeper
+from galaxy.util.sleeper import Sleeper
from galaxy.util.directory_hash import directory_hash_id
from galaxy.util.odict import odict
diff -r 433d5f4f5c66c17701d84b08185ca2b733664d6b -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 lib/galaxy/objectstore/s3.py
--- a/lib/galaxy/objectstore/s3.py
+++ b/lib/galaxy/objectstore/s3.py
@@ -11,7 +11,7 @@
from datetime import datetime
from galaxy import util
-from galaxy.jobs import Sleeper
+from galaxy.util.sleeper import Sleeper
from galaxy.util.directory_hash import directory_hash_id
from galaxy.objectstore import ObjectStore, convert_bytes
from galaxy.exceptions import ObjectNotFound
diff -r 433d5f4f5c66c17701d84b08185ca2b733664d6b -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 lib/galaxy/util/sleeper.py
--- /dev/null
+++ b/lib/galaxy/util/sleeper.py
@@ -0,0 +1,22 @@
+import threading
+
+
+class Sleeper( object ):
+ """
+ Provides a 'sleep' method that sleeps for a number of seconds *unless*
+ the notify method is called (from a different thread).
+ """
+ def __init__( self ):
+ self.condition = threading.Condition()
+
+ def sleep( self, seconds ):
+ # Should this be in a try/finally block? -John
+ self.condition.acquire()
+ self.condition.wait( seconds )
+ self.condition.release()
+
+ def wake( self ):
+ # Should this be in a try/finally block? -John
+ self.condition.acquire()
+ self.condition.notify()
+ self.condition.release()
https://bitbucket.org/galaxy/galaxy-central/commits/b78fc1c8b14e/
Changeset: b78fc1c8b14e
User: jmchilton
Date: 2013-12-02 02:07:04
Summary: More work on objectstore dependencies.
Be explicit about what in galaxy.util is being used, don't fail if galaxy.eggs is unavailable - assume the actual dependencies will be there (boto and rods) if not fail just a little later. If nothing else, this should fix some failing buildbot tests (nosetests records a failure if it cannot import a file and it cannot import the s3 or irods object store files because of these imports).
Affected #: 4 files
diff -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 -r b78fc1c8b14e7926d3551f5a676d107fc0a4ed89 lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -10,7 +10,7 @@
import logging
import threading
-from galaxy import util
+from galaxy.util import umask_fix_perms, parse_xml, force_symlink
from galaxy.exceptions import ObjectInvalid, ObjectNotFound
from galaxy.util.sleeper import Sleeper
from galaxy.util.directory_hash import directory_hash_id
@@ -291,7 +291,7 @@
# Create the file if it does not exist
if not dir_only:
open(path, 'w').close()
- util.umask_fix_perms(path, self.config.umask, 0666)
+ umask_fix_perms(path, self.config.umask, 0666)
def empty(self, obj, **kwargs):
return os.path.getsize(self.get_filename(obj, **kwargs)) == 0
@@ -345,7 +345,7 @@
if file_name and self.exists(obj, **kwargs):
try:
if preserve_symlinks and os.path.islink( file_name ):
- util.force_symlink( os.readlink( file_name ), self.get_filename( obj, **kwargs ) )
+ force_symlink( os.readlink( file_name ), self.get_filename( obj, **kwargs ) )
else:
shutil.copy( file_name, self.get_filename( obj, **kwargs ) )
except IOError, ex:
@@ -464,7 +464,7 @@
def __parse_distributed_config(self, config, config_xml=None):
if not config_xml:
- tree = util.parse_xml(self.distributed_config)
+ tree = parse_xml(self.distributed_config)
root = tree.getroot()
log.debug('Loading backends for distributed object store from %s' % self.distributed_config)
else:
@@ -598,7 +598,7 @@
# This is a top level invocation of build_object_store_from_config, and
# we have an object_store_conf.xml -- read the .xml and build
# accordingly
- tree = util.parse_xml(config.object_store_config_file)
+ tree = parse_xml(config.object_store_config_file)
root = tree.getroot()
store = root.get('type')
config_xml = root
diff -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 -r b78fc1c8b14e7926d3551f5a676d107fc0a4ed89 lib/galaxy/objectstore/rods.py
--- a/lib/galaxy/objectstore/rods.py
+++ b/lib/galaxy/objectstore/rods.py
@@ -15,9 +15,14 @@
from galaxy.objectstore import DiskObjectStore, ObjectStore, local_extra_dirs
from galaxy.exceptions import ObjectNotFound
-import galaxy.eggs
-galaxy.eggs.require( 'PyRods' )
-import irods
+try:
+ import galaxy.eggs
+ galaxy.eggs.require( 'PyRods' )
+ import irods
+except ImportError:
+ irods = None
+
+NO_PYRODS_ERROR_MESSAGE = "IRODS object store configured, but no PyRods dependency available. Please install and properly configure PyRods or modify object store configuration."
log = logging.getLogger( __name__ )
@@ -27,6 +32,8 @@
Galaxy object store based on iRODS
"""
def __init__( self, config, file_path=None, extra_dirs=None ):
+ if irods is None:
+ raise Exception(NO_PYRODS_ERROR_MESSAGE)
super( IRODSObjectStore, self ).__init__( config, file_path=file_path, extra_dirs=extra_dirs )
self.cache_path = config.object_store_cache_path
self.default_resource = config.irods_default_resource or None
@@ -310,7 +317,8 @@
irods.__rods_strerror_map[ v ] = name
return irods.__rods_strerror_map.get( errno, 'GALAXY_NO_ERRNO_MAPPING_FOUND' )
-irods.strerror = _rods_strerror
+if irods is not None:
+ irods.strerror = _rods_strerror
def rods_connect():
diff -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 -r b78fc1c8b14e7926d3551f5a676d107fc0a4ed89 lib/galaxy/objectstore/s3.py
--- a/lib/galaxy/objectstore/s3.py
+++ b/lib/galaxy/objectstore/s3.py
@@ -10,7 +10,7 @@
import subprocess
from datetime import datetime
-from galaxy import util
+from galaxy.util import umask_fix_perms
from galaxy.util.sleeper import Sleeper
from galaxy.util.directory_hash import directory_hash_id
from galaxy.objectstore import ObjectStore, convert_bytes
@@ -18,10 +18,16 @@
import multiprocessing
from galaxy.objectstore.s3_multipart_upload import multipart_upload
-import boto
-from boto.s3.key import Key
-from boto.s3.connection import S3Connection
-from boto.exception import S3ResponseError
+try:
+ import boto
+ from boto.s3.key import Key
+ from boto.s3.connection import S3Connection
+ from boto.exception import S3ResponseError
+except ImportError:
+ boto = None
+
+NO_BOTO_ERROR_MESSAGE = "S3/Swift object store configured, but no boto dependency available. Please install and properly configure boto or modify object store configuration."
+
log = logging.getLogger( __name__ )
logging.getLogger('boto').setLevel(logging.INFO) # Otherwise boto is quite noisy
@@ -34,6 +40,8 @@
Galaxy and S3.
"""
def __init__(self, config, config_xml):
+ if boto is None:
+ raise Exception(NO_BOTO_ERROR_MESSAGE)
super(S3ObjectStore, self).__init__(config, config_xml)
self.config = config
self.staging_path = self.config.file_path
@@ -163,13 +171,13 @@
def _fix_permissions(self, rel_path):
""" Set permissions on rel_path"""
for basedir, dirs, files in os.walk(rel_path):
- util.umask_fix_perms(basedir, self.config.umask, 0777, self.config.gid)
+ umask_fix_perms(basedir, self.config.umask, 0777, self.config.gid)
for f in files:
path = os.path.join(basedir, f)
# Ignore symlinks
if os.path.islink(path):
continue
- util.umask_fix_perms( path, self.config.umask, 0666, self.config.gid )
+ umask_fix_perms( path, self.config.umask, 0666, self.config.gid )
def _construct_path(self, obj, dir_only=None, extra_dir=None, extra_dir_at_root=False, alt_name=None, **kwargs):
rel_path = os.path.join(*directory_hash_id(obj.id))
diff -r 1f62ef450cd7c79af0de6a22f8c2b1c1b6cb9114 -r b78fc1c8b14e7926d3551f5a676d107fc0a4ed89 lib/galaxy/objectstore/s3_multipart_upload.py
--- a/lib/galaxy/objectstore/s3_multipart_upload.py
+++ b/lib/galaxy/objectstore/s3_multipart_upload.py
@@ -4,10 +4,8 @@
This parallelizes the task over available cores using multiprocessing.
Code mostly taken form CloudBioLinux.
"""
-from __future__ import with_statement
import os
-import sys
import glob
import subprocess
import contextlib
@@ -16,10 +14,17 @@
import multiprocessing
from multiprocessing.pool import IMapIterator
-from galaxy import eggs
-eggs.require('boto')
+try:
+ from galaxy import eggs
+ eggs.require('boto')
+except ImportError:
+ pass
-import boto
+try:
+ import boto
+except ImportError:
+ boto = None
+
def map_wrap(f):
@functools.wraps(f)
https://bitbucket.org/galaxy/galaxy-central/commits/a03f4f2f46dd/
Changeset: a03f4f2f46dd
User: jmchilton
Date: 2013-12-02 02:07:04
Summary: Use relative imports in objectstore code.
Goal is to enable the whole module to be placed in lwr.objectstore.
Affected #: 3 files
diff -r b78fc1c8b14e7926d3551f5a676d107fc0a4ed89 -r a03f4f2f46dd783bd183def7ade25d0e10017ced lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -610,17 +610,17 @@
if store == 'disk':
return DiskObjectStore(config=config, config_xml=config_xml)
elif store == 's3':
- from galaxy.objectstore.s3 import S3ObjectStore
+ from .s3 import S3ObjectStore
return S3ObjectStore(config=config, config_xml=config_xml)
elif store == 'swift':
- from galaxy.objectstore.s3 import SwiftObjectStore
+ from .s3 import SwiftObjectStore
return SwiftObjectStore(config=config, config_xml=config_xml)
elif store == 'distributed':
return DistributedObjectStore(config=config, fsmon=fsmon, config_xml=config_xml)
elif store == 'hierarchical':
return HierarchicalObjectStore(config=config, config_xml=config_xml)
elif store == 'irods':
- from galaxy.objectstore.rods import IRODSObjectStore
+ from .rods import IRODSObjectStore
return IRODSObjectStore(config=config, config_xml=config_xml)
else:
log.error("Unrecognized object store definition: {0}".format(store))
diff -r b78fc1c8b14e7926d3551f5a676d107fc0a4ed89 -r a03f4f2f46dd783bd183def7ade25d0e10017ced lib/galaxy/objectstore/rods.py
--- a/lib/galaxy/objectstore/rods.py
+++ b/lib/galaxy/objectstore/rods.py
@@ -12,8 +12,8 @@
from posixpath import basename as path_basename
from posixpath import dirname as path_dirname
-from galaxy.objectstore import DiskObjectStore, ObjectStore, local_extra_dirs
from galaxy.exceptions import ObjectNotFound
+from ..objectstore import DiskObjectStore, ObjectStore, local_extra_dirs
try:
import galaxy.eggs
diff -r b78fc1c8b14e7926d3551f5a676d107fc0a4ed89 -r a03f4f2f46dd783bd183def7ade25d0e10017ced lib/galaxy/objectstore/s3.py
--- a/lib/galaxy/objectstore/s3.py
+++ b/lib/galaxy/objectstore/s3.py
@@ -13,11 +13,11 @@
from galaxy.util import umask_fix_perms
from galaxy.util.sleeper import Sleeper
from galaxy.util.directory_hash import directory_hash_id
-from galaxy.objectstore import ObjectStore, convert_bytes
+from ..objectstore import ObjectStore, convert_bytes
from galaxy.exceptions import ObjectNotFound
import multiprocessing
-from galaxy.objectstore.s3_multipart_upload import multipart_upload
+from .s3_multipart_upload import multipart_upload
try:
import boto
from boto.s3.key import Key
@@ -28,7 +28,6 @@
NO_BOTO_ERROR_MESSAGE = "S3/Swift object store configured, but no boto dependency available. Please install and properly configure boto or modify object store configuration."
-
log = logging.getLogger( __name__ )
logging.getLogger('boto').setLevel(logging.INFO) # Otherwise boto is quite noisy
https://bitbucket.org/galaxy/galaxy-central/commits/10701b684e73/
Changeset: 10701b684e73
User: jmchilton
Date: 2013-12-02 02:07:04
Summary: Make sqlalchemy dependency in object store optional unless create is used.
Affected #: 1 file
diff -r a03f4f2f46dd783bd183def7ade25d0e10017ced -r 10701b684e73af78f9688ded379e82b3417c86bf lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -15,8 +15,12 @@
from galaxy.util.sleeper import Sleeper
from galaxy.util.directory_hash import directory_hash_id
from galaxy.util.odict import odict
+try:
+ from sqlalchemy.orm import object_session
+except ImportError:
+ object_session = None
-from sqlalchemy.orm import object_session
+NO_SESSION_ERROR_MESSAGE = "Attempted to 'create' object store entity in configuration with no database session present."
log = logging.getLogger( __name__ )
@@ -525,8 +529,7 @@
except IndexError:
raise ObjectInvalid( 'objectstore.create, could not generate obj.object_store_id: %s, kwargs: %s'
% ( str( obj ), str( kwargs ) ) )
- object_session( obj ).add( obj )
- object_session( obj ).flush()
+ create_object_in_session( obj )
log.debug("Selected backend '%s' for creation of %s %s" % (obj.object_store_id, obj.__class__.__name__, obj.id))
else:
log.debug("Using preferred backend '%s' for creation of %s %s" % (obj.object_store_id, obj.__class__.__name__, obj.id))
@@ -554,8 +557,7 @@
if store.exists(obj, **kwargs):
log.warning('%s object with ID %s found in backend object store with ID %s' % (obj.__class__.__name__, obj.id, id))
obj.object_store_id = id
- object_session( obj ).add( obj )
- object_session( obj ).flush()
+ create_object_in_session( obj )
return id
return None
@@ -661,3 +663,12 @@
else:
size = '%.2fb' % bytes
return size
+
+
+def create_object_in_session( obj ):
+ session = object_session( obj ) if object_session is not None else None
+ if session is not None:
+ object_session( obj ).add( obj )
+ object_session( obj ).flush()
+ else:
+ raise Exception( NO_SESSION_ERROR_MESSAGE )
https://bitbucket.org/galaxy/galaxy-central/commits/1ba3ef72b736/
Changeset: 1ba3ef72b736
User: jmchilton
Date: 2013-12-02 02:07:04
Summary: Update objectstore XML parsing to stdlib's ElementTree implementation.
Eliminates dependency on older elementtree egg.
Affected #: 1 file
diff -r 10701b684e73af78f9688ded379e82b3417c86bf -r 1ba3ef72b7364678ab87d95412164eee89f8913e lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -9,8 +9,9 @@
import shutil
import logging
import threading
+from xml.etree import ElementTree
-from galaxy.util import umask_fix_perms, parse_xml, force_symlink
+from galaxy.util import umask_fix_perms, force_symlink
from galaxy.exceptions import ObjectInvalid, ObjectNotFound
from galaxy.util.sleeper import Sleeper
from galaxy.util.directory_hash import directory_hash_id
@@ -206,7 +207,7 @@
self.extra_dirs['job_work'] = config.job_working_directory
self.extra_dirs['temp'] = config.new_file_path
#The new config_xml overrides universe settings.
- if config_xml:
+ if config_xml is not None:
for e in config_xml:
if e.tag == 'files_dir':
self.file_path = e.get('path')
@@ -294,7 +295,7 @@
os.makedirs(dir)
# Create the file if it does not exist
if not dir_only:
- open(path, 'w').close()
+ open(path, 'w').close() # Should be rb?
umask_fix_perms(path, self.config.umask, 0666)
def empty(self, obj, **kwargs):
@@ -324,7 +325,7 @@
return False
def get_data(self, obj, start=0, count=-1, **kwargs):
- data_file = open(self.get_filename(obj, **kwargs), 'r')
+ data_file = open(self.get_filename(obj, **kwargs), 'r') # Should be rb?
data_file.seek(start)
content = data_file.read(count)
data_file.close()
@@ -446,7 +447,7 @@
def __init__(self, config, config_xml=None, fsmon=False):
super(DistributedObjectStore, self).__init__(config, config_xml=config_xml)
- if not config_xml:
+ if config_xml is None:
self.distributed_config = config.distributed_object_store_config_file
assert self.distributed_config is not None, "distributed object store ('object_store = distributed') " \
"requires a config file, please set one in " \
@@ -467,9 +468,8 @@
log.info("Filesystem space monitor started")
def __parse_distributed_config(self, config, config_xml=None):
- if not config_xml:
- tree = parse_xml(self.distributed_config)
- root = tree.getroot()
+ if config_xml is None:
+ root = ElementTree.parse(self.distributed_config).getroot()
log.debug('Loading backends for distributed object store from %s' % self.distributed_config)
else:
root = config_xml.find('backends')
@@ -596,15 +596,14 @@
Depending on the configuration setting, invoke the appropriate object store
"""
- if not config_xml and config.object_store_config_file:
+ if config_xml is None and config.object_store_config_file:
# This is a top level invocation of build_object_store_from_config, and
# we have an object_store_conf.xml -- read the .xml and build
# accordingly
- tree = parse_xml(config.object_store_config_file)
- root = tree.getroot()
+ root = ElementTree.parse(config.object_store_config_file).getroot()
store = root.get('type')
config_xml = root
- elif config_xml:
+ elif config_xml is not None:
store = config_xml.get('type')
else:
store = config.object_store
https://bitbucket.org/galaxy/galaxy-central/commits/a194847d84d3/
Changeset: a194847d84d3
User: jmchilton
Date: 2013-12-02 02:07:04
Summary: Add test cases for some basic object store types.
Namely tests for disk, hierarchical, and distributed stores - as well parsing.
Affected #: 1 file
diff -r 1ba3ef72b7364678ab87d95412164eee89f8913e -r a194847d84d373cd7efdb581819115e7303e0568 test/unit/test_objectstore.py
--- /dev/null
+++ b/test/unit/test_objectstore.py
@@ -0,0 +1,210 @@
+import os
+from shutil import rmtree
+from string import Template
+from tempfile import mkdtemp
+try:
+ from galaxy import objectstore
+except ImportError:
+ from lwr import objectstore
+from contextlib import contextmanager
+
+DISK_TEST_CONFIG = """<?xml version="1.0"?>
+<object_store type="disk">
+ <files_dir path="${temp_directory}/files1"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp1"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory1"/>
+</object_store>
+"""
+
+
+def test_disk_store():
+ with TestConfig(DISK_TEST_CONFIG) as (directory, object_store):
+ # Test no dataset with id 1 exists.
+ absent_dataset = MockDataset(1)
+ assert not object_store.exists(absent_dataset)
+
+ # Write empty dataset 2 in second backend, ensure it is empty and
+ # exists.
+ empty_dataset = MockDataset(2)
+ directory.write(b"", "files1/000/dataset_2.dat")
+ assert object_store.exists(empty_dataset)
+ assert object_store.empty(empty_dataset)
+
+ # Write non-empty dataset in backend 1, test it is not emtpy & exists.
+ hello_world_dataset = MockDataset(3)
+ directory.write(b"Hello World!", "files1/000/dataset_3.dat")
+ assert object_store.exists(hello_world_dataset)
+ assert not object_store.empty(hello_world_dataset)
+
+ # Test get_data
+ data = object_store.get_data(hello_world_dataset)
+ assert data == b"Hello World!"
+
+ data = object_store.get_data(hello_world_dataset, start=1, count=6)
+ assert data == b"ello W"
+
+ # Test Size
+
+ # Test absent and empty datasets yield size of 0.
+ assert object_store.size(absent_dataset) == 0
+ assert object_store.size(empty_dataset) == 0
+ # Elsewise
+ assert object_store.size(hello_world_dataset) > 0 # Should this always be the number of bytes?
+
+ # Test percent used (to some degree)
+ percent_store_used = object_store.get_store_usage_percent()
+ assert percent_store_used > 0.0
+ assert percent_store_used < 100.0
+
+ # Test update_from_file test
+ output_dataset = MockDataset(4)
+ output_real_path = os.path.join(directory.temp_directory, "files1", "000", "dataset_4.dat")
+ assert not os.path.exists(output_real_path)
+ output_working_path = directory.write(b"NEW CONTENTS", "job_working_directory1/example_output")
+ object_store.update_from_file(output_dataset, file_name=output_working_path, create=True)
+ assert os.path.exists(output_real_path)
+
+ # Test delete
+ to_delete_dataset = MockDataset(5)
+ to_delete_real_path = directory.write(b"content to be deleted!", "files1/000/dataset_5.dat")
+ assert object_store.exists(to_delete_dataset)
+ assert object_store.delete(to_delete_dataset)
+ assert not object_store.exists(to_delete_dataset)
+ assert not os.path.exists(to_delete_real_path)
+
+
+HIERARCHICAL_TEST_CONFIG = """<?xml version="1.0"?>
+<object_store type="hierarchical">
+ <backends>
+ <backend id="files1" type="disk" weight="1" order="0">
+ <files_dir path="${temp_directory}/files1"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp1"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory1"/>
+ </backend>
+ <backend id="files2" type="disk" weight="1" order="1">
+ <files_dir path="${temp_directory}/files2"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp2"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory2"/>
+ </backend>
+ </backends>
+</object_store>
+"""
+
+
+def test_hierarchical_store():
+ with TestConfig(HIERARCHICAL_TEST_CONFIG) as (directory, object_store):
+
+ # Test no dataset with id 1 exists.
+ assert not object_store.exists(MockDataset(1))
+
+ # Write empty dataset 2 in second backend, ensure it is empty and
+ # exists.
+ directory.write("", "files2/000/dataset_2.dat")
+ assert object_store.exists(MockDataset(2))
+ assert object_store.empty(MockDataset(2))
+
+ # Write non-empty dataset in backend 1, test it is not emtpy & exists.
+ directory.write("Hello World!", "files1/000/dataset_3.dat")
+ assert object_store.exists(MockDataset(3))
+ assert not object_store.empty(MockDataset(3))
+
+ # Assert creation always happens in first backend.
+ for i in range(100):
+ dataset = MockDataset(100 + i)
+ object_store.create(dataset)
+ assert object_store.get_filename(dataset).find("files1") > 0
+
+
+DISTRIBUTED_TEST_CONFIG = """<?xml version="1.0"?>
+<object_store type="distributed">
+ <backends>
+ <backend id="files1" type="disk" weight="2" order="0">
+ <files_dir path="${temp_directory}/files1"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp1"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory1"/>
+ </backend>
+ <backend id="files2" type="disk" weight="1" order="1">
+ <files_dir path="${temp_directory}/files2"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp2"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory2"/>
+ </backend>
+ </backends>
+</object_store>
+"""
+
+
+def test_distributed_store():
+ with TestConfig(DISTRIBUTED_TEST_CONFIG) as (directory, object_store):
+ with __stubbed_persistence() as persisted_ids:
+ for i in range(100):
+ dataset = MockDataset(100 + i)
+ object_store.create(dataset)
+
+ ## Test distributes datasets between backends according to weights
+ backend_1_count = len([v for v in persisted_ids.values() if v == "files1"])
+ backend_2_count = len([v for v in persisted_ids.values() if v == "files2"])
+
+ assert backend_1_count > 0
+ assert backend_2_count > 0
+ assert backend_1_count > backend_2_count
+
+
+class TestConfig(object):
+ def __init__(self, config_xml):
+ self.temp_directory = mkdtemp()
+ self.write(config_xml, "store.xml")
+ config = MockConfig(self.temp_directory)
+ self.object_store = objectstore.build_object_store_from_config(config)
+
+ def __enter__(self):
+ return self, self.object_store
+
+ def __exit__(self, type, value, tb):
+ rmtree(self.temp_directory)
+
+ def write(self, contents, name):
+ path = os.path.join(self.temp_directory, name)
+ directory = os.path.dirname(path)
+ if not os.path.exists(directory):
+ os.makedirs(directory)
+ expanded_contents = Template(contents).safe_substitute(temp_directory=self.temp_directory)
+ open(path, "w").write(expanded_contents)
+ return path
+
+
+class MockConfig(object):
+
+ def __init__(self, temp_directory):
+ self.file_path = temp_directory
+ self.object_store_config_file = os.path.join(temp_directory, "store.xml")
+ self.object_store_check_old_style = False
+ self.job_working_directory = temp_directory
+ self.new_file_path = temp_directory
+ self.umask = 0000
+
+
+class MockDataset(object):
+
+ def __init__(self, id):
+ self.id = id
+ self.object_store_id = None
+
+
+## Poor man's mocking. Need to get a real mocking library as real Galaxy development
+## dependnecy.
+PERSIST_METHOD_NAME = "create_object_in_session"
+
+
+@contextmanager
+def __stubbed_persistence():
+ real_method = getattr(objectstore, PERSIST_METHOD_NAME)
+ try:
+ persisted_ids = {}
+
+ def persist(object):
+ persisted_ids[object.id] = object.object_store_id
+ setattr(objectstore, PERSIST_METHOD_NAME, persist)
+ yield persisted_ids
+
+ finally:
+ setattr(objectstore, PERSIST_METHOD_NAME, real_method)
https://bitbucket.org/galaxy/galaxy-central/commits/5c62540e3f59/
Changeset: 5c62540e3f59
User: jmchilton
Date: 2013-12-02 02:07:04
Summary: Add an LWR object store implementation.
This changeset implements an object store implementation that delegates to a concrete remote object store instance via an LWR server. Can utilize existing LWR security mechanisms and multiple transport options.
Updates the Galaxy LWR client through LWR changeset 2333f57.
This changeset contains no tests for this new implementation, but the LWR contains the same code along with an integration test that spins up a temp LWR to test against - this test case demonstrating the lwr object store client and server can be found here : https://bitbucket.org/jmchilton/lwr/src/default/test/lwr_objectstore_test.py.
Affected #: 4 files
diff -r a194847d84d373cd7efdb581819115e7303e0568 -r 5c62540e3f5999fe70b3eeff73bee8cce5aa24c3 lib/galaxy/jobs/runners/lwr_client/client.py
--- a/lib/galaxy/jobs/runners/lwr_client/client.py
+++ b/lib/galaxy/jobs/runners/lwr_client/client.py
@@ -50,6 +50,7 @@
return "No remote output found for path %s" % self.path
+# TODO: Rename to job client.
class Client(object):
"""
Objects of this client class perform low-level communication with a remote LWR server.
@@ -326,3 +327,55 @@
@parseJson()
def file_available(self, path):
return self._raw_execute("file_available", {"path": path})
+
+
+class ObjectStoreClient(object):
+
+ def __init__(self, lwr_interface):
+ self.lwr_interface = lwr_interface
+
+ @parseJson()
+ def exists(self, **kwds):
+ return self._raw_execute("object_store_exists", args=self.__data(**kwds))
+
+ @parseJson()
+ def file_ready(self, **kwds):
+ return self._raw_execute("object_store_file_ready", args=self.__data(**kwds))
+
+ @parseJson()
+ def create(self, **kwds):
+ return self._raw_execute("object_store_create", args=self.__data(**kwds))
+
+ @parseJson()
+ def empty(self, **kwds):
+ return self._raw_execute("object_store_empty", args=self.__data(**kwds))
+
+ @parseJson()
+ def size(self, **kwds):
+ return self._raw_execute("object_store_size", args=self.__data(**kwds))
+
+ @parseJson()
+ def delete(self, **kwds):
+ return self._raw_execute("object_store_delete", args=self.__data(**kwds))
+
+ @parseJson()
+ def get_data(self, **kwds):
+ return self._raw_execute("object_store_get_data", args=self.__data(**kwds))
+
+ @parseJson()
+ def get_filename(self, **kwds):
+ return self._raw_execute("object_store_get_filename", args=self.__data(**kwds))
+
+ @parseJson()
+ def update_from_file(self, **kwds):
+ return self._raw_execute("object_store_update_from_file", args=self.__data(**kwds))
+
+ @parseJson()
+ def get_store_usage_percent(self):
+ return self._raw_execute("object_store_get_store_usage_percent", args={})
+
+ def __data(self, **kwds):
+ return kwds
+
+ def _raw_execute(self, command, args={}):
+ return self.lwr_interface.execute(command, args, data=None, input_path=None, output_path=None)
diff -r a194847d84d373cd7efdb581819115e7303e0568 -r 5c62540e3f5999fe70b3eeff73bee8cce5aa24c3 lib/galaxy/jobs/runners/lwr_client/manager.py
--- a/lib/galaxy/jobs/runners/lwr_client/manager.py
+++ b/lib/galaxy/jobs/runners/lwr_client/manager.py
@@ -19,6 +19,7 @@
from galaxy.util import unicodify as text_type
from .client import Client, InputCachingClient
+from .client import ObjectStoreClient
from .transport import get_transport
from .util import TransferEventManager
from .destination import url_to_destination_params
@@ -74,6 +75,26 @@
return destination_params
+class ObjectStoreClientManager(object):
+
+ def __init__(self, **kwds):
+ if 'object_store' in kwds:
+ self.interface_class = LocalLwrInterface
+ self.interface_args = dict(object_store=kwds['object_store'])
+ else:
+ self.interface_class = HttpLwrInterface
+ transport_type = kwds.get('transport_type', None)
+ transport = get_transport(transport_type)
+ self.interface_args = dict(transport=transport)
+ self.extra_client_kwds = {}
+
+ def get_client(self, client_params):
+ interface_class = self.interface_class
+ interface_args = dict(destination_params=client_params, **self.interface_args)
+ interface = interface_class(**interface_args)
+ return ObjectStoreClient(interface)
+
+
class JobManagerInteface(object):
"""
Abstract base class describes how client communicates with remote job
@@ -114,9 +135,10 @@
class LocalLwrInterface(object):
- def __init__(self, destination_params, job_manager, file_cache):
+ def __init__(self, destination_params, job_manager=None, file_cache=None, object_store=None):
self.job_manager = job_manager
self.file_cache = file_cache
+ self.object_store = object_store
def __app_args(self):
## Arguments that would be specified from LwrApp if running
@@ -124,6 +146,7 @@
return {
'manager': self.job_manager,
'file_cache': self.file_cache,
+ 'object_store': self.object_store,
'ip': None
}
@@ -204,4 +227,4 @@
int_val = int(val)
return int_val
-__all__ = [ClientManager, HttpLwrInterface]
+__all__ = [ClientManager, ObjectStoreClientManager, HttpLwrInterface]
diff -r a194847d84d373cd7efdb581819115e7303e0568 -r 5c62540e3f5999fe70b3eeff73bee8cce5aa24c3 lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -623,6 +623,9 @@
elif store == 'irods':
from .rods import IRODSObjectStore
return IRODSObjectStore(config=config, config_xml=config_xml)
+ elif store == 'lwr':
+ from .lwr import LwrObjectStore
+ return LwrObjectStore(config=config, config_xml=config_xml)
else:
log.error("Unrecognized object store definition: {0}".format(store))
diff -r a194847d84d373cd7efdb581819115e7303e0568 -r 5c62540e3f5999fe70b3eeff73bee8cce5aa24c3 lib/galaxy/objectstore/lwr.py
--- /dev/null
+++ b/lib/galaxy/objectstore/lwr.py
@@ -0,0 +1,76 @@
+from __future__ import absolute_import # Need to import lwr_client absolutely.
+from ..objectstore import ObjectStore
+try:
+ from galaxy.jobs.runners.lwr_client.manager import ObjectStoreClientManager
+except ImportError:
+ from lwr.lwr_client.manager import ObjectStoreClientManager
+
+
+class LwrObjectStore(ObjectStore):
+ """
+ Object store implementation that delegates to a remote LWR server.
+
+ This may be more aspirational than practical for now, it would be good to
+ Galaxy to a point that a handler thread could be setup that doesn't attempt
+ to access the disk files returned by a (this) object store - just passing
+ them along to the LWR unmodified. That modification - along with this
+ implementation and LWR job destinations would then allow Galaxy to fully
+ manage jobs on remote servers with completely different mount points.
+
+ This implementation should be considered beta and may be dropped from
+ Galaxy at some future point or significantly modified.
+ """
+
+ def __init__(self, config, config_xml):
+ self.lwr_client = self.__build_lwr_client(config_xml)
+
+ def exists(self, obj, **kwds):
+ return self.lwr_client.exists(**self.__build_kwds(obj, **kwds))
+
+ def file_ready(self, obj, **kwds):
+ return self.lwr_client.file_ready(**self.__build_kwds(obj, **kwds))
+
+ def create(self, obj, **kwds):
+ return self.lwr_client.create(**self.__build_kwds(obj, **kwds))
+
+ def empty(self, obj, **kwds):
+ return self.lwr_client.empty(**self.__build_kwds(obj, **kwds))
+
+ def size(self, obj, **kwds):
+ return self.lwr_client.size(**self.__build_kwds(obj, **kwds))
+
+ def delete(self, obj, **kwds):
+ return self.lwr_client.delete(**self.__build_kwds(obj, **kwds))
+
+ # TODO: Optimize get_data.
+ def get_data(self, obj, **kwds):
+ return self.lwr_client.get_data(**self.__build_kwds(obj, **kwds))
+
+ def get_filename(self, obj, **kwds):
+ return self.lwr_client.get_filename(**self.__build_kwds(obj, **kwds))
+
+ def update_from_file(self, obj, **kwds):
+ return self.lwr_client.update_from_file(**self.__build_kwds(obj, **kwds))
+
+ def get_store_usage_percent(self):
+ return self.lwr_client.get_store_usage_percent()
+
+ def get_object_url(self, obj, extra_dir=None, extra_dir_at_root=False, alt_name=None):
+ return None
+
+ def __build_kwds(self, obj, **kwds):
+ kwds['object_id'] = obj.id
+ return kwds
+ pass
+
+ def __build_lwr_client(self, config_xml):
+ url = config_xml.get("url")
+ private_token = config_xml.get("private_token", None)
+ transport = config_xml.get("transport", None)
+ manager_options = dict(transport=transport)
+ client_options = dict(url=url, private_token=private_token)
+ lwr_client = ObjectStoreClientManager(**manager_options).get_client(client_options)
+ return lwr_client
+
+ def shutdown(self):
+ pass
https://bitbucket.org/galaxy/galaxy-central/commits/a540510a3091/
Changeset: a540510a3091
User: dannon
Date: 2013-12-03 17:12:57
Summary: Merged in jmchilton/galaxy-central-fork-1 (pull request #269)
Object Store dependency refactoring, testing, and added LWR implementation.
Affected #: 14 files
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -14,7 +14,6 @@
import shutil
import subprocess
import sys
-import threading
import traceback
from galaxy import model, util
from galaxy.datatypes import metadata
@@ -39,21 +38,6 @@
# and should eventually become API'd
TOOL_PROVIDED_JOB_METADATA_FILE = 'galaxy.json'
-class Sleeper( object ):
- """
- Provides a 'sleep' method that sleeps for a number of seconds *unless*
- the notify method is called (from a different thread).
- """
- def __init__( self ):
- self.condition = threading.Condition()
- def sleep( self, seconds ):
- self.condition.acquire()
- self.condition.wait( seconds )
- self.condition.release()
- def wake( self ):
- self.condition.acquire()
- self.condition.notify()
- self.condition.release()
class JobDestination( Bunch ):
"""
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -11,7 +11,8 @@
from sqlalchemy.sql.expression import and_, or_, select, func
from galaxy import model
-from galaxy.jobs import Sleeper, JobWrapper, TaskWrapper, JobDestination
+from galaxy.util.sleeper import Sleeper
+from galaxy.jobs import JobWrapper, TaskWrapper, JobDestination
log = logging.getLogger( __name__ )
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/jobs/manager.py
--- a/lib/galaxy/jobs/manager.py
+++ b/lib/galaxy/jobs/manager.py
@@ -11,7 +11,8 @@
from Queue import Empty, Queue
from galaxy import model
-from galaxy.jobs import handler, JobWrapper, NoopQueue, Sleeper
+from galaxy.util.sleeper import Sleeper
+from galaxy.jobs import handler, JobWrapper, NoopQueue
from galaxy.util.json import from_json_string
log = logging.getLogger( __name__ )
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/jobs/runners/lwr_client/client.py
--- a/lib/galaxy/jobs/runners/lwr_client/client.py
+++ b/lib/galaxy/jobs/runners/lwr_client/client.py
@@ -50,6 +50,7 @@
return "No remote output found for path %s" % self.path
+# TODO: Rename to job client.
class Client(object):
"""
Objects of this client class perform low-level communication with a remote LWR server.
@@ -326,3 +327,55 @@
@parseJson()
def file_available(self, path):
return self._raw_execute("file_available", {"path": path})
+
+
+class ObjectStoreClient(object):
+
+ def __init__(self, lwr_interface):
+ self.lwr_interface = lwr_interface
+
+ @parseJson()
+ def exists(self, **kwds):
+ return self._raw_execute("object_store_exists", args=self.__data(**kwds))
+
+ @parseJson()
+ def file_ready(self, **kwds):
+ return self._raw_execute("object_store_file_ready", args=self.__data(**kwds))
+
+ @parseJson()
+ def create(self, **kwds):
+ return self._raw_execute("object_store_create", args=self.__data(**kwds))
+
+ @parseJson()
+ def empty(self, **kwds):
+ return self._raw_execute("object_store_empty", args=self.__data(**kwds))
+
+ @parseJson()
+ def size(self, **kwds):
+ return self._raw_execute("object_store_size", args=self.__data(**kwds))
+
+ @parseJson()
+ def delete(self, **kwds):
+ return self._raw_execute("object_store_delete", args=self.__data(**kwds))
+
+ @parseJson()
+ def get_data(self, **kwds):
+ return self._raw_execute("object_store_get_data", args=self.__data(**kwds))
+
+ @parseJson()
+ def get_filename(self, **kwds):
+ return self._raw_execute("object_store_get_filename", args=self.__data(**kwds))
+
+ @parseJson()
+ def update_from_file(self, **kwds):
+ return self._raw_execute("object_store_update_from_file", args=self.__data(**kwds))
+
+ @parseJson()
+ def get_store_usage_percent(self):
+ return self._raw_execute("object_store_get_store_usage_percent", args={})
+
+ def __data(self, **kwds):
+ return kwds
+
+ def _raw_execute(self, command, args={}):
+ return self.lwr_interface.execute(command, args, data=None, input_path=None, output_path=None)
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/jobs/runners/lwr_client/manager.py
--- a/lib/galaxy/jobs/runners/lwr_client/manager.py
+++ b/lib/galaxy/jobs/runners/lwr_client/manager.py
@@ -19,6 +19,7 @@
from galaxy.util import unicodify as text_type
from .client import Client, InputCachingClient
+from .client import ObjectStoreClient
from .transport import get_transport
from .util import TransferEventManager
from .destination import url_to_destination_params
@@ -74,6 +75,26 @@
return destination_params
+class ObjectStoreClientManager(object):
+
+ def __init__(self, **kwds):
+ if 'object_store' in kwds:
+ self.interface_class = LocalLwrInterface
+ self.interface_args = dict(object_store=kwds['object_store'])
+ else:
+ self.interface_class = HttpLwrInterface
+ transport_type = kwds.get('transport_type', None)
+ transport = get_transport(transport_type)
+ self.interface_args = dict(transport=transport)
+ self.extra_client_kwds = {}
+
+ def get_client(self, client_params):
+ interface_class = self.interface_class
+ interface_args = dict(destination_params=client_params, **self.interface_args)
+ interface = interface_class(**interface_args)
+ return ObjectStoreClient(interface)
+
+
class JobManagerInteface(object):
"""
Abstract base class describes how client communicates with remote job
@@ -114,9 +135,10 @@
class LocalLwrInterface(object):
- def __init__(self, destination_params, job_manager, file_cache):
+ def __init__(self, destination_params, job_manager=None, file_cache=None, object_store=None):
self.job_manager = job_manager
self.file_cache = file_cache
+ self.object_store = object_store
def __app_args(self):
## Arguments that would be specified from LwrApp if running
@@ -124,6 +146,7 @@
return {
'manager': self.job_manager,
'file_cache': self.file_cache,
+ 'object_store': self.object_store,
'ip': None
}
@@ -204,4 +227,4 @@
int_val = int(val)
return int_val
-__all__ = [ClientManager, HttpLwrInterface]
+__all__ = [ClientManager, ObjectStoreClientManager, HttpLwrInterface]
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -29,6 +29,7 @@
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.util.directory_hash import directory_hash_id
from galaxy.web.framework.helpers import to_unicode
from galaxy.web.form_builder import (AddressField, CheckboxField, HistoryField,
PasswordField, SelectField, TextArea, TextField, WorkflowField,
@@ -4012,18 +4013,3 @@
self.repository_id = repository_id
self.repository_path = repository_path
self.version = version
-
-## ---- Utility methods -------------------------------------------------------
-
-def directory_hash_id( id ):
- s = str( id )
- l = len( s )
- # Shortcut -- ids 0-999 go under ../000/
- if l < 4:
- return [ "000" ]
- # Pad with zeros until a multiple of three
- padded = ( ( 3 - len( s ) % 3 ) * "0" ) + s
- # Drop the last three digits -- 1000 files per directory
- padded = padded[:-3]
- # Break into chunks of three
- return [ padded[i*3:(i+1)*3] for i in range( len( padded ) // 3 ) ]
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -9,14 +9,19 @@
import shutil
import logging
import threading
+from xml.etree import ElementTree
-from galaxy import util
+from galaxy.util import umask_fix_perms, force_symlink
from galaxy.exceptions import ObjectInvalid, ObjectNotFound
-from galaxy.jobs import Sleeper
-from galaxy.model import directory_hash_id
+from galaxy.util.sleeper import Sleeper
+from galaxy.util.directory_hash import directory_hash_id
from galaxy.util.odict import odict
+try:
+ from sqlalchemy.orm import object_session
+except ImportError:
+ object_session = None
-from sqlalchemy.orm import object_session
+NO_SESSION_ERROR_MESSAGE = "Attempted to 'create' object store entity in configuration with no database session present."
log = logging.getLogger( __name__ )
@@ -202,7 +207,7 @@
self.extra_dirs['job_work'] = config.job_working_directory
self.extra_dirs['temp'] = config.new_file_path
#The new config_xml overrides universe settings.
- if config_xml:
+ if config_xml is not None:
for e in config_xml:
if e.tag == 'files_dir':
self.file_path = e.get('path')
@@ -290,8 +295,8 @@
os.makedirs(dir)
# Create the file if it does not exist
if not dir_only:
- open(path, 'w').close()
- util.umask_fix_perms(path, self.config.umask, 0666)
+ open(path, 'w').close() # Should be rb?
+ umask_fix_perms(path, self.config.umask, 0666)
def empty(self, obj, **kwargs):
return os.path.getsize(self.get_filename(obj, **kwargs)) == 0
@@ -320,7 +325,7 @@
return False
def get_data(self, obj, start=0, count=-1, **kwargs):
- data_file = open(self.get_filename(obj, **kwargs), 'r')
+ data_file = open(self.get_filename(obj, **kwargs), 'r') # Should be rb?
data_file.seek(start)
content = data_file.read(count)
data_file.close()
@@ -345,7 +350,7 @@
if file_name and self.exists(obj, **kwargs):
try:
if preserve_symlinks and os.path.islink( file_name ):
- util.force_symlink( os.readlink( file_name ), self.get_filename( obj, **kwargs ) )
+ force_symlink( os.readlink( file_name ), self.get_filename( obj, **kwargs ) )
else:
shutil.copy( file_name, self.get_filename( obj, **kwargs ) )
except IOError, ex:
@@ -358,7 +363,7 @@
def get_store_usage_percent(self):
st = os.statvfs(self.file_path)
- return (float(st.f_blocks - st.f_bavail)/st.f_blocks) * 100
+ return ( float( st.f_blocks - st.f_bavail ) / st.f_blocks ) * 100
class CachingObjectStore(ObjectStore):
@@ -428,7 +433,7 @@
return store.__getattribute__(method)(obj, **kwargs)
if default_is_exception:
raise default( 'objectstore, __call_method failed: %s on %s, kwargs: %s'
- %( method, str( obj ), str( kwargs ) ) )
+ % ( method, str( obj ), str( kwargs ) ) )
else:
return default
@@ -442,7 +447,7 @@
def __init__(self, config, config_xml=None, fsmon=False):
super(DistributedObjectStore, self).__init__(config, config_xml=config_xml)
- if not config_xml:
+ if config_xml is None:
self.distributed_config = config.distributed_object_store_config_file
assert self.distributed_config is not None, "distributed object store ('object_store = distributed') " \
"requires a config file, please set one in " \
@@ -462,10 +467,9 @@
self.filesystem_monitor_thread.start()
log.info("Filesystem space monitor started")
- def __parse_distributed_config(self, config, config_xml = None):
- if not config_xml:
- tree = util.parse_xml(self.distributed_config)
- root = tree.getroot()
+ def __parse_distributed_config(self, config, config_xml=None):
+ if config_xml is None:
+ root = ElementTree.parse(self.distributed_config).getroot()
log.debug('Loading backends for distributed object store from %s' % self.distributed_config)
else:
root = config_xml.find('backends')
@@ -512,7 +516,7 @@
if pct > maxpct:
new_weighted_backend_ids = filter(lambda x: x != id, new_weighted_backend_ids)
self.weighted_backend_ids = new_weighted_backend_ids
- self.sleeper.sleep(120) # Test free space every 2 minutes
+ self.sleeper.sleep(120) # Test free space every 2 minutes
def create(self, obj, **kwargs):
"""
@@ -524,9 +528,8 @@
obj.object_store_id = random.choice(self.weighted_backend_ids)
except IndexError:
raise ObjectInvalid( 'objectstore.create, could not generate obj.object_store_id: %s, kwargs: %s'
- %( str( obj ), str( kwargs ) ) )
- object_session( obj ).add( obj )
- object_session( obj ).flush()
+ % ( str( obj ), str( kwargs ) ) )
+ create_object_in_session( obj )
log.debug("Selected backend '%s' for creation of %s %s" % (obj.object_store_id, obj.__class__.__name__, obj.id))
else:
log.debug("Using preferred backend '%s' for creation of %s %s" % (obj.object_store_id, obj.__class__.__name__, obj.id))
@@ -538,7 +541,7 @@
return self.backends[object_store_id].__getattribute__(method)(obj, **kwargs)
if default_is_exception:
raise default( 'objectstore, __call_method failed: %s on %s, kwargs: %s'
- %( method, str( obj ), str( kwargs ) ) )
+ % ( method, str( obj ), str( kwargs ) ) )
else:
return default
@@ -554,8 +557,7 @@
if store.exists(obj, **kwargs):
log.warning('%s object with ID %s found in backend object store with ID %s' % (obj.__class__.__name__, obj.id, id))
obj.object_store_id = id
- object_session( obj ).add( obj )
- object_session( obj ).flush()
+ create_object_in_session( obj )
return id
return None
@@ -594,15 +596,14 @@
Depending on the configuration setting, invoke the appropriate object store
"""
- if not config_xml and config.object_store_config_file:
+ if config_xml is None and config.object_store_config_file:
# This is a top level invocation of build_object_store_from_config, and
# we have an object_store_conf.xml -- read the .xml and build
# accordingly
- tree = util.parse_xml(config.object_store_config_file)
- root = tree.getroot()
+ root = ElementTree.parse(config.object_store_config_file).getroot()
store = root.get('type')
config_xml = root
- elif config_xml:
+ elif config_xml is not None:
store = config_xml.get('type')
else:
store = config.object_store
@@ -610,21 +611,25 @@
if store == 'disk':
return DiskObjectStore(config=config, config_xml=config_xml)
elif store == 's3':
- from galaxy.objectstore.s3 import S3ObjectStore
+ from .s3 import S3ObjectStore
return S3ObjectStore(config=config, config_xml=config_xml)
elif store == 'swift':
- from galaxy.objectstore.s3 import SwiftObjectStore
+ from .s3 import SwiftObjectStore
return SwiftObjectStore(config=config, config_xml=config_xml)
elif store == 'distributed':
return DistributedObjectStore(config=config, fsmon=fsmon, config_xml=config_xml)
elif store == 'hierarchical':
return HierarchicalObjectStore(config=config, config_xml=config_xml)
elif store == 'irods':
- from galaxy.objectstore.rods import IRODSObjectStore
+ from .rods import IRODSObjectStore
return IRODSObjectStore(config=config, config_xml=config_xml)
+ elif store == 'lwr':
+ from .lwr import LwrObjectStore
+ return LwrObjectStore(config=config, config_xml=config_xml)
else:
log.error("Unrecognized object store definition: {0}".format(store))
+
def local_extra_dirs( func ):
""" A decorator for non-local plugins to utilize local directories for their extra_dirs (job_working_directory and temp).
"""
@@ -638,6 +643,7 @@
raise Exception( "Could not call DiskObjectStore's %s method, does your Object Store plugin inherit from DiskObjectStore?" % func.__name__ )
return wraps
+
def convert_bytes(bytes):
""" A helper function used for pretty printing disk usage """
if bytes is None:
@@ -659,3 +665,12 @@
else:
size = '%.2fb' % bytes
return size
+
+
+def create_object_in_session( obj ):
+ session = object_session( obj ) if object_session is not None else None
+ if session is not None:
+ object_session( obj ).add( obj )
+ object_session( obj ).flush()
+ else:
+ raise Exception( NO_SESSION_ERROR_MESSAGE )
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/objectstore/lwr.py
--- /dev/null
+++ b/lib/galaxy/objectstore/lwr.py
@@ -0,0 +1,76 @@
+from __future__ import absolute_import # Need to import lwr_client absolutely.
+from ..objectstore import ObjectStore
+try:
+ from galaxy.jobs.runners.lwr_client.manager import ObjectStoreClientManager
+except ImportError:
+ from lwr.lwr_client.manager import ObjectStoreClientManager
+
+
+class LwrObjectStore(ObjectStore):
+ """
+ Object store implementation that delegates to a remote LWR server.
+
+ This may be more aspirational than practical for now, it would be good to
+ Galaxy to a point that a handler thread could be setup that doesn't attempt
+ to access the disk files returned by a (this) object store - just passing
+ them along to the LWR unmodified. That modification - along with this
+ implementation and LWR job destinations would then allow Galaxy to fully
+ manage jobs on remote servers with completely different mount points.
+
+ This implementation should be considered beta and may be dropped from
+ Galaxy at some future point or significantly modified.
+ """
+
+ def __init__(self, config, config_xml):
+ self.lwr_client = self.__build_lwr_client(config_xml)
+
+ def exists(self, obj, **kwds):
+ return self.lwr_client.exists(**self.__build_kwds(obj, **kwds))
+
+ def file_ready(self, obj, **kwds):
+ return self.lwr_client.file_ready(**self.__build_kwds(obj, **kwds))
+
+ def create(self, obj, **kwds):
+ return self.lwr_client.create(**self.__build_kwds(obj, **kwds))
+
+ def empty(self, obj, **kwds):
+ return self.lwr_client.empty(**self.__build_kwds(obj, **kwds))
+
+ def size(self, obj, **kwds):
+ return self.lwr_client.size(**self.__build_kwds(obj, **kwds))
+
+ def delete(self, obj, **kwds):
+ return self.lwr_client.delete(**self.__build_kwds(obj, **kwds))
+
+ # TODO: Optimize get_data.
+ def get_data(self, obj, **kwds):
+ return self.lwr_client.get_data(**self.__build_kwds(obj, **kwds))
+
+ def get_filename(self, obj, **kwds):
+ return self.lwr_client.get_filename(**self.__build_kwds(obj, **kwds))
+
+ def update_from_file(self, obj, **kwds):
+ return self.lwr_client.update_from_file(**self.__build_kwds(obj, **kwds))
+
+ def get_store_usage_percent(self):
+ return self.lwr_client.get_store_usage_percent()
+
+ def get_object_url(self, obj, extra_dir=None, extra_dir_at_root=False, alt_name=None):
+ return None
+
+ def __build_kwds(self, obj, **kwds):
+ kwds['object_id'] = obj.id
+ return kwds
+ pass
+
+ def __build_lwr_client(self, config_xml):
+ url = config_xml.get("url")
+ private_token = config_xml.get("private_token", None)
+ transport = config_xml.get("transport", None)
+ manager_options = dict(transport=transport)
+ client_options = dict(url=url, private_token=private_token)
+ lwr_client = ObjectStoreClientManager(**manager_options).get_client(client_options)
+ return lwr_client
+
+ def shutdown(self):
+ pass
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/objectstore/rods.py
--- a/lib/galaxy/objectstore/rods.py
+++ b/lib/galaxy/objectstore/rods.py
@@ -12,12 +12,17 @@
from posixpath import basename as path_basename
from posixpath import dirname as path_dirname
-from galaxy.objectstore import DiskObjectStore, ObjectStore, local_extra_dirs
from galaxy.exceptions import ObjectNotFound
+from ..objectstore import DiskObjectStore, ObjectStore, local_extra_dirs
-import galaxy.eggs
-galaxy.eggs.require( 'PyRods' )
-import irods
+try:
+ import galaxy.eggs
+ galaxy.eggs.require( 'PyRods' )
+ import irods
+except ImportError:
+ irods = None
+
+NO_PYRODS_ERROR_MESSAGE = "IRODS object store configured, but no PyRods dependency available. Please install and properly configure PyRods or modify object store configuration."
log = logging.getLogger( __name__ )
@@ -27,6 +32,8 @@
Galaxy object store based on iRODS
"""
def __init__( self, config, file_path=None, extra_dirs=None ):
+ if irods is None:
+ raise Exception(NO_PYRODS_ERROR_MESSAGE)
super( IRODSObjectStore, self ).__init__( config, file_path=file_path, extra_dirs=extra_dirs )
self.cache_path = config.object_store_cache_path
self.default_resource = config.irods_default_resource or None
@@ -146,7 +153,7 @@
doi = irods.dataObjInp_t()
doi.objPath = rods_path
doi.createMode = 0640
- doi.dataSize = 0 # 0 actually means "unknown", although literally 0 would be preferable
+ doi.dataSize = 0 # 0 actually means "unknown", although literally 0 would be preferable
irods.addKeyVal( doi.condInput, irods.DEST_RESC_NAME_KW, self.default_resource )
status = irods.rcDataObjCreate( self.rods_conn, doi )
assert status >= 0, 'create(): rcDataObjCreate() failed: %s: %s: %s' % ( rods_path, status, irods.strerror( status ) )
@@ -237,7 +244,7 @@
incoming_path = os.path.join( os.path.dirname( cached_path ), "__incoming_%s" % os.path.basename( cached_path ) )
doi = irods.dataObjInp_t()
doi.objPath = self.__get_rods_path( obj, **kwargs )
- doi.dataSize = 0 # TODO: does this affect performance? should we get size?
+ doi.dataSize = 0 # TODO: does this affect performance? should we get size?
doi.numThreads = 0
# TODO: might want to VERIFY_CHKSUM_KW
log.debug( 'get_filename(): caching %s to %s', doi.objPath, incoming_path )
@@ -296,6 +303,7 @@
def get_store_usage_percent(self):
return 0.0
+
# monkeypatch an strerror method into the irods module
def _rods_strerror( errno ):
"""
@@ -309,7 +317,9 @@
irods.__rods_strerror_map[ v ] = name
return irods.__rods_strerror_map.get( errno, 'GALAXY_NO_ERRNO_MAPPING_FOUND' )
-irods.strerror = _rods_strerror
+if irods is not None:
+ irods.strerror = _rods_strerror
+
def rods_connect():
"""
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/objectstore/s3.py
--- a/lib/galaxy/objectstore/s3.py
+++ b/lib/galaxy/objectstore/s3.py
@@ -10,21 +10,26 @@
import subprocess
from datetime import datetime
-from galaxy import util
-from galaxy.jobs import Sleeper
-from galaxy.model import directory_hash_id
-from galaxy.objectstore import ObjectStore, convert_bytes
+from galaxy.util import umask_fix_perms
+from galaxy.util.sleeper import Sleeper
+from galaxy.util.directory_hash import directory_hash_id
+from ..objectstore import ObjectStore, convert_bytes
from galaxy.exceptions import ObjectNotFound
import multiprocessing
-from galaxy.objectstore.s3_multipart_upload import multipart_upload
-import boto
-from boto.s3.key import Key
-from boto.s3.connection import S3Connection
-from boto.exception import S3ResponseError
+from .s3_multipart_upload import multipart_upload
+try:
+ import boto
+ from boto.s3.key import Key
+ from boto.s3.connection import S3Connection
+ from boto.exception import S3ResponseError
+except ImportError:
+ boto = None
+
+NO_BOTO_ERROR_MESSAGE = "S3/Swift object store configured, but no boto dependency available. Please install and properly configure boto or modify object store configuration."
log = logging.getLogger( __name__ )
-logging.getLogger('boto').setLevel(logging.INFO) # Otherwise boto is quite noisy
+logging.getLogger('boto').setLevel(logging.INFO) # Otherwise boto is quite noisy
class S3ObjectStore(ObjectStore):
@@ -34,6 +39,8 @@
Galaxy and S3.
"""
def __init__(self, config, config_xml):
+ if boto is None:
+ raise Exception(NO_BOTO_ERROR_MESSAGE)
super(S3ObjectStore, self).__init__(config, config_xml)
self.config = config
self.staging_path = self.config.file_path
@@ -82,7 +89,7 @@
raise
def __cache_monitor(self):
- time.sleep(2) # Wait for things to load before starting the monitor
+ time.sleep(2) # Wait for things to load before starting the monitor
while self.running:
total_size = 0
# Is this going to be too expensive of an operation to be done frequently?
@@ -110,7 +117,7 @@
# For now, delete enough to leave at least 10% of the total cache free
delete_this_much = total_size - cache_limit
self.__clean_cache(file_list, delete_this_much)
- self.sleeper.sleep(30) # Test cache size every 30 seconds?
+ self.sleeper.sleep(30) # Test cache size every 30 seconds?
def __clean_cache(self, file_list, delete_this_much):
""" Keep deleting files from the file_list until the size of the deleted
@@ -154,7 +161,7 @@
log.debug("Using cloud object store with bucket '%s'" % bucket.name)
return bucket
except S3ResponseError:
- log.debug("Could not get bucket '%s', attempt %s/5" % (bucket_name, i+1))
+ log.debug("Could not get bucket '%s', attempt %s/5" % (bucket_name, i + 1))
time.sleep(2)
# All the attempts have been exhausted and connection was not established,
# raise error
@@ -163,13 +170,13 @@
def _fix_permissions(self, rel_path):
""" Set permissions on rel_path"""
for basedir, dirs, files in os.walk(rel_path):
- util.umask_fix_perms(basedir, self.config.umask, 0777, self.config.gid)
+ umask_fix_perms(basedir, self.config.umask, 0777, self.config.gid)
for f in files:
path = os.path.join(basedir, f)
# Ignore symlinks
if os.path.islink(path):
continue
- util.umask_fix_perms( path, self.config.umask, 0666, self.config.gid )
+ umask_fix_perms( path, self.config.umask, 0666, self.config.gid )
def _construct_path(self, obj, dir_only=None, extra_dir=None, extra_dir_at_root=False, alt_name=None, **kwargs):
rel_path = os.path.join(*directory_hash_id(obj.id))
@@ -283,7 +290,7 @@
return True
else:
log.debug("Pulled key '%s' into cache to %s" % (rel_path, self._get_cache_path(rel_path)))
- self.transfer_progress = 0 # Reset transfer progress counter
+ self.transfer_progress = 0 # Reset transfer progress counter
key.get_contents_to_filename(self._get_cache_path(rel_path), cb=self._transfer_cb, num_cb=10)
return True
except S3ResponseError, ex:
@@ -315,14 +322,14 @@
mb_size = os.path.getsize(source_file) / 1e6
#DBTODO Hack, refactor this logic.
if mb_size < 60 or type(self) == SwiftObjectStore:
- self.transfer_progress = 0 # Reset transfer progress counter
+ self.transfer_progress = 0 # Reset transfer progress counter
key.set_contents_from_filename(source_file, reduced_redundancy=self.use_rr,
cb=self._transfer_cb, num_cb=10)
else:
multipart_upload(self.bucket, key.name, source_file, mb_size, use_rr=self.use_rr)
end_time = datetime.now()
# print "+ Push ended at '%s'; %s bytes transfered in %ssec" % (end_time, os.path.getsize(source_file), end_time-start_time)
- log.debug("Pushed cache file '%s' to key '%s' (%s bytes transfered in %s sec)" % (source_file, rel_path, os.path.getsize(source_file), end_time-start_time))
+ log.debug("Pushed cache file '%s' to key '%s' (%s bytes transfered in %s sec)" % (source_file, rel_path, os.path.getsize(source_file), end_time - start_time))
return True
else:
log.error("Tried updating key '%s' from source file '%s', but source file does not exist."
@@ -408,7 +415,7 @@
return bool(self.size(obj, **kwargs) > 0)
else:
raise ObjectNotFound( 'objectstore.empty, object does not exist: %s, kwargs: %s'
- %( str( obj ), str( kwargs ) ) )
+ % ( str( obj ), str( kwargs ) ) )
def size(self, obj, **kwargs):
rel_path = self._construct_path(obj, **kwargs)
@@ -484,7 +491,7 @@
return cache_path
# Check if the file exists in persistent storage and, if it does, pull it into cache
elif self.exists(obj, **kwargs):
- if dir_only: # Directories do not get pulled into cache
+ if dir_only: # Directories do not get pulled into cache
return cache_path
else:
if self._pull_into_cache(rel_path):
@@ -494,7 +501,7 @@
# if dir_only:
# return cache_path
raise ObjectNotFound( 'objectstore.get_filename, no cache_path: %s, kwargs: %s'
- %( str( obj ), str( kwargs ) ) )
+ % ( str( obj ), str( kwargs ) ) )
# return cache_path # Until the upload tool does not explicitly create the dataset, return expected path
def update_from_file(self, obj, file_name=None, create=False, **kwargs):
@@ -520,14 +527,14 @@
self._push_to_os(rel_path, source_file)
else:
raise ObjectNotFound( 'objectstore.update_from_file, object does not exist: %s, kwargs: %s'
- %( str( obj ), str( kwargs ) ) )
+ % ( str( obj ), str( kwargs ) ) )
def get_object_url(self, obj, **kwargs):
if self.exists(obj, **kwargs):
rel_path = self._construct_path(obj, **kwargs)
try:
key = Key(self.bucket, rel_path)
- return key.generate_url(expires_in = 86400) # 24hrs
+ return key.generate_url(expires_in=86400) # 24hrs
except S3ResponseError, ex:
log.warning("Trouble generating URL for dataset '%s': %s" % (rel_path, ex))
return None
@@ -552,4 +559,3 @@
port=self.port,
calling_format=boto.s3.connection.OrdinaryCallingFormat(),
path=self.conn_path)
-
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/objectstore/s3_multipart_upload.py
--- a/lib/galaxy/objectstore/s3_multipart_upload.py
+++ b/lib/galaxy/objectstore/s3_multipart_upload.py
@@ -4,10 +4,8 @@
This parallelizes the task over available cores using multiprocessing.
Code mostly taken form CloudBioLinux.
"""
-from __future__ import with_statement
import os
-import sys
import glob
import subprocess
import contextlib
@@ -16,10 +14,17 @@
import multiprocessing
from multiprocessing.pool import IMapIterator
-from galaxy import eggs
-eggs.require('boto')
+try:
+ from galaxy import eggs
+ eggs.require('boto')
+except ImportError:
+ pass
-import boto
+try:
+ import boto
+except ImportError:
+ boto = None
+
def map_wrap(f):
@functools.wraps(f)
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/util/directory_hash.py
--- /dev/null
+++ b/lib/galaxy/util/directory_hash.py
@@ -0,0 +1,23 @@
+
+
+def directory_hash_id( id ):
+ """
+
+ >>> directory_hash_id( 100 )
+ ['000']
+ >>> directory_hash_id( "90000" )
+ ['090']
+ >>> directory_hash_id("777777777")
+ ['000', '777', '777']
+ """
+ s = str( id )
+ l = len( s )
+ # Shortcut -- ids 0-999 go under ../000/
+ if l < 4:
+ return [ "000" ]
+ # Pad with zeros until a multiple of three
+ padded = ( ( 3 - len( s ) % 3 ) * "0" ) + s
+ # Drop the last three digits -- 1000 files per directory
+ padded = padded[:-3]
+ # Break into chunks of three
+ return [ padded[ i * 3 : (i + 1 ) * 3 ] for i in range( len( padded ) // 3 ) ]
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f lib/galaxy/util/sleeper.py
--- /dev/null
+++ b/lib/galaxy/util/sleeper.py
@@ -0,0 +1,22 @@
+import threading
+
+
+class Sleeper( object ):
+ """
+ Provides a 'sleep' method that sleeps for a number of seconds *unless*
+ the notify method is called (from a different thread).
+ """
+ def __init__( self ):
+ self.condition = threading.Condition()
+
+ def sleep( self, seconds ):
+ # Should this be in a try/finally block? -John
+ self.condition.acquire()
+ self.condition.wait( seconds )
+ self.condition.release()
+
+ def wake( self ):
+ # Should this be in a try/finally block? -John
+ self.condition.acquire()
+ self.condition.notify()
+ self.condition.release()
diff -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 -r a540510a3091ad7cfe3c4680c8bb04a20679e44f test/unit/test_objectstore.py
--- /dev/null
+++ b/test/unit/test_objectstore.py
@@ -0,0 +1,210 @@
+import os
+from shutil import rmtree
+from string import Template
+from tempfile import mkdtemp
+try:
+ from galaxy import objectstore
+except ImportError:
+ from lwr import objectstore
+from contextlib import contextmanager
+
+DISK_TEST_CONFIG = """<?xml version="1.0"?>
+<object_store type="disk">
+ <files_dir path="${temp_directory}/files1"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp1"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory1"/>
+</object_store>
+"""
+
+
+def test_disk_store():
+ with TestConfig(DISK_TEST_CONFIG) as (directory, object_store):
+ # Test no dataset with id 1 exists.
+ absent_dataset = MockDataset(1)
+ assert not object_store.exists(absent_dataset)
+
+ # Write empty dataset 2 in second backend, ensure it is empty and
+ # exists.
+ empty_dataset = MockDataset(2)
+ directory.write(b"", "files1/000/dataset_2.dat")
+ assert object_store.exists(empty_dataset)
+ assert object_store.empty(empty_dataset)
+
+ # Write non-empty dataset in backend 1, test it is not emtpy & exists.
+ hello_world_dataset = MockDataset(3)
+ directory.write(b"Hello World!", "files1/000/dataset_3.dat")
+ assert object_store.exists(hello_world_dataset)
+ assert not object_store.empty(hello_world_dataset)
+
+ # Test get_data
+ data = object_store.get_data(hello_world_dataset)
+ assert data == b"Hello World!"
+
+ data = object_store.get_data(hello_world_dataset, start=1, count=6)
+ assert data == b"ello W"
+
+ # Test Size
+
+ # Test absent and empty datasets yield size of 0.
+ assert object_store.size(absent_dataset) == 0
+ assert object_store.size(empty_dataset) == 0
+ # Elsewise
+ assert object_store.size(hello_world_dataset) > 0 # Should this always be the number of bytes?
+
+ # Test percent used (to some degree)
+ percent_store_used = object_store.get_store_usage_percent()
+ assert percent_store_used > 0.0
+ assert percent_store_used < 100.0
+
+ # Test update_from_file test
+ output_dataset = MockDataset(4)
+ output_real_path = os.path.join(directory.temp_directory, "files1", "000", "dataset_4.dat")
+ assert not os.path.exists(output_real_path)
+ output_working_path = directory.write(b"NEW CONTENTS", "job_working_directory1/example_output")
+ object_store.update_from_file(output_dataset, file_name=output_working_path, create=True)
+ assert os.path.exists(output_real_path)
+
+ # Test delete
+ to_delete_dataset = MockDataset(5)
+ to_delete_real_path = directory.write(b"content to be deleted!", "files1/000/dataset_5.dat")
+ assert object_store.exists(to_delete_dataset)
+ assert object_store.delete(to_delete_dataset)
+ assert not object_store.exists(to_delete_dataset)
+ assert not os.path.exists(to_delete_real_path)
+
+
+HIERARCHICAL_TEST_CONFIG = """<?xml version="1.0"?>
+<object_store type="hierarchical">
+ <backends>
+ <backend id="files1" type="disk" weight="1" order="0">
+ <files_dir path="${temp_directory}/files1"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp1"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory1"/>
+ </backend>
+ <backend id="files2" type="disk" weight="1" order="1">
+ <files_dir path="${temp_directory}/files2"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp2"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory2"/>
+ </backend>
+ </backends>
+</object_store>
+"""
+
+
+def test_hierarchical_store():
+ with TestConfig(HIERARCHICAL_TEST_CONFIG) as (directory, object_store):
+
+ # Test no dataset with id 1 exists.
+ assert not object_store.exists(MockDataset(1))
+
+ # Write empty dataset 2 in second backend, ensure it is empty and
+ # exists.
+ directory.write("", "files2/000/dataset_2.dat")
+ assert object_store.exists(MockDataset(2))
+ assert object_store.empty(MockDataset(2))
+
+ # Write non-empty dataset in backend 1, test it is not emtpy & exists.
+ directory.write("Hello World!", "files1/000/dataset_3.dat")
+ assert object_store.exists(MockDataset(3))
+ assert not object_store.empty(MockDataset(3))
+
+ # Assert creation always happens in first backend.
+ for i in range(100):
+ dataset = MockDataset(100 + i)
+ object_store.create(dataset)
+ assert object_store.get_filename(dataset).find("files1") > 0
+
+
+DISTRIBUTED_TEST_CONFIG = """<?xml version="1.0"?>
+<object_store type="distributed">
+ <backends>
+ <backend id="files1" type="disk" weight="2" order="0">
+ <files_dir path="${temp_directory}/files1"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp1"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory1"/>
+ </backend>
+ <backend id="files2" type="disk" weight="1" order="1">
+ <files_dir path="${temp_directory}/files2"/>
+ <extra_dir type="temp" path="${temp_directory}/tmp2"/>
+ <extra_dir type="job_work" path="${temp_directory}/job_working_directory2"/>
+ </backend>
+ </backends>
+</object_store>
+"""
+
+
+def test_distributed_store():
+ with TestConfig(DISTRIBUTED_TEST_CONFIG) as (directory, object_store):
+ with __stubbed_persistence() as persisted_ids:
+ for i in range(100):
+ dataset = MockDataset(100 + i)
+ object_store.create(dataset)
+
+ ## Test distributes datasets between backends according to weights
+ backend_1_count = len([v for v in persisted_ids.values() if v == "files1"])
+ backend_2_count = len([v for v in persisted_ids.values() if v == "files2"])
+
+ assert backend_1_count > 0
+ assert backend_2_count > 0
+ assert backend_1_count > backend_2_count
+
+
+class TestConfig(object):
+ def __init__(self, config_xml):
+ self.temp_directory = mkdtemp()
+ self.write(config_xml, "store.xml")
+ config = MockConfig(self.temp_directory)
+ self.object_store = objectstore.build_object_store_from_config(config)
+
+ def __enter__(self):
+ return self, self.object_store
+
+ def __exit__(self, type, value, tb):
+ rmtree(self.temp_directory)
+
+ def write(self, contents, name):
+ path = os.path.join(self.temp_directory, name)
+ directory = os.path.dirname(path)
+ if not os.path.exists(directory):
+ os.makedirs(directory)
+ expanded_contents = Template(contents).safe_substitute(temp_directory=self.temp_directory)
+ open(path, "w").write(expanded_contents)
+ return path
+
+
+class MockConfig(object):
+
+ def __init__(self, temp_directory):
+ self.file_path = temp_directory
+ self.object_store_config_file = os.path.join(temp_directory, "store.xml")
+ self.object_store_check_old_style = False
+ self.job_working_directory = temp_directory
+ self.new_file_path = temp_directory
+ self.umask = 0000
+
+
+class MockDataset(object):
+
+ def __init__(self, id):
+ self.id = id
+ self.object_store_id = None
+
+
+## Poor man's mocking. Need to get a real mocking library as real Galaxy development
+## dependnecy.
+PERSIST_METHOD_NAME = "create_object_in_session"
+
+
+@contextmanager
+def __stubbed_persistence():
+ real_method = getattr(objectstore, PERSIST_METHOD_NAME)
+ try:
+ persisted_ids = {}
+
+ def persist(object):
+ persisted_ids[object.id] = object.object_store_id
+ setattr(objectstore, PERSIST_METHOD_NAME, persist)
+ yield persisted_ids
+
+ finally:
+ setattr(objectstore, PERSIST_METHOD_NAME, real_method)
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Refactoring code cleanup for installing tool dependencies from the tool shed into Galaxy.
by commits-noreply@bitbucket.org 03 Dec '13
by commits-noreply@bitbucket.org 03 Dec '13
03 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3116103966fa/
Changeset: 3116103966fa
User: greg
Date: 2013-12-03 17:01:20
Summary: Refactoring code cleanup for installing tool dependencies from the tool shed into Galaxy.
Affected #: 4 files
diff -r dd53fe2a3e7308ccd7a007f78ae6e29b7eff9ef0 -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -3631,6 +3631,11 @@
return False
@property
+ def is_deactivated_or_installed( self ):
+ return self.status in [ self.installation_status.DEACTIVATED,
+ self.installation_status.INSTALLED ]
+
+ @property
def is_latest_installable_revision( self ):
if self.tool_shed_status:
return galaxy.util.asbool( self.tool_shed_status.get( 'latest_installable_revision', False ) )
diff -r dd53fe2a3e7308ccd7a007f78ae6e29b7eff9ef0 -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -37,11 +37,30 @@
def append_line( self, skip_if_contained=True, make_executable=True, **kwd ):
env_var_dict = dict( **kwd )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( self.install_dir, env_var_dict )
+ env_entry, env_file = self.create_or_update_env_shell_file( self.install_dir, env_var_dict )
return_code = file_append( env_entry, env_file, skip_if_contained=skip_if_contained, make_executable=make_executable )
self.return_code = self.return_code or return_code
return self.return_code
+ def create_or_update_env_shell_file( self, install_dir, env_var_dict ):
+ env_var_action = env_var_dict[ 'action' ]
+ env_var_value = env_var_dict[ 'value' ]
+ if env_var_action in [ 'prepend_to', 'set_to', 'append_to' ]:
+ env_var_name = env_var_dict[ 'name' ]
+ if env_var_action == 'prepend_to':
+ changed_value = '%s:$%s' % ( env_var_value, env_var_name )
+ elif env_var_action == 'set_to':
+ changed_value = '%s' % env_var_value
+ elif env_var_action == 'append_to':
+ changed_value = '$%s:%s' % ( env_var_name, env_var_value )
+ line = "%s=%s; export %s" % ( env_var_name, changed_value, env_var_name )
+ elif env_var_action == "source":
+ line = ". %s" % env_var_value
+ else:
+ raise Exception( "Unknown shell file action %s" % env_var_action )
+ env_shell_file_path = os.path.join( install_dir, 'env.sh' )
+ return line, env_shell_file_path
+
class InstallEnvironment( object ):
"""Object describing the environment built up as part of the process of building and installing a package."""
diff -r dd53fe2a3e7308ccd7a007f78ae6e29b7eff9ef0 -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 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
@@ -216,7 +216,7 @@
if can_install_tool_dependency:
# Set this dependent repository's tool dependency env.sh file with a path to the required repository's installed tool dependency package.
# We can get everything we need from the discovered installed required_repository.
- if required_repository.is_installed:
+ if required_repository.is_deactivated_or_installed:
if not os.path.exists( required_repository_package_install_dir ):
print 'Missing required tool dependency directory %s' % str( required_repository_package_install_dir )
repo_files_dir = required_repository.repo_files_directory( app )
@@ -848,20 +848,29 @@
type='set_environment',
status=app.model.ToolDependency.installation_status.INSTALLING,
set_status=True )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, env_var_dict )
if env_var_version == '1.0':
- # Handle setting environment variables using a fabric method.
- fabric_util.file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
- sa_session.refresh( tool_dependency )
- if tool_dependency.status not in [ app.model.ToolDependency.installation_status.ERROR,
- app.model.ToolDependency.installation_status.INSTALLED ]:
+ # Create this tool dependency's env.sh file.
+ env_file_builder = fabric_util.EnvFileBuilder( install_dir )
+ return_code = env_file_builder.append_line( skip_if_contained=True, make_executable=True, **env_var_dict )
+ if return_code:
+ error_message = 'Error creating env.sh file for tool dependency %s, return_code: %s' % \
+ ( str( tool_dependency.name ), str( return_code ) )
+ log.debug( error_message )
tool_dependency = tool_dependency_util.set_tool_dependency_attributes( app,
tool_dependency=tool_dependency,
- status=app.model.ToolDependency.installation_status.INSTALLED,
- error_message=None,
+ status=app.model.ToolDependency.installation_status.ERROR,
+ error_message=error_message,
remove_from_disk=False )
- log.debug( 'Environment variable %s set in %s for tool dependency %s.' % \
- ( str( env_var_name ), str( install_dir ), str( tool_dependency.name ) ) )
+ else:
+ if tool_dependency.status not in [ app.model.ToolDependency.installation_status.ERROR,
+ app.model.ToolDependency.installation_status.INSTALLED ]:
+ tool_dependency = tool_dependency_util.set_tool_dependency_attributes( app,
+ tool_dependency=tool_dependency,
+ status=app.model.ToolDependency.installation_status.INSTALLED,
+ error_message=None,
+ remove_from_disk=False )
+ log.debug( 'Environment variable %s set in %s for tool dependency %s.' % \
+ ( str( env_var_name ), str( install_dir ), str( tool_dependency.name ) ) )
else:
error_message = 'Only set_environment version 1.0 is currently supported (i.e., change your tag to be <set_environment version="1.0">).'
tool_dependency = tool_dependency_util.set_tool_dependency_attributes( app,
diff -r dd53fe2a3e7308ccd7a007f78ae6e29b7eff9ef0 -r 3116103966fa1cd6c942aa918bcd647f39c0aae3 lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
@@ -145,25 +145,6 @@
return dict( name=env_var_name, action=env_var_action, value=elem.text)
return None
-def create_or_update_env_shell_file( install_dir, env_var_dict ):
- env_var_action = env_var_dict[ 'action' ]
- env_var_value = env_var_dict[ 'value' ]
- if env_var_action in ['prepend_to', 'set_to', 'append_to']:
- env_var_name = env_var_dict[ 'name' ]
- if env_var_action == 'prepend_to':
- changed_value = '%s:$%s' % ( env_var_value, env_var_name )
- elif env_var_action == 'set_to':
- changed_value = '%s' % env_var_value
- elif env_var_action == 'append_to':
- changed_value = '$%s:%s' % ( env_var_name, env_var_value )
- line = "%s=%s; export %s" % ( env_var_name, changed_value, env_var_name )
- elif env_var_action == "source":
- line = ". %s" % env_var_value
- else:
- raise Exception( "Unknown shell file action %s" % env_var_action )
- env_shell_file_path = os.path.join( install_dir, 'env.sh' )
- return line, env_shell_file_path
-
def download_binary( url, work_dir ):
'''
Download a pre-compiled binary from the specified URL.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Fix for determining if a required tool dependency is in an error state.
by commits-noreply@bitbucket.org 03 Dec '13
by commits-noreply@bitbucket.org 03 Dec '13
03 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/dd53fe2a3e73/
Changeset: dd53fe2a3e73
User: greg
Date: 2013-12-03 15:35:05
Summary: Fix for determining if a required tool dependency is in an error state.
Affected #: 2 files
diff -r a62c54ddbe2a845be9f0ee2dc4fe4b5820bcd70c -r dd53fe2a3e7308ccd7a007f78ae6e29b7eff9ef0 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -3631,11 +3631,6 @@
return False
@property
- def is_installed( self ):
- return self.status in [ self.installation_status.DEACTIVATED,
- self.installation_status.INSTALLED ]
-
- @property
def is_latest_installable_revision( self ):
if self.tool_shed_status:
return galaxy.util.asbool( self.tool_shed_status.get( 'latest_installable_revision', False ) )
diff -r a62c54ddbe2a845be9f0ee2dc4fe4b5820bcd70c -r dd53fe2a3e7308ccd7a007f78ae6e29b7eff9ef0 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
@@ -98,9 +98,9 @@
tool_dependency,
error_message,
remove_installation_path=False )
- elif required_tool_dependency.in_error_state:
- error_message = "This tool dependency's required tool dependency %s has status %s." % \
- ( str( required_tool_dependency.name ), str( required_tool_dependency.status ) )
+ elif required_tool_dependency is not None and required_tool_dependency.in_error_state:
+ error_message = "This tool dependency's required tool dependency %s version %s has status %s." % \
+ ( str( required_tool_dependency.name ), str( required_tool_dependency.version ), str( required_tool_dependency.status ) )
tool_dependency = tool_dependency_util.handle_tool_dependency_installation_error( app,
tool_dependency,
error_message,
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: UI: Improve masthead, simplify code
by commits-noreply@bitbucket.org 03 Dec '13
by commits-noreply@bitbucket.org 03 Dec '13
03 Dec '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a62c54ddbe2a/
Changeset: a62c54ddbe2a
User: guerler
Date: 2013-12-03 07:42:58
Summary: UI: Improve masthead, simplify code
Affected #: 4 files
diff -r f1729c6dcba86603a9e471688df633251511a22b -r a62c54ddbe2a845be9f0ee2dc4fe4b5820bcd70c static/scripts/galaxy.masthead.js
--- a/static/scripts/galaxy.masthead.js
+++ b/static/scripts/galaxy.masthead.js
@@ -14,20 +14,11 @@
// options
options : null,
- // item list
- list : {},
-
- // keeps track of the last element
- itemLast: null,
-
- // counter
- itemCounter: 0,
-
// background
$background: null,
- // flag indicating visibility of background
- backgroundVisible: false,
+ // list
+ list: [],
// initialize
initialize : function(options)
@@ -47,9 +38,7 @@
// assign background
this.$background = $(this.el).find('#masthead-background');
- // loop through item specific unload functions
- // and collect all there warning messages, regarding
- // the user's attempt to unload the page
+ // loop through unload functions if the user attempts to unload the page
var self = this;
window.onbeforeunload = function()
{
@@ -68,7 +57,7 @@
// configure events
events:
{
- 'click' : '_eventRefresh',
+ 'click' : '_click',
'mousedown' : function(e) { e.preventDefault() }
},
@@ -84,32 +73,36 @@
return this._add(item, false);
},
+ // activate
+ highlight: function(id)
+ {
+ var current = $(this.el).find('#' + id + '> li');
+ if (current) {
+ current.addClass('active');
+ }
+ },
+
// adds a new item to the masthead
_add : function(item, append)
{
- var $loc = $(this.el).find('#' + item.mastheadLocation);
+ var $loc = $(this.el).find('#' + item.location);
if ($loc)
{
// create frame for new item
- var itemId = 'masthead-item-' + this.itemCounter++;
- var $itemNew = $(item.el);
+ var $current = $(item.el);
- // configure id and class in order to mark new items
- $itemNew.attr('id', itemId);
- $itemNew.addClass('masthead-item');
+ // configure class in order to mark new items
+ $current.addClass('masthead-item');
// append to masthead
if (append) {
- $loc.append($itemNew);
+ $loc.append($current);
} else {
- $loc.prepend($itemNew);
+ $loc.prepend($current);
}
// add to list
- this.list[itemId] = item;
-
- // return item id
- return itemId;
+ this.list.push(item);
}
// location not found
@@ -117,63 +110,27 @@
},
// handle click event
- _eventRefresh: function(e)
+ _click: function(e)
{
- // identify current item
- var itemCurrent = $(e.target).closest('.masthead-item');
-
- // get identifier
- if (itemCurrent.length)
- itemCurrent = itemCurrent.attr('id');
-
- // check last item
- if (this.itemLast && this.itemLast != itemCurrent)
- {
- var it = this.list[this.itemLast];
- if (it) {
- if (it.mastheadReset) {
- it.mastheadReset();
- }
- }
+ // close all popups
+ var $all = $(this.el).find('.popup');
+ if ($all) {
+ $all.hide();
}
- // check if current item is in active state
- var useBackground = false;
- if (itemCurrent)
- {
- var it = this.list[itemCurrent];
- if (it) {
- if (it.mastheadReset) {
- if (this.itemLast == itemCurrent) {
- useBackground = this.backgroundVisible ? false : true;
- } else {
- useBackground = true;
- }
- }
- }
- }
-
- // decide wether to show/hide background
- if (useBackground) {
+ // open current item
+ var $current = $(e.target).closest('.masthead-item').find('.popup');
+ if ($(e.target).hasClass('head')) {
+ $current.show();
this.$background.show();
} else {
this.$background.hide();
}
-
- // backup
- this.backgroundVisible = useBackground;
- this.itemLast = itemCurrent;
},
/*
HTML TEMPLATES
*/
-
- // template item
- _templateItem: function(id)
- {
- return '<div id="' + id + '" class="masthead-item"></div>';
- },
// fill template
_template: function(options)
@@ -202,9 +159,9 @@
// icon options
options:
{
- id : "galaxy-icon",
- icon : "fa-cog",
- tooltip : "galaxy-icon",
+ id : '',
+ icon : 'fa-cog',
+ tooltip : '',
with_number : false,
on_click : function() { alert ('clicked') },
on_unload : null,
@@ -212,7 +169,7 @@
},
// location identifier for masthead class
- mastheadLocation: 'iconbar',
+ location: 'iconbar',
// initialize
initialize: function (options)
@@ -278,7 +235,7 @@
// fill template icon
_template: function (options)
{
- var tmpl = '<div id=' + options.id + ' class="symbol">' +
+ var tmpl = '<div id="' + options.id + '" class="symbol">' +
'<div class="icon fa fa-2x ' + options.icon + '"></div>';
if (options.with_number)
tmpl+= '<div class="number"></div>';
@@ -296,7 +253,7 @@
options:
{
id : '',
- title : 'Title',
+ title : '',
target : '_parent',
content : '',
type : 'url',
@@ -306,18 +263,15 @@
},
// location
- mastheadLocation: 'navbar',
+ location: 'navbar',
// optional sub menu
$menu: null,
- // flag if menu is visible
- menuVisible: false,
-
// events
events:
{
- 'click .head' : '_eventClickHead'
+ 'click .head' : '_head'
},
// initialize
@@ -352,7 +306,7 @@
},
// add menu item
- addMenu: function (options)
+ add: function (options)
{
// menu option defaults
var menuOptions = {
@@ -382,7 +336,7 @@
$(this.el).find('.symbol').addClass('caret');
// update element link
- this.$menu = $(this.el).find('.menu');
+ this.$menu = $(this.el).find('.popup');
}
// create
@@ -397,9 +351,6 @@
{
// prevent default
e.preventDefault();
-
- // check for menu options
- self._hideMenu();
// no modifications if new tab is requested
if (self.options.target === '_blank')
@@ -414,42 +365,14 @@
this.$menu.append($(this._templateDivider()));
},
- // add reset function called by masthead
- mastheadReset: function()
- {
- this._hideMenu();
- },
-
- // hide menu
- _hideMenu: function()
- {
- if (this.$menu && this.menuVisible)
- {
- this.$menu.hide();
- this.menuVisible = false;
- }
- },
-
// show menu on header click
- _eventClickHead: function(e)
+ _head: function(e)
{
// prevent default
e.preventDefault();
// check for menu options
- if (this.$menu)
- {
- // show/hide menu
- if (!this.menuVisible)
- {
- this.$menu.show();
- this.menuVisible = true;
- } else {
- this.$menu.hide();
- this.menuVisible = false;
- }
- } else {
- // open new frame
+ if (!this.$menu) {
Galaxy.frame.add(this.options);
}
},
@@ -463,7 +386,7 @@
// fill template header
_templateMenu: function ()
{
- return '<ul class="menu dropdown-menu"></ul>';
+ return '<ul class="popup dropdown-menu"></ul>';
},
_templateDivider: function()
@@ -475,7 +398,7 @@
_template: function (options)
{
// start template
- var tmpl = '<ul class="nav navbar-nav" border="0" cellspacing="0">' +
+ var tmpl = '<ul id="' + options.id + '" class="nav navbar-nav" border="0" cellspacing="0">' +
'<li class="root dropdown" style="">' +
'<a class="head dropdown-toggle" data-toggle="dropdown" target="' + options.target + '" href="' + options.content + '">' +
options.title + '<b class="symbol"></b>' +
diff -r f1729c6dcba86603a9e471688df633251511a22b -r a62c54ddbe2a845be9f0ee2dc4fe4b5820bcd70c static/scripts/galaxy.menu.js
--- a/static/scripts/galaxy.menu.js
+++ b/static/scripts/galaxy.menu.js
@@ -29,6 +29,7 @@
// Analyze data tab.
//
var tab_analysis = new mod_masthead.GalaxyMastheadTab({
+ id : "analysis",
title : "Analyze Data",
content : "root/index"
});
@@ -38,6 +39,7 @@
// Workflow tab.
//
var tab_workflow = new mod_masthead.GalaxyMastheadTab({
+ id : "workflow",
title : "Workflow",
content : "workflow"
@@ -48,33 +50,34 @@
// 'Shared Items' or Libraries tab.
//
var tab_shared = new mod_masthead.GalaxyMastheadTab({
+ id : "shared",
title : "Shared Data",
content : "library/index"
});
- tab_shared.addMenu({
+ tab_shared.add({
title : "Data Libraries",
content : "library/index",
divider : true
});
- tab_shared.addMenu({
+ tab_shared.add({
title : "Published Histories",
content : "history/list_published"
});
- tab_shared.addMenu({
+ tab_shared.add({
title : "Published Workflows",
content : "workflow/list_published"
});
- tab_shared.addMenu({
+ tab_shared.add({
title : "Published Visualizations",
content : "visualization/list_published"
});
- tab_shared.addMenu({
+ tab_shared.add({
title : "Published Pages",
content : "page/list_published"
});
@@ -87,17 +90,18 @@
if (this.options.user.requests)
{
var tab_lab = new mod_masthead.GalaxyMastheadTab({
+ id : "lab",
title : "Lab"
});
- tab_lab.addMenu({
+ tab_lab.add({
title : "Sequencing Requests",
content : "requests/index"
});
- tab_lab.addMenu({
+ tab_lab.add({
title : "Find Samples",
content : "requests/find_samples_index"
});
- tab_lab.addMenu({
+ tab_lab.add({
title : "Help",
content : this.options.lims_doc_url
});
@@ -108,16 +112,16 @@
// Visualization tab.
//
var tab_visualization = new mod_masthead.GalaxyMastheadTab({
-
+ id : "visualization",
title : "Visualization",
content : "visualization/list"
});
- tab_visualization.addMenu({
+ tab_visualization.add({
title : "New Track Browser",
content : "visualization/trackster",
target : "_frame"
});
- tab_visualization.addMenu({
+ tab_visualization.add({
title : "Saved Visualizations",
content : "visualization/list",
target : "_frame"
@@ -130,10 +134,11 @@
if (this.options.enable_cloud_launch)
{
var tab_cloud = new mod_masthead.GalaxyMastheadTab({
+ id : "cloud",
title : "Cloud",
content : "cloudlaunch/index"
});
- tab_cloud.addMenu({
+ tab_cloud.add({
title : "New Cloud Cluster",
content : "cloudlaunch/index"
});
@@ -146,6 +151,7 @@
if (this.options.is_admin_user)
{
var tab_admin = new mod_masthead.GalaxyMastheadTab({
+ id : "admin",
title : "Admin",
content : "admin/index",
extra_class : "admin-only"
@@ -157,54 +163,55 @@
// Help tab.
//
var tab_help = new mod_masthead.GalaxyMastheadTab({
+ id : "help",
title : "Help"
});
if (this.options.biostar_url)
{
- tab_help.addMenu({
+ tab_help.add({
title : "Galaxy Q&A Site",
content : this.options.biostar_url_redirect,
target : "_blank"
});
- tab_help.addMenu({
+ tab_help.add({
title : "Ask a question",
content : "biostar/biostar_question_redirect",
target : "_blank"
});
}
- tab_help.addMenu({
+ tab_help.add({
title : "Support",
content : this.options.support_url,
target : "_blank"
});
- tab_help.addMenu({
+ tab_help.add({
title : "Search",
content : this.options.search_url,
target : "_blank"
});
- tab_help.addMenu({
+ tab_help.add({
title : "Mailing Lists",
content : this.options.mailing_lists,
target : "_blank"
});
- tab_help.addMenu({
+ tab_help.add({
title : "Videos",
content : this.options.screencasts_url,
target : "_blank"
});
- tab_help.addMenu({
+ tab_help.add({
title : "Wiki",
content : this.options.wiki_url,
target : "_blank"
});
- tab_help.addMenu({
+ tab_help.add({
title : "How to Cite Galaxy",
content : this.options.citation_url,
target : "_blank"
});
if (!this.options.terms_url)
{
- tab_help.addMenu({
+ tab_help.add({
title : "Terms and Conditions",
content : this.options.terms_url,
target : "_blank"
@@ -218,12 +225,13 @@
if (!this.options.user.valid)
{
var tab_user = new mod_masthead.GalaxyMastheadTab({
+ id : "user",
title : "User",
extra_class : "loggedout-only"
});
// login
- tab_user.addMenu({
+ tab_user.add({
title : "Login",
content : "user/login",
target : "galaxy_main"
@@ -232,7 +240,7 @@
// register
if (this.options.allow_user_creation)
{
- tab_user.addMenu({
+ tab_user.add({
title : "Register",
content : "user/create",
target : "galaxy_main"
@@ -243,37 +251,38 @@
this.masthead.append(tab_user);
} else {
var tab_user = new mod_masthead.GalaxyMastheadTab({
+ id : "user",
title : "User",
extra_class : "loggedin-only"
});
// show user logged in info
- tab_user.addMenu({
+ tab_user.add({
title : "Logged in as " + this.options.user.email
});
// remote user
if (this.options.use_remote_user && this.options.remote_user_logout_href)
{
- tab_user.addMenu({
+ tab_user.add({
title : "Logout",
content : this.options.remote_user_logout_href,
target : "_top"
});
} else {
- tab_user.addMenu({
+ tab_user.add({
title : "Preferences",
content : "user?cntrller=user",
target : "galaxy_main"
});
- tab_user.addMenu({
+ tab_user.add({
title : "Custom Builds",
content : "user/dbkeys",
target : "galaxy_main"
});
- tab_user.addMenu({
+ tab_user.add({
title : "Logout",
content : "user/logout",
target : "_top",
@@ -282,23 +291,23 @@
}
// default tabs
- tab_user.addMenu({
+ tab_user.add({
title : "Saved Histories",
content : "history/list",
target : "galaxy_main"
});
- tab_user.addMenu({
+ tab_user.add({
title : "Saved Datasets",
content : "dataset/list",
target : "galaxy_main"
});
- tab_user.addMenu({
+ tab_user.add({
title : "Saved Pages",
content : "page/list",
target : "_top"
});
- tab_user.addMenu({
+ tab_user.add({
title : "API Keys",
content : "user/api_keys?cntrller=user",
target : "galaxy_main"
@@ -306,7 +315,7 @@
if (this.options.use_remote_user)
{
- tab_user.addMenu({
+ tab_user.add({
title : "Public Name",
content : "user/edit_username?cntrller=user",
target : "galaxy_main"
@@ -316,6 +325,10 @@
// add to masthead
this.masthead.append(tab_user);
}
+
+ // identify active tab
+ if (this.options.active_view)
+ this.masthead.highlight(this.options.active_view);
}
});
diff -r f1729c6dcba86603a9e471688df633251511a22b -r a62c54ddbe2a845be9f0ee2dc4fe4b5820bcd70c templates/webapps/galaxy/base_panels.mako
--- a/templates/webapps/galaxy/base_panels.mako
+++ b/templates/webapps/galaxy/base_panels.mako
@@ -14,5 +14,7 @@
## Masthead
<%def name="masthead()">
- <% mod_masthead.load(); %>
+ <%
+ mod_masthead.load(self.active_view);
+ %></%def>
\ No newline at end of file
diff -r f1729c6dcba86603a9e471688df633251511a22b -r a62c54ddbe2a845be9f0ee2dc4fe4b5820bcd70c templates/webapps/galaxy/galaxy.masthead.mako
--- a/templates/webapps/galaxy/galaxy.masthead.mako
+++ b/templates/webapps/galaxy/galaxy.masthead.mako
@@ -28,7 +28,7 @@
</%def>
## masthead head generator
-<%def name="load()">
+<%def name="load(active_view = None)"><%
## get configuration
masthead_config = {
@@ -51,7 +51,8 @@
'allow_user_creation' : app.config.allow_user_creation,
'logo_url' : h.url_for(app.config.get( 'logo_url', '/')),
'is_admin_user' : trans.user and app.config.is_admin_user(trans.user),
-
+ 'active_view' : active_view,
+
## user details
'user' : {
'requests' : bool(trans.user and (trans.user.requests or trans.app.security_agent.get_accessible_request_types(trans, trans.user))),
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0