summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Gemfile9
-rw-r--r--application.rb58
-rw-r--r--config.rb20
-rw-r--r--config.ru5
-rw-r--r--helper.rb218
-rw-r--r--public/JME.classbin0 -> 26321 bytes
-rw-r--r--public/JME.jarbin0 -> 38760 bytes
-rw-r--r--public/images/arrow_down_float.pngbin0 -> 618 bytes
-rw-r--r--public/images/arrow_left_float.pngbin0 -> 647 bytes
-rw-r--r--public/images/gray_jean.pngbin0 -> 13475 bytes
-rw-r--r--public/javascripts/toxcreate.js240
-rw-r--r--public/stylesheets/screen.css1
-rw-r--r--public/stylesheets/screen.sass124
-rw-r--r--views/jme_help.html197
-rw-r--r--views/js_link.haml5
-rw-r--r--views/layout.haml35
-rw-r--r--views/predict.haml84
-rw-r--r--views/prediction.haml26
19 files changed, 1024 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..49b161f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+Gemfile.lock
+.sass-cache/
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..c88c19a
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,9 @@
+source :rubygems
+
+gem "compass"
+gem "sinatra"
+gem "haml"
+gem "sass"
+
+gem "opentox-client", :path => "../opentox-client"
+gem "opentox-server", :path => "../opentox-server"
diff --git a/application.rb b/application.rb
new file mode 100644
index 0000000..bd1985c
--- /dev/null
+++ b/application.rb
@@ -0,0 +1,58 @@
+require 'rubygems'
+require 'compass' #must be loaded before sinatra
+require 'sinatra'
+require 'haml' #must be loaded after sinatra
+require 'opentox-client'
+require 'opentox-server'
+require File.join(File.dirname(__FILE__),'helper.rb')
+require File.join(ENV["HOME"],".opentox","config","lazar-gui.rb")
+
+
+get '/?' do
+ redirect to('/predict')
+end
+
+get '/predict/?' do
+ @models = []
+ models = OpenTox::Model.all $model[:uri]
+ models.each do |model|
+ model.get
+ @models << model
+ end
+ haml :predict
+end
+
+post '/predict/?' do
+ @identifier = params[:identifier]
+ @compound = OpenTox::Compound.from_smiles $compound[:uri], @identifier.to_s
+ @models = []
+ @predictions = []
+ lazar = OpenTox::Algorithm.new File.join($algorithm[:uri],"lazar")
+
+ params[:selection].each do |model|
+ @mselected = model[0]
+ @mall = OpenTox::Model.all $model[:uri]
+ @mall.each do |m|
+ m.get
+ @models << m if m.title.match("#{@mselected}")
+ end
+ end
+ @models.each do |m|
+ @prediction_uri = m.run :compound_uri => "#{@compound.uri}"
+ prediction = OpenTox::Dataset.new @prediction_uri
+ @predictions << prediction
+ end
+
+ @prediction_results = []
+ @predictions.each{|p| @prediction_results << p.get}
+
+
+ haml :prediction
+end
+
+get '/stylesheets/:name.css' do
+ content_type 'text/css', :charset => 'utf-8'
+ sass(:"stylesheets/#{params[:name]}", Compass.sass_engine_options )
+end
+
+
diff --git a/config.rb b/config.rb
new file mode 100644
index 0000000..fca7490
--- /dev/null
+++ b/config.rb
@@ -0,0 +1,20 @@
+# Require any additional compass plugins here.
+
+# Set this to the root of your project when deployed:
+http_path = "/"
+css_dir = "public/stylesheets"
+sass_dir = "public/stylesheets"
+images_dir = "public/images"
+javascripts_dir = "public/javascripts"
+
+# You can select your preferred output style here (can be overridden via the command line):
+# output_style = :expanded or :nested or :compact or :compressed
+output_style = :compressed
+
+# To enable relative paths to assets via compass helper functions. Uncomment:
+# relative_assets = true
+
+# To disable debugging comments that display the original location of your selectors. Uncomment:
+line_comments = false
+
+preferred_syntax = :sass
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000..4bb92c7
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,5 @@
+SERVICE = "lazar-gui"
+require 'bundler'
+Bundler.require
+require './application.rb'
+run Sinatra::Application
diff --git a/helper.rb b/helper.rb
new file mode 100644
index 0000000..abcecd4
--- /dev/null
+++ b/helper.rb
@@ -0,0 +1,218 @@
+helpers do
+
+ def is_authorized(uri, action)
+ if OpenTox::Authorization.server && session[:subjectid] != nil
+ return OpenTox::Authorization.authorized?(uri, action, session[:subjectid])
+ else
+ return true
+ end
+ return false
+ end
+
+ def is_aluist
+ OpenTox::Authorization.list_user_groups(session[:username], session[:subjectid]).include?("aluist")
+ end
+
+ def hide_link(destination)
+ @link_id = 0 unless @link_id
+ @link_id += 1
+ haml :js_link, :locals => {:name => "close", :destination => destination, :method => "hide"}, :layout => false
+ end
+
+ def toggle_link(destination,name)
+ @link_id = 0 unless @link_id
+ @link_id += 1
+ haml :js_link, :locals => {:name => name, :destination => destination, :method => "toggle"}, :layout => false
+ end
+
+ def sort(descriptors,value_map)
+ features = {:activating => [], :deactivating => [], :pc_features => []}
+ if descriptors.kind_of?(Array)
+ descriptors.each do |d|
+ if !value_map.empty?
+ features[:activating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} if d[OT.effect] == 2
+ features[:deactivating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]} if d[OT.effect] == 1
+ else
+ if d[OT.effect] =~ TRUE_REGEXP
+ features[:activating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]}
+ elsif d[OT.effect] =~ FALSE_REGEXP
+ features[:deactivating] << {:smarts => d[OT.smarts],:p_value => d[OT.pValue]}
+ end
+ end
+ end
+ else
+ descriptors.each do |d,v|
+ features[:pc_features] << {:feature => d, :value => v}
+ end
+ end
+ features
+ end
+
+ def compound_image(compound,descriptors,value_map)
+ haml :compound_image, :locals => {:compound => compound, :features => sort(descriptors,value_map)}, :layout => false
+ end
+
+ def activity_markup(activity,value_map)
+ if value_map and !value_map.empty?
+ if value_map.size == 2
+ activity = value_map.index(activity) if value_map.has_value? activity
+ if activity.to_i == 2
+ haml ".active #{value_map[activity]}", :layout => false
+ elsif activity.to_i == 1
+ haml ".inactive #{value_map[activity]}", :layout => false
+ else
+ haml ".other #{activity.to_s}", :layout => false
+ end
+ else
+ haml ".other #{activity.to_s}", :layout => false
+ end
+ elsif OpenTox::Algorithm::numeric? activity
+ haml ".other #{sprintf('%.03g', activity.to_f)}", :layout => false
+ else
+ haml ".other #{activity.to_s}", :layout => false
+ end
+=begin
+ case activity.class.to_s
+ when /Float/
+ haml ".other #{sprintf('%.03g', activity)}", :layout => false
+ when /String/
+ case activity
+ when "true"
+ haml ".active active", :layout => false
+ when "false"
+ haml ".inactive inactive", :layout => false
+ else
+ haml ".other #{activity.to_s}", :layout => false
+ end
+ else
+ if activity #true
+ haml ".active active", :layout => false
+ elsif !activity # false
+ haml ".inactive inactive", :layout => false
+ else
+ haml ".other #{activity.to_s}", :layout => false
+ end
+ end
+=end
+ end
+
+ def neighbors_navigation
+ @page = 0 unless @page
+ haml :neighbors_navigation, :layout => false
+ end
+
+ def models_navigation
+ @page = 0 unless @page
+ haml :models_navigation, :layout => false
+ end
+
+ def models_navigation_bottom
+ @page = 0 unless @page
+ haml :models_navigation_bottom, :layout => false
+ end
+
+ def endpoint_option_list(max_time=3600)
+ out = ""
+ tmpfile = File.join(TMP_DIR, 'endpoint_option_list')
+ if File.exists? tmpfile
+ if Time.now-File.mtime(tmpfile) <= max_time
+ f = File.open(tmpfile, 'r+')
+ f.each{|line| out << line}
+ return out
+ else
+ File.unlink(tmpfile)
+ end
+ end
+ result = endpoint_selection()
+ if result.lines.count > 3
+ f = File.new(tmpfile,'w')
+ f.print result
+ f.close
+ end
+ result
+ end
+
+ def endpoint_level(endpoint="Endpoints", level=1)
+ results = OpenTox::Ontology::Echa.echa_endpoints(endpoint) rescue results = []
+ out = ""
+ out += "<ul id='list_#{endpoint}' class='endpoint level_#{level}'>\n" if results.size > 0
+ results.each do |result|
+ r = result.split(',')
+ endpointname = CGI.escape(r.first.split("#").last).gsub(".","")
+ title = r[1..r.size-1].to_s
+ out += " <li class='level_#{level}'><input type='radio' name='endpoint' value='#{result}' id='#{endpointname}' class='endpoint_list' /><label for='#{endpointname}' id='label_#{endpointname}'>#{title.gsub("\"","")}</label>\n"
+ out += endpoint_level(endpointname, level + 1)
+ out += "</li>\n"
+ end
+ out += "</ul>\n" if results.size > 0
+ return out
+ end
+
+ def endpoint_selection()
+ out = "<span id='endpoint_label'></span><input type='button' id='endpoint_list_button' value='Select endpoint' /> \n
+ <div id='div_endpoint'>\n"
+ out += "<b>Please select:</b>\n"
+ out += endpoint_level
+ js = ""
+ out += "</div>\n"
+ return out
+ end
+
+ def logmmol_to_mg(value ,mw)
+ mg = round_to((10**(-1.0*round_to(value.to_f, 2))*(mw.to_f*1000)),4)
+ return mg
+ end
+
+ def logmg_to_mg(value)
+ mg = round_to(10**round_to(value.to_f, 2),4)
+ return mg
+ end
+
+ def ptd50_to_td50(value ,mw)
+ td50 = round_to((10**(-1.0*round_to(value.to_f, 2))*(mw.to_f*1000)),4)
+ return td50
+ end
+
+ def round_to(value, deci)
+ rounded = (value.to_f*(10**deci)).round / (10**deci).to_f
+ return rounded
+ end
+
+ def calc_mw(compound_uri)
+ ds = OpenTox::Dataset.new()
+ ds.save(@subjectid)
+ ds.add_compound(compound_uri)
+ ds.save(@subjectid)
+ mw_algorithm_uri = File.join(CONFIG[:services]["opentox-algorithm"],"pc/MW")
+ mw_uri = OpenTox::RestClientWrapper.post(mw_algorithm_uri, {:dataset_uri=>ds.uri})
+ ds.delete(@subjectid)
+ mw_ds = OpenTox::Dataset.find(mw_uri, @subjectid)
+ mw = mw_ds.data_entries[compound_uri][mw_uri.to_s + "/feature/MW"].first.to_f
+ mw_ds.delete(@subjectid)
+ return mw
+ end
+
+ def transform(value, compound_uri, name, haml)
+ prediction_trans = nil
+ model_name = name.to_s.downcase
+ if model_name.include? "ptd50"
+ mw = calc_mw(compound_uri)
+ td50 = ptd50_to_td50(value, mw)
+ prediction_trans = "TD50: #{td50}"
+ elsif model_name.include? "loael"
+ if model_name.include? "mol"
+ mw = calc_mw(compound_uri)
+ mg = logmmol_to_mg(value, mw)
+ prediction_trans = "mg/kg bw/day: #{mg}"
+ elsif model_name.include? "mg"
+ mg = logmg_to_mg(value)
+ prediction_trans = "mg/kg bw/day: #{mg}"
+ end
+ end
+ if haml == true
+ haml ".other #{prediction_trans.to_s}", :layout => false
+ else
+ return prediction_trans
+ end
+ end
+end
diff --git a/public/JME.class b/public/JME.class
new file mode 100644
index 0000000..9efda0e
--- /dev/null
+++ b/public/JME.class
Binary files differ
diff --git a/public/JME.jar b/public/JME.jar
new file mode 100644
index 0000000..d571682
--- /dev/null
+++ b/public/JME.jar
Binary files differ
diff --git a/public/images/arrow_down_float.png b/public/images/arrow_down_float.png
new file mode 100644
index 0000000..2466c8f
--- /dev/null
+++ b/public/images/arrow_down_float.png
Binary files differ
diff --git a/public/images/arrow_left_float.png b/public/images/arrow_left_float.png
new file mode 100644
index 0000000..07b7b14
--- /dev/null
+++ b/public/images/arrow_left_float.png
Binary files differ
diff --git a/public/images/gray_jean.png b/public/images/gray_jean.png
new file mode 100644
index 0000000..355fba2
--- /dev/null
+++ b/public/images/gray_jean.png
Binary files differ
diff --git a/public/javascripts/toxcreate.js b/public/javascripts/toxcreate.js
new file mode 100644
index 0000000..ef2a953
--- /dev/null
+++ b/public/javascripts/toxcreate.js
@@ -0,0 +1,240 @@
+$(function() {
+
+ jQuery.fn.toggleWarnings = function(id) {
+ var id = id;
+ this.bind("click", function() {
+ if($("a#show_model_" + id + "_warnings").html()=="show") {
+ $("div#model_" + id + "_warnings").slideDown("slow");
+ $("a#show_model_" + id + "_warnings").html("hide");
+ }else{
+ $("div#model_" + id + "_warnings").slideUp("slow");
+ $("a#show_model_" + id + "_warnings").html("show");
+ }
+ return false;
+ });
+ };
+
+ trim = function() {
+ return this.replace(/^\s+|\s+$/g, '');
+ }
+
+ checkStati = function(stati) {
+ stati = stati.split(", ");
+ $("body")
+ var newstati = new Array;
+ $.each(stati, function(){
+ checkProgress(this);
+ if(checkStatus(this) > 0) newstati.push(this);
+ });
+ if (newstati.length > 0) var statusCheck = setTimeout('checkStati("' + newstati.join(", ") + '")',10000);
+ };
+
+ checkStatus = function(id) {
+ if(id == "") return -1;
+ var opts = {method: 'get', action: 'model/' + id + '/status', id: id};
+ var status_changed = $.ajax({
+ type: opts.method,
+ url: opts.action,
+ async: false,
+ dataType: 'html',
+ data: {
+ '_method': 'get'
+ },
+ success: function(data) {
+ var status_before = "";
+ if ($("span#model_" + id + "_status") != null) status_before = $("span#model_" + id + "_status").html().trim();
+ if (status_before == "Deleting") return -1;
+ var status_after = data.trim();
+ $("span#model_" + id + "_status").animate({"opacity": "0.2"},1000);
+ $("span#model_" + id + "_status").animate({"opacity": "1"},1000);
+ if( status_before != status_after) {
+ $("span#model_" + id + "_status").html(data);
+ loadModel(id, 'model');
+ if (status_after == "Completed" || status_after == "Error") id = -1;
+ }
+ },
+ error: function(data) {
+ //alert("status check error");
+ id = -1;
+ }
+ });
+ return id;
+ };
+
+
+ checkProgress = function(id) {
+ var task = $("input#model_" + id + "_task").attr('value');
+ var opts = {action: task + "/percentageCompleted" , id: id};
+ var progress_changed = $.ajax({
+ url: opts.action,
+ async: false,
+ dataType: 'html',
+ data: {
+ '_method': 'get'
+ },
+ success: function(data) {
+ var progress = data.trim();
+ if (progress == "100") return -1;
+ $("div#model_" + id + "_progress").progressbar("value", parseInt(progress));
+ $("div#model_" + id + "_progress").attr({title: parseInt(progress) + "%"});
+ },
+ error: function(data) {
+ id = -1;
+ }
+ });
+ return id;
+ };
+
+ loadModel = function(id, view) {
+ if(id == "") return -1;
+ var opts = {method: 'get', action: 'model/' + id + '/' + view, view: view };
+ var out = id;
+ $.ajax({
+ type: opts.method,
+ url: opts.action,
+ dataType: 'html',
+ data: {
+ '_method': 'get'
+ },
+ success: function(data) {
+ if (view == "model") $("div#model_" + id).html(data);
+ if (view.match(/validation/)) $("dl#model_validation_" + id).html(data);
+ addExternalLinks();
+ },
+ error: function(data) {
+ //alert("loadModel error");
+ }
+ });
+ return false;
+ };
+
+});
+
+jQuery.fn.editModel = function(options) {
+ var defaults = {
+ method: 'get',
+ action: this.attr('href'),
+ trigger_on: 'click'
+ };
+ var opts = $.extend(defaults, options);
+ this.bind(opts.trigger_on, function() {
+ $.ajax({
+ type: opts.method,
+ url: opts.action,
+ dataType: 'html',
+ data: {
+ '_method': 'get'
+ },
+ success: function(data) {
+ $("div#model_" + opts.id + "_name").html(data);
+ $("input#model_" + opts.id + "_name").focus();
+ },
+ error: function(data) {
+ alert("model edit error!");
+ }
+ });
+ return false;
+ });
+};
+
+jQuery.fn.cancelEdit = function(options) {
+ var defaults = {
+ method: 'get',
+ action: 'model/' + options.id + '/name?mode=show',
+ trigger_on: 'click'
+ };
+ var opts = $.extend(defaults, options);
+
+ this.bind(opts.trigger_on, function() {
+ $.ajax({
+ type: opts.method,
+ url: opts.action,
+ dataType: 'html',
+ data: {
+ '_method': 'get'
+ },
+ success: function(data) {
+ $("div#model_" + opts.id + "_name").html(data);
+ },
+ error: function(data) {
+ alert("model cancel error!");
+ }
+ });
+ return false;
+ });
+};
+
+jQuery.fn.saveModel = function(options) {
+ var defaults = {
+ method: 'put',
+ action: 'model/' + options.id,
+ trigger_on: 'click'
+ };
+ var opts = $.extend(defaults, options);
+
+ this.bind(opts.trigger_on, function() {
+ var name = $("input#model_" + opts.id + "_name").val();
+ $.ajax({
+ type: opts.method,
+ url: opts.action,
+ dataType: 'html',
+ data: {
+ '_method': 'put',
+ 'name': name
+ },
+ success: function(data) {
+ $("div#model_" + opts.id + "_name").html(data);
+ },
+ error: function(data) {
+ alert("model save error!");
+ }
+ });
+ return false;
+ });
+};
+
+
+jQuery.fn.deleteModel = function(type, options) {
+ var defaults = {
+ method: 'post',
+ action: this.attr('href'),
+ confirm_message: 'Are you sure?',
+ trigger_on: 'click'
+ };
+ var opts = $.extend(defaults, options);
+ this.bind(opts.trigger_on, function() {
+ if(confirm(opts.confirm_message)) {
+ $("div#model_" + opts.id).fadeTo("slow",0.5);
+ $("span#model_" + opts.id + "_status").html("Deleting");
+ $("a#delete_" + opts.id).html("");
+ $.ajax({
+ type: opts.method,
+ url: opts.action,
+ dataType: 'html',
+ data: {
+ '_method': 'delete'
+ },
+ success: function(data) {
+ $("div#model_" + opts.id).fadeTo("slow",0).slideUp("slow").remove();
+ },
+ error: function(data) {
+ $("span#model_" + opts.id + "_status").html("Delete Error");
+ //alert("model delete error!");
+ }
+ });
+ }
+ return false;
+ });
+};
+
+$(document).ready(function() {
+ addExternalLinks();
+});
+
+addExternalLinks = function() {
+ $('A[rel="external"]').each(function() {
+ $(this).attr('alt', 'Link opens in new window.');
+ $(this).attr('title', 'Link opens in new window.');
+ $(this).attr('target', '_blank');
+ });
+};
diff --git a/public/stylesheets/screen.css b/public/stylesheets/screen.css
new file mode 100644
index 0000000..adc0596
--- /dev/null
+++ b/public/stylesheets/screen.css
@@ -0,0 +1 @@
+body{background-image:url("/images/gray_jean.png");background-color:#ccf;overflow:scroll;font-family:sans-serif;margin:1em;min-width:800px;min-heigth:600px}body a{text-decoration:none;font-weight:bold;color:#000}.logo{text-align:right;font-size:1.5em;text-shadow:#b9dcff 2px 2px}.info{background-color:#b9dcff;margin:1em 0;padding:10px;text-align:center;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;background-image:-webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(70%, #b9dcff));background-image:-webkit-linear-gradient(#ffffff,#b9dcff 70%);background-image:-moz-linear-gradient(#ffffff,#b9dcff 70%);background-image:-o-linear-gradient(#ffffff,#b9dcff 70%);background-image:linear-gradient(#ffffff,#b9dcff 70%);-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset}.content{background-image:url("/images/gray_jean.png")}.content h1{margin:0.3em;text-shadow:#fff 0 1px 0;font-size:x-large;font-family:monospace}.content h2{text-shadow:#fff 0 1px 0;font-size:x-large;font-family:monospace}.content .arrow{margin:5px 0px 5px 20px}.content .back{display:inline}.content .close{text-align:right}.content fieldset#top{border:0;margin-top:5em;padding:10px;background-color:#b9dcff;-moz-border-radius-topleft:25px;-webkit-border-top-left-radius:25px;border-top-left-radius:25px;-moz-border-radius-topright:25px;-webkit-border-top-right-radius:25px;border-top-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box;-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset}.content fieldset#top draw{display:block}.content fieldset#middle{border:0;padding:10px;background-color:#b9dcff;-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset}.content .model{display:inline;margin:1em}.content fieldset#bottom{border:0;background-color:#b9dcff;padding:10px;margin-bottom:5em;-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box}.content .predictions{background-color:#b9dcff;padding:10px;text-align:justify;margin:0.3em;-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-border-radius-topleft:25px;-webkit-border-top-left-radius:25px;border-top-left-radius:25px;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-topright:25px;-webkit-border-top-right-radius:25px;border-top-right-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box}.content .was{margin-top:2em;padding:1em;background-image:url("/images/gray_jean.png");-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-border-radius-topleft:25px;-webkit-border-top-left-radius:25px;border-top-left-radius:25px;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-topright:25px;-webkit-border-top-right-radius:25px;border-top-right-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box}.content .results{margin-top:2em;padding:1em;background-image:url("/images/gray_jean.png");-webkit-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;box-shadow:1px 1px 1px #fff inset,-1px -1px 1px rgba(0,0,0,0.3) inset;-moz-border-radius-topleft:25px;-webkit-border-top-left-radius:25px;border-top-left-radius:25px;-moz-border-radius-bottomleft:25px;-webkit-border-bottom-left-radius:25px;border-bottom-left-radius:25px;-moz-border-radius-topright:25px;-webkit-border-top-right-radius:25px;border-top-right-radius:25px;-moz-border-radius-bottomright:25px;-webkit-border-bottom-right-radius:25px;border-bottom-right-radius:25px;-webkit-background-clip:border;-moz-background-clip:border;background-clip:border-box}.footer{margin:20px 0 20px 0}
diff --git a/public/stylesheets/screen.sass b/public/stylesheets/screen.sass
new file mode 100644
index 0000000..3c5e48c
--- /dev/null
+++ b/public/stylesheets/screen.sass
@@ -0,0 +1,124 @@
+//@import compass/reset, compass/css3, compass/utilities, compass/layout
+@import compass/css3
+
+//$bg-color: #C5C1A4
+$bg-color: #CCCCFF
+$bg-color-div: #C5C1E4
+//$border: 2px solid #C5C1A4
+$ist-blue: #B9DCFF
+
+body
+ background-image: url("/images/gray_jean.png")
+ background-color: $bg-color
+ overflow: scroll
+ font-family: sans-serif
+ margin: 1em
+ min-width: 800px
+ min-heigth: 600px
+
+ a
+ text-decoration: none
+ font-weight: bold
+ color: black
+
+.logo
+ text-align: right
+ font-size: 1.5em
+ +text-shadow($ist-blue 2px 2px)
+
+.info
+ background-color: $ist-blue
+ margin: 1em 0
+ padding: 10px
+ text-align: center
+ +border-bottom-left-radius(25px)
+ +border-bottom-right-radius(25px)
+ +background-image(linear-gradient(#FFFFFF, $ist-blue 70%))
+ +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset)
+
+.content
+
+ background-image: url("/images/gray_jean.png")
+
+ h1
+ margin: 0.3em
+ text-shadow: #FFF 0 1px 0
+ font-size: x-large
+ font-family: monospace
+
+ h2
+ text-shadow: #FFF 0 1px 0
+ font-size: x-large
+ font-family: monospace
+
+ .arrow
+ margin: 5px 0px 5px 20px
+
+ .back
+ display: inline
+
+ .close
+ text-align: right
+
+ fieldset#top
+ border: 0
+ margin-top: 5em
+ padding: 10px
+ background-color: $ist-blue
+ +border-top-left-radius(25px)
+ +border-top-right-radius(25px)
+ +background-clip(border-box)
+ +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset)
+ draw
+ display: block
+
+ fieldset#middle
+ border: 0
+ padding: 10px
+ background-color: $ist-blue
+ +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset)
+
+ .model
+ display: inline
+ margin: 1em
+
+ fieldset#bottom
+ border: 0
+ background-color: $ist-blue
+ padding: 10px
+ margin-bottom: 5em
+ +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset)
+ +border-bottom-left-radius(25px)
+ +border-bottom-right-radius(25px)
+ +background-clip(border-box)
+
+ .predictions
+ background-color: $ist-blue
+ padding: 10px
+ text-align: justify
+ margin: 0.3em
+ +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset)
+ +border-left-radius(25px)
+ +border-right-radius(25px)
+ +background-clip(border-box)
+
+ .was
+ margin-top: 2em
+ padding: 1em
+ background-image: url("/images/gray_jean.png")
+ +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset)
+ +border-left-radius(25px)
+ +border-right-radius(25px)
+ +background-clip(border-box)
+
+ .results
+ margin-top: 2em
+ padding: 1em
+ background-image: url("/images/gray_jean.png")
+ +box-shadow(1px 1px 1px rgba(white, 1) inset, -1px -1px 1px rgba(black, 0.3) inset)
+ +border-left-radius(25px)
+ +border-right-radius(25px)
+ +background-clip(border-box)
+
+.footer
+ margin: 20px 0 20px 0
diff --git a/views/jme_help.html b/views/jme_help.html
new file mode 100644
index 0000000..adf3e1f
--- /dev/null
+++ b/views/jme_help.html
@@ -0,0 +1,197 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html>
+<head>
+ <meta name="generator" content=
+ "HTML Tidy for Linux/x86 (vers 12 April 2005), see www.w3.org">
+ <meta http-equiv="content-type" content=
+ "text/html; charset=us-ascii">
+
+ <title>JME Help</title>
+ <meta name="author" content="Peter Ertl, Novartis Pharma AG">
+ <link rel="stylesheet" href="../style.css" type="text/css">
+<style type="text/css">
+ body {
+ background-color: white;
+ }
+ h2.c3 {text-align: center}
+ p.c2 {font-style: italic; text-align: right}
+ p.c1 {text-align: center}
+</style>
+</head>
+
+<body>
+<h1>JME Molecular Editor</h1>
+
+ <p class="c2">Written by Peter Ertl, Novartis Pharma
+ AG</p>
+
+ <h2 class="c3">Basic Instructions</h2>
+
+ <p>This editor is intended to be used without any special
+ documentation or training, but there are some tricks which
+ can help you to work with it more efficiently.</p>
+
+ <h3>Menu Buttons</h3>
+
+ <ul>
+ <li><b>D-R</b> deletes functional groups - choose this
+ option and then click on the bond connecting the group
+ with the main skeleton</li>
+
+ <li><b>UDO</b> undo last editing step</li>
+
+ <li><b>QRY</b> (if enabled in the param tag) allows easy
+ specification of atomic queries for substructure
+ searches</li>
+
+ <li><b>Stereo bonds</b> - the type of stereo bond (up,
+ down) may be changed by clicking on the already created
+ stereo bond; this cycles through two / four possible
+ stereo bond types</li>
+
+ <li><b>Atomic charges</b> may be changed by the
+ <b>+/-</b> button. Editor enables modification of charges
+ only in "reasonable" cases. If you are not satisfied with
+ the editor's inteligence (concerning charges and the
+ explicit number of hydrogens) you can force your will by
+ using the <b>X</b> button</li>
+
+ <li><b>"Non-organic" atoms</b> or atoms with nonstandard
+ valence may be entered with help of <b>X</b> button by
+ specifying atomic SMILES (without [ ] brackets, i.e. Si,
+ Fe++, NH3+).</li>
+ </ul>
+
+ <h3>Keyboard Shortcuts</h3>
+
+ <p>Most of the commands may be accessed also by keyboard
+ shortcuts. It is possible to:</p>
+
+ <ul>
+ <li>change <b>atom type</b> by pressing <b>C</b>,
+ <b>N</b>, <b>O</b>, <b>S</b>, <b>F</b>, <b>L</b> (for Cl)
+ <b>B</b> (for Br) <b>I</b>, <b>P</b>, <b>H</b>, <b>X</b>,
+ <b>R</b> and clicking the respective atom</li>
+
+ <li>choose <b>bond order</b>: <b>-</b> for single bond,
+ <b>=</b> for double bond, <b>#</b> for triple bond</li>
+
+ <li>choose <b>ring type</b> by pressing <b>3</b>,
+ <b>4</b>, <b>5</b>, <b>6</b>, <b>7</b>, <b>8</b>,
+ <b>9</b> or <b>1</b> for phenyl, <b>0</b> for furyl</li>
+
+ <li>start <b>delete mode</b> by pressing <b>D</b> or
+ <b>Del</b> and</li>
+
+ <li>return to the <b>standard state</b> (carbon, single
+ bond) with <b>Esc</b></li>
+ </ul>
+
+ <p><b>common functional groups</b> may also be added by
+ keyboard shortcuts. Use <b>t</b> for t-butyl, <b>ft</b> for
+ trifluoromethyl, <b>lt</b> for trichloromethyl, <b>a</b>
+ for COOH, <b>z</b> for SO2Me and <b>y</b> for nitro, and
+ then click the atom where the group should be
+ connected.</p>
+
+ <h3>Moving and Rotation</h3>
+
+ <p>You can move molecule by "dragging free space" with the
+ left mouse button and rotate it by using the left mouse
+ button and <b>Shift</b> key (or left and right mouse
+ buttons together).</p>
+
+ <h3>Adding rings</h3>
+
+ <p>When a ring template is selected and multivalent atom is
+ clicked, a new ring will be created connected by single
+ bond to this atom. When spiro ring is required, the
+ <b>Shift</b> key must be pressed when clicking on the atom.
+ Spiro ring may be added only to atom with 2 single
+ bonds.</p>
+
+ <h3>Multivalent nitrogen groups</h3>
+
+ <p>Multivalent nitrogen groups, such as nitro, azide,
+ N-oxide, nitrile etc, should be drawn with a pentavalent
+ nitrogen as shown below.</p>
+
+ <p class="c1"><img src="images/nitro.gif" alt=
+ "nitro stuff"></p>
+
+ <p>The program automatically converts polar form of these
+ groups into non-polar one with pentavalent nitrogen. If you
+ prefer polar nitro (and similar) groups, use keyword
+ "polarnitro" in the applet param tag.</p>
+
+ <h3>Stereochemistry</h3>
+
+ <p>Stereochemistry at C4 centers, double bonds and allenes
+ is supported. Use the up/down wedge bonds to indicate
+ stereochemistry at the C4 centers. Remember, that only
+ bonds with a "sharp point" towards the atom are considered.
+ When creating SMILES the editor tries to guess missing
+ stereo features, in unresolvable cases an error message is
+ issued and the SMILES without stereo information is
+ created.</p>
+
+ <p>When the autoez keyword is set, SMILES with E,Z
+ stereochemistry on all non-ring double bonds is generated
+ automatically. Without this keyword (or for ring double
+ bonds) you have to mark a double bond as stereo by clicking
+ on it with the stereo bond button selected. The bond color
+ will change to violet.</p>
+
+ <p>Stereochemistry may be completely disabled by the
+ "nostereo" option in the param tag.</p>
+
+ <h3>Input of Multipart Structures</h3>
+
+ <p>By default only non-disconnected structures are allowed.
+ This may be changed by a "multipart" option in the applet
+ param tag. A button <b>NEW</b> appears in the JME menu.
+ Creation of a new molecule may be started only after
+ clicking the <b>NEW</b> button, selecting a proper template
+ (atom, ring, bond) and clicking free space in the drawing
+ area. Without <b>NEW</b> button the click on the free space
+ has the same effect as in the standard mode (i.e moving or
+ rotation of the last touched molecule). In the multipart
+ mode <b>CLR</b> button deletes the last touched
+ molecule.</p>
+
+ <h3>Atom Numbering</h3>
+
+ <p>Atom numbering (marking) is enabled with the option
+ "number" in the applet param tag (for reaction input this
+ is default). Button <b>123</b> appears in the JME menu. To
+ mark an atom press the <b>123</b> button and then the atom.
+ You can mark more atoms with the same number when pressing
+ <b>Shift</b> while clicking the 2nd and further atoms.
+ Second click on the marked atom deletes the number.</p>
+
+ <h3>Reaction Input</h3>
+
+ <p>Reaction input is enabled with the option "reaction" in
+ the applet param tag. Button with an arrow, <b>NEW</b>
+ button and <b>123</b> button appear in the JME menu and
+ arrow appears also in the drawing area. Now simply draw
+ reactant(s), product(s) and modulator(s) (modulators have
+ to be above the arrow) as explained in the description of
+ input of multipart structures. The arrow button enables
+ simplified input of reactions. After clicking it, the
+ reactant will be copied to the product (including atom
+ numbering, if any). When the <b>Shift</b> is pressed during
+ this action all atoms will be automatically numbered.</p>
+
+ <h3>Query Features</h3>
+
+ <p>Query button (when enabled in the option tag) launches a
+ query window which allows creation of SMARTS atom queries
+ by combining various atom attributes. Create a SMARTS query
+ and then click the respective atom in the
+ molecule.</p>
+</body>
+</html>
+
+
diff --git a/views/js_link.haml b/views/js_link.haml
new file mode 100644
index 0000000..7d8cdce
--- /dev/null
+++ b/views/js_link.haml
@@ -0,0 +1,5 @@
+%a{:href => "#{destination}", :id => "js_link#{@link_id}"} #{name}
+:javascript
+ $("a#js_link#{@link_id}").click(function () {
+ $("#{destination}").#{method}();
+ });
diff --git a/views/layout.haml b/views/layout.haml
new file mode 100644
index 0000000..14e9689
--- /dev/null
+++ b/views/layout.haml
@@ -0,0 +1,35 @@
+!!!
+%html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}
+ %head
+ %meta{'http-equiv' => 'Content-Type', :content => 'text/html; charset=UTF-8'}
+ %meta{'http-equiv' => "X-UA-Compatible", :content => "chrome=1"}
+ %title Lazar Toxicity Predictions
+ %link{ :href=>"/stylesheets/screen.css", :media=>"screen, projection", :rel=>"stylesheet", :type=>"text/css"}
+ -#%link{ :type=>"text/javascript", :src=>"/sketcher/jquery-ui-1.9.2.custom.css"}
+ -#%link{ :href=>"/stylesheets/css/print.css", :media=>"print", :rel=>"stylesheet", :type=>"text/css"}
+ -#%link{ :href=>"/stylesheets/css/ie.css", :media=>"screen, projection", :rel=>"stylesheet", :type=>"text/css"}
+ -#%link{:rel=>"stylesheet", :href=>"http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css"}
+ %script{:src=>"http://code.jquery.com/jquery-1.8.3.js"}
+ -#%script{ :type=>"text/javascript", :src=>"/javascripts/ChemDoodleWeb-libs.js"}
+ -#%script{ :type=>"text/javascript", :src=>"/javascripts/ChemDoodleWeb.js"}
+ -#%script{ :type=>"text/javascript", :src=>"/sketcher/jquery-ui-1.9.2.custom.min.js"}
+ -#%script{ :type=>"text/javascript", :src=>"/sketcher/ChemDoodleWeb-sketcher.js"}
+ -#%script{:src=>"http://kemia.github.com/js/kemia.js"}
+ -#%script{:src=>"http://code.jquery.com/ui/1.9.2/jquery-ui.js"}
+ -#%script{:type => "text/javascript", :src => "#{to('/javascripts/toxcreate.js')}"}
+
+
+
+ %body
+ .logo
+ %h1 Lazar Toxicity Predictions
+
+ .info
+ This is a placeholder for informations about this IST application. In 3 steps to your prediction.
+
+ .content
+ = yield
+
+ .footer
+ &copy;
+ %a{:href => 'http://www.in-silico.ch', :rel => "external"} in-silico toxicology gmbh 2004-2013
diff --git a/views/predict.haml b/views/predict.haml
new file mode 100644
index 0000000..2de8b75
--- /dev/null
+++ b/views/predict.haml
@@ -0,0 +1,84 @@
+:javascript
+ function getsmiles() {
+ if (document.JME.smiles() != '') {
+ document.form.identifier.value = document.JME.smiles() ;
+ }
+ }
+
+%form{:name => "form", :action => to('/predict'), :method => "post", :enctype => "multipart/form-data" }
+ %fieldset#top
+ %a{:href => "#insert", :id => "linkInsert#{p.object_id}"}
+ %h1 1. Draw or insert your compound
+ :javascript
+ $("a#linkInsert#{p.object_id}").click(function () {
+ $("#insert").toggle();
+ document.location = document.location + "#" + "insert";
+ });
+ #insert{ :style => "display: none" }
+ %p
+ %label &nbsp;
+ .jme
+ %applet{:code => "JME.class", :name => "JME", :archive => "JME.jar", :width => "500", :height => "360"}
+ %param{ :name => "options", :value => "polarnitro"}
+ Please enable Java and JavaScript in your browser to use the JME editor.
+ %span{:style=>"font-size:75%"}
+ &copy;
+ %a{:href => 'http://www.molinspiration.com/jme/index.html', :rel => "external"} JME Editor
+ courtesy of Peter Ertl, Novartis
+ %br
+ %label{:for => 'identifier'}
+ or enter the
+ %a{:href => "http://en.wikipedia.org/wiki/Simplified_molecular_input_line_entry_specification", :rel => "external"} SMILES
+ string
+ %input{:type => 'text', :name => 'identifier', :id => 'identifier', :size => '60'}
+
+ .close
+ = hide_link "#insert"
+
+ .arrow
+ %img{:src=>"/images/arrow_down_float.png", :alt=>"arrow", :class=> "arrow"}
+
+
+ %fieldset#middle
+ %a{:href => "#models", :id => "linkModels#{p.object_id}"}
+ %h1 2. Select one or more toxic endpoints
+
+ :javascript
+ $("a#linkModels#{p.object_id}").click(function () {
+ $("#models").toggle();
+ document.location = document.location + "#" + "models";
+ });
+
+ #models{ :style => "display: none;"}
+ %p Description about these models.
+ %br
+ - @models.each do |model|
+ %input{:type => 'checkbox', :name => "selection[#{model.title}]", :value => "#{model.metadata}", :uri => "#{model.uri}", :disabled => false}
+ %model= model.title
+ %p= model.metadata["#{RDF::DC.modified}"]
+ %br
+
+ .close
+ = hide_link "#models"
+
+ .arrow
+ %img{:src=>"/images/arrow_down_float.png", :alt=>"arrow", :class=> "arrow"}
+
+
+ %fieldset#bottom
+ %a{:href => "#predict", :id => "linkPredict#{p.object_id}"}
+ %h1 3. Predict
+
+ :javascript
+ $("a#linkPredict#{p.object_id}").click(function () {
+ $("#predict").toggle();
+ document.location = document.location + "#" + "predict";
+ });
+
+ #predict{ :style => "display: none;"}
+ %p Display the prediction including neighbours and sort mechanism
+ %br
+ %input{ :type => "submit", :value => "Predict", :onclick => "getsmiles();"}
+
+ .close
+ = hide_link "#predict"
diff --git a/views/prediction.haml b/views/prediction.haml
new file mode 100644
index 0000000..1286d52
--- /dev/null
+++ b/views/prediction.haml
@@ -0,0 +1,26 @@
+.predictions
+ .back
+ %h1
+ %img{:src=>"/images/arrow_left_float.png", :alt=>"arrow"}
+ %a{:href => to('/predict')} New Prediction
+
+ .was
+ %h2= "Compound image: "
+ %img{:src=>"#{@compound.uri}/image", :alt=>@compound.uri, :width=>"100px"}
+ %br
+ %h2= "Compound SMILES string: "
+ %p= @identifier
+
+ .results
+ %h2= "Selected Entpoints: "
+ - @models.each do |m|
+ %p= m.inspect
+ %br
+ %h2= "Prediction Uri: "
+ - @predictions.each do |p|
+ %p= p.uri
+ %br
+ %h2= "Prediction Results: "
+ - @prediction_results.each do |r|
+ %p= r
+