Updated master to SVN trunk revision 572

This commit is contained in:
Yury V Bukhman
2015-06-26 15:04:35 -05:00
parent 67544a10e6
commit 2d658405a1
184 changed files with 8236 additions and 6182 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+16 -1
View File
@@ -63,13 +63,28 @@ a:visited { color: #428bca !important;}
border: 1px solid black;
margin: 20px auto 0;
width: 1600px;
padding-left: 50px;
padding-left: 50px;
overflow: hidden; /* MB: added so that float left stuffs won't collapse. */
}
#contents {
padding: 5px 25px;
}
/* MB: Options in GCAT. For unordered list */
#options {
margin: 0;
padding: 0;
list-style: none;
}
/* MB: 1 option in GCAT. */
#options li {
float: left;
width: 33%;
padding: 0 100px 0 0;
}
/*#mainContent{
margin:0;
min-height:500px;
+6 -2
View File
@@ -55,7 +55,11 @@ class AssaysController < ApplicationController
flash.now[:error] = @result[:error_message] #.join("\n")
#do not allow bad guys to fill disc space with invalid files
FileUtils.rm @result[:path]
render :action => 'inputfile_error_message'
# render :action => 'inputfile_error_message'
@error_msg = @result[:error_message]
@console_msg = @result[:console_msg]
render :action => 'inputfile_error_message'
else
# parse the output text file into a hash in order to create a table in Assays#show
@table = output_table(@result, !@result[:layout_file].nil?)
@@ -70,4 +74,4 @@ class AssaysController < ApplicationController
end
end
end
+71 -12
View File
@@ -32,8 +32,10 @@ class Assay
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :input_file, :transformation, :transformation_input, :blank_value, :blank_value_input, :start_index, :remove_points, :remove_jumps, :plate_type,
:plate_dimensions_row, :plate_dimensions_column, :timestamp_format, :growth_threshold, :layout_file,:filename,:content_type, :model, :loess_input
attr_accessor :input_file, :blank_value, :blank_value_input, :start_index, :remove_points, :remove_jumps, :plate_type,
:plate_dimensions_row, :plate_dimensions_column, :timestamp_format, :growth_threshold, :layout_file,:filename,:content_type, :model, :loess_input, :console_out, :specg_min,
:specg_max, :totg_min, :totg_max, :lagT_min, :lagT_max,:transformation, :transformation_input
# (1) Validation of input data file
validates_presence_of :input_file, :message => '- No input file was specified.'
@@ -117,7 +119,7 @@ class Assay
if self.transformation == '-1'
self.transformation = Float(self.transformation_input)
else
self.transformation = self.transformation.to_i
self.transformation = self.transformation.to_f
end
# Soothing parameter for growth curve model. Applied for Loess model only.
@@ -128,6 +130,8 @@ class Assay
# (3) blank value (A Real Number)
if self.blank_value == 'default'
self.blank_value = nil
elsif self.blank_value == 'zero'
self.blank_value = 0
else
self.blank_value = Float(self.blank_value_input)
end
@@ -156,6 +160,20 @@ class Assay
self.remove_jumps = false
end
## (7) Heatmap values
if (self.specg_min != '' && self.specg_max != '')
self.specg_max = Float(self.specg_max)
self.specg_min = Float(self.specg_min)
end
if (self.totg_min != '' && self.totg_max != '')
self.totg_min = Float(self.totg_min)
self.totg_max = Float(self.totg_max)
end
if (self.lagT_min != '' && self.lagT_max != '')
self.lagT_max = Float(self.lagT_max)
self.lagT_min = Float(self.lagT_min)
end
############################################################################################
@@ -201,7 +219,11 @@ class Assay
if(File.size(inputfile) > MAX_FILE_SIZE)
return {:error_message => "Error: File too big. Maximum file size allowed is #{MAX_FILE_SIZE/(10**6)} MB.", :path => inputfile}
end
# Try to override stdout to redirect the console output.
$stdout = File.new(out_dir_path + '/console.out', 'w')
$stdout.sync = true
# use web interface parsed parameters to call R function/library via Rinruby
R.eval ('library(GCAT)')
R.assign "out.dir", out_dir_path
@@ -253,9 +275,12 @@ class Assay
# (2) transformation. N value (A Real Number)
R.assign "add.constant", self.transformation
# R.assign "add.constant", 0
# (3) blank value (A Real Number)
if (self.blank_value == nil)
R.eval "blank.value <- NULL"
elsif (self.blank_value == 0)
R.eval "blank.value <- 0"
else
R.assign "blank.value", self.blank_value
end
@@ -303,16 +328,40 @@ class Assay
R.assign 'use.linear.param', 'F'
R.assign 'smooth.param', 0.1 # default value
end
## Heatmap values
if (self.specg_max != '' && self.specg_min != '')
R.assign 'specMin', self.specg_min
R.assign 'specMax', self.specg_max
R.eval "specRange <- c(specMin, specMax)"
else
R.eval 'specRange <- NA'
end
if (self.totg_min != '' && self.totg_max != '')
R.assign 'totMin', self.totg_min
R.assign 'totMax', self.totg_max
R.eval "totalRange <- c(totMin, totMax)"
else
R.eval 'totalRange <- NA'
end
if (self.lagT_min != '' && self.lagT_max != '')
R.assign 'lagT_min', self.lagT_min
R.assign 'lagT_max', self.lagT_max
R.eval "lagRange <- c(lagT_min, lagT_max)"
else
R.eval 'lagRange <- NA'
end
# This block evaluates the files (csv or xlsx, single.plate or multiple.plate)
R.eval ('R_file_return_value <- gcat.analysis.main(file, single.plate, layout.file, out.dir=out.dir, graphic.dir = out.dir, add.constant, blank.value,
start.index, growth.cutoff, use.linear.param=use.linear.param, use.loess=use.loess, smooth.param=smooth.param,
points.to.remove = points.to.remove, remove.jumps, time.input, plate.nrow = 8, plate.ncol = 12, input.skip.lines = 0,
multi.column.headers = c("Plate.ID", "Well", "OD", "Time"), single.column.headers = c("","A1"),
start.index, growth.cutoff, use.linear.param=use.linear.param, use.loess=use.loess, smooth.param=smooth.param, lagRange = lagRange,
totalRange = totalRange, specRange = specRange, points.to.remove = points.to.remove, remove.jumps, time.input, plate.nrow = 8,
plate.ncol = 12, input.skip.lines = 0, multi.column.headers = c("Plate.ID", "Well", "OD", "Time"), single.column.headers = c("","A1"),
layout.sheet.headers = c("Strain", "Media Definition"), silent = T, verbose = F, return.fit = F, overview.jpgs = T)')
# good file returns a list of file path(length is more than 1), bad file returns error message string(array length = 1)
print R.R_file_return_value
R.eval ('R_array_return_length <- length(R_file_return_value)')
unless R.R_array_return_length == 1
puts R.R_file_return_value, "\n"
@@ -323,16 +372,23 @@ class Assay
if(error_message.include? "Error in <remove.points>")
num_data_points = error_message.split("data has ").last.gsub("\n\n", "")
error_message = "Invalid 'Points to ignore'. Please select a value in the range (1-#{num_data_points})."
else
# debugger
console_message = error_message
split_s = error_message.split(":")
print split_s
split_s.each {|x| error_message = x}
end
return {:error_message => error_message, :path => inputfile}
return {:error_message => error_message, :path => inputfile, :console_msg => console_message}
end
# process generated files
raise "no files generated" if files.empty?
#search for "_overview.jpg files" from Array of files
overviewFiles = ""
pdfFile = ""
txtFile = ""
consoleOut = ""
files_Array_Size = files.size - 1
for i in 0..files_Array_Size
@@ -368,6 +424,7 @@ class Assay
# build array named overviewFiles that contains "_overview.jpg files"
overviewFiles = overviewFiles.split("\n")
raise "no overview files generated" if overviewFiles.empty?
if self.plate_type == 'm'
@@ -375,18 +432,20 @@ class Assay
else
zipfile = out_dir_path + "/singlePlateAnalysis.zip"
end
consoleOut = out_dir_path + "/console.out"
self.console_out = consoleOut
# create Zip files at current directory
Zip::File.open(zipfile, Zip::File::CREATE) { |zf|
files.each{|file| zf.add(File.basename(file), file)}
#files.each{|file| zf.add(file.sub(out_dir_path + "/", ""), file))}
#zf.add(File.basename(consoleOut), consoleOut)
}
#return results unless error
#zip files, jpg of overviews, txt file for datagrid, pdf file
{:status => status, :overviewFiles => overviewFiles, :zipfile => zipfile, :txtFile => txtFile, :pdfFile => pdfFile, :inputfile => inputfile, :layout_file => layout_file, :model => self.model}
{:status => status, :overviewFiles => overviewFiles, :zipfile => zipfile, :txtFile => txtFile, :pdfFile => pdfFile, :inputfile => inputfile, :layout_file => layout_file, :model => self.model,
:consoleout => consoleOut}
end # end of r_calculation method
+138 -126
View File
@@ -1,112 +1,106 @@
<%= form_for @assay do |f| %>
<% if @assay.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@assay.errors.count, "error") %> prohibited this assay from being saved:</h2>
<ul>
<% @assay.errors.full_messages.each do |msg| %>
<% if @assay.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@assay.errors.count, "error") %> prohibited this assay from being saved:</h2>
<ul>
<% @assay.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<h3>Plate Type</h3>
<%= f.radio_button(:plate_type, 's', :checked => true) %>
<%= f.label(:plate_type_single, "Single-plate") %><br />
<%= f.radio_button(:plate_type, 'm', :checked => false) %>
<%= f.label(:plate_type_single, "Multiple-plate") %><br />
<h3>Input Data File</h3>
Please specify a plate results file to upload for analysis:<br>
<div class="field">
<%= f.file_field :input_file %>
</div>
<h3><span data-tooltip="Optionally upload a companion .csv file containing identifying information for all wells in the experiments(s) to be analyzed, including strain identifiers and growth media (or growth environment) definitions, which are used for graphic output.">Plate Layout File</span></h3>
Optionally upload a plate layout file:<br>
<div class="field">
<%= f.file_field :layout_file %>
</div>
<div class="actions" style="margin-top:30px;">
<%= link_to "Single-Plate Example File","/resources/YPDAFEXglucoseTests_2-25-10.csv" %><br>
<%= link_to "Single-Plate Layout Example File","/resources/YPDAFEXglucoseTests_2-25-10_Layout.csv" %><br>
<%= link_to "Multi-Plate Example File","/resources/test_YYYY_MM_DD_HH_MM_SS.csv" %><br>
<%= link_to "Multi-Plate Layout Example File","/resources/MultiPlateLayout_plateID.csv" %>
</div>
<h3><span data-tooltip="OD value for blank well read. As the default option <NULL>, GCAT will automatically take the first OD reading of each well to be the blank.">Media background</span></h3>
<%= f.radio_button(:blank_value, "default", {:checked => true, :class => "user_enter3 user_enter3_no"}) %>
<%= f.label(:blank_value_blank_value_default, "Take the first OD reading of each well to be the blank") %><br />
<%= f.radio_button(:blank_value, "user", {:class => "user_enter3 user_enter3_yes"}) %>
<%= f.label(:blank_value_user, "User Input.") %>
<div class="field optional_input3" style="display:none">
<%= f.text_field :blank_value_input, :placeholder => 'Enter your OD blank value here' %>
</div>
<h3><span data-tooltip="GCAT transforms optical density (OD) to log(x+δ). x = OD Media background. Specify a value for n or choose from the defaults. Note: 0 is not recommended unless all wells contain many repeated measurements for initial density that can be used to accurately estimate the baseline density. See the user manual for more details.">OD Transform</span></h3>
<%= f.radio_button(:transformation, 1, {:checked => true, :class => "user_enter2 user_enter2_no"}) %>
<%= f.label(:transformation_one, "log(x + 0.1)") %><br />
<%= f.radio_button(:transformation, 0, {:class => "user_enter2 user_enter2_no"}) %>
<%= f.label(:transformation_zero, "log(x)") %><br />
<%= f.radio_button(:transformation, -1, {:class => "user_enter2 user_enter2_yes"}) %>
<%= f.label(:transformation_any, "log(x + δ)") %>
<div class="field optional_input2" style="display:none">
<%= f.text_field :transformation_input, :placeholder => 'Enter your n value here'%>
</div>
<h3><span data-tooltip="Choose the preferred growth curve model selection available below.">Growth curve model</span></h3>
<%= f.radio_button(:model, 1, {:checked => true, :class => "user_enter1 user_enter1_no"})%>
<%= f.label(:model_one, "Sigmoid curve") %>
<%#= f.radio_button(:model, 0, {:class => "user_enter1 user_enter1_no"}) %>
<%#= f.label(:model_zero, "Sigmoid + linear") %>
<%= f.radio_button(:model, -1, {:class => "user_enter1 user_enter1_yes"}) %>
<%= f.label(:model_any, "LOESS. The default smoothing value is 0.1.") %>
<div class="field optional_input1" style="display:none">
<%= f.text_field :loess_input, :placeholder => 'Enter the smoothing value here.'%>
</div>
<h3><span data-tooltip="Enter the index of the timepoint at which the wells were inoculated with the culture.
" >Inoculation timepoint</span></h3>
<div class="field">
<%= f.label :start_index, "Enter the timepoint index (positive integer only). The default value is 2. " %><br />
<%= f.text_field(:start_index, :type => 'number', :min =>'1', :size => '3', :value => '2') %>
</div>
<h3><span data-tooltip="Enter a threshold to determine the presence of a growing culture. GCAT rejects curves where the density measurements never reach this value above the specified inoculation timepoint." >Growth Threshold</span></h3>
<div class="field">
<%= f.label :growth_threshold, "Enter the growth threshold. The default value is 0.05. " %><br />
<%= f.text_field(:growth_threshold, :type => 'number', :min =>'0', :size => '3', :value => '0.05', :step => "0.01") %>
</div>
<h3><span data-tooltip="Enter indices (as a comma-separated list) of any erroneous reads that should be removed across the entire experiment. " >Points to ignore</span></h3>
<div class="field">
<%= f.label :remove_points,"Enter a comma-separated list of points. Example: 2,3,4,5 (positive integers only). The default is an empty list." %><br />
<%= f.text_field :remove_points %>
</div>
<% end %>
</ul>
</div>
<% end %>
<div class="actions" style="margin-top:30px;">
<%= link_to "GCAT Users Manual","/resources/GCAT_users_manual.pdf" %> </br>
<%= link_to "GCAT Release Notes","/resources/Release_Notes.pdf" %>
</div>
<section>
<ul id="options">
<li>
<h3>Plate Type</h3>
<%= f.radio_button(:plate_type, 's', :checked => true) %>
<%= f.label(:plate_type_single, "Single-plate") %><br />
<%= f.radio_button(:plate_type, 'm', :checked => false) %>
<%= f.label(:plate_type_single, "Multiple-plate") %><br />
</li>
<li>
<h3>Input Data File</h3>
Please specify a plate results file to upload for analysis:<br>
<div class="field">
<%= f.file_field :input_file %>
</div>
<div class="actions" style="margin-top:30px;">
<%= link_to "Single-Plate Example File","/resources/YPDAFEXglucoseTests_2-25-10.csv" %><br>
<%= link_to "Multi-Plate Example File","/resources/test_YYYY_MM_DD_HH_MM_SS.csv" %><br>
</div>
</li>
<li>
<h3><span data-tooltip="Optionally upload a companion .csv file containing identifying information for all wells in the experiments(s) to be analyzed, including strain identifiers and growth media (or growth environment) definitions, which are used for graphic output.">Plate Layout File</span></h3>
Optionally upload a plate layout file:<br>
<div class="field">
<%= f.file_field :layout_file %>
</div>
<div class="actions" style="margin-top:30px;">
<%= link_to "Single-Plate Layout Example File","/resources/YPDAFEXglucoseTests_2-25-10_Layout.csv" %><br>
<%= link_to "Multi-Plate Layout Example File","/resources/MultiPlateLayout_plateID.csv" %>
</div>
</li>
<li>
<h3><span data-tooltip="OD value for blank well read. As the default option <NULL>, GCAT will automatically take the first OD reading of each well to be the blank.">Media background</span></h3>
<%= f.radio_button(:blank_value, "zero", {:class => "user_enter3 user_enter3_no"}) %>
<%= f.label(:blank_value_zero, "0" ) %> <br/>
<%= f.radio_button(:blank_value, "default", {:class => "user_enter3 user_enter3_no"}) %>
<%= f.label(:blank_value_default, "Take the first OD reading of each well to be the blank") %><br>
<%= f.radio_button(:blank_value, "user", {:checked => true, :class => "user_enter3 user_enter3_yes"}) %>
<%= f.label(:blank_value_user, "User Input.") %>
<div class="field optional_input3" style="display:none">
<%= f.text_field :blank_value_input, :placeholder => 'Enter your OD blank value here' %>
</div>
</li>
<li>
<h3><span data-tooltip="GCAT transforms optical density (OD) to log(x+δ). x = OD Media background. Specify a value for n or choose from the defaults. Note: 0 is not recommended unless all wells contain many repeated measurements for initial density that can be used to accurately estimate the baseline density. See the user manual for more details.">OD Transform</span></h3>
<%= f.radio_button(:transformation, 0, {:checked => true, :class => "user_enter2 user_enter2_no"}) %>
<%= f.label(:transformation_zero, "log(x)") %><br />
<%= f.radio_button(:transformation, 0.1, {:class => "user_enter2 user_enter2_no"}) %>
<%= f.label(:transformation_one, "log(x + 0.1)") %><br />
<%= f.radio_button(:transformation, -1, {:class => "user_enter2 user_enter2_yes"}) %>
<%= f.label(:transformation_any, "log(x + δ)") %>
<div class="field optional_input2" style="display:none">
<%= f.text_field :transformation_input, :placeholder => 'Enter your δ value here'%>
</div>
</li>
<li>
<h3><span data-tooltip="Choose the preferred growth curve model selection available below.">Growth curve model</span></h3>
<%= f.radio_button(:model, 1, {:checked => true, :class => "user_enter1 user_enter1_no"})%>
<%= f.label(:model_one, "Sigmoid curve") %><br />
<%#= f.radio_button(:model, 0, {:class => "user_enter1 user_enter1_no"}) %>
<%#= f.label(:model_zero, "Sigmoid + linear") %>
<%= f.radio_button(:model, -1, {:class => "user_enter1 user_enter1_yes"}) %>
<%= f.label(:model_any, "LOESS. The default smoothing value is 0.1.") %>
<div class="field optional_input1" style="display:none">
<%= f.text_field :loess_input, :placeholder => 'Enter the smoothing value here.'%>
</div>
</li>
<li>
<h3><span data-tooltip="Enter the index of the timepoint at which the wells were inoculated with the culture.
" >Inoculation timepoint</span></h3>
<div class="field">
<%= f.label :start_index, "Enter the timepoint index (positive integer only). The default value is 2. " %><br />
<%= f.text_field(:start_index, :type => 'number', :min =>'1', :size => '3', :value => '2') %>
</div>
</li>
<li>
<h3><span data-tooltip="Enter a threshold to determine the presence of a growing culture. GCAT rejects curves where the density measurements never reach this value above the specified inoculation timepoint." >Growth Threshold</span></h3>
<div class="field">
<%= f.label :growth_threshold, "Enter the growth threshold. The default value is 0.05. " %><br />
<%= f.text_field(:growth_threshold, :type => 'number', :min =>'0', :size => '3', :value => '0.05', :step => "0.01") %>
</div>
</li>
<li>
<h3><span data-tooltip="Enter indices (as a comma-separated list) of any erroneous reads that should be removed across the entire experiment. " >Points to ignore</span></h3>
<div class="field">
<%= f.label :remove_points,"Enter a comma-separated list of points. Example: 2,3,4,5 (positive integers only). The default is an empty list." %><br />
<%= f.text_field :remove_points %>
</div>
<!--<h3><span data-tooltip="GCAT automatically detects sudden changes in OD ('jumps'). Check this box if these instances should be removed when possible. If only one or two jumps are present GCAT will attempt to remove only the affected region." >Remove Jumps</span></h3>-->
<%#= f.check_box(:remove_jumps) %>
<%#= f.label(:remove_jumps, "Employ the jump detection algorithm to attempt to remove problematic points.") %>
@@ -122,26 +116,44 @@ Optionally upload a plate layout file:<br>
<%= f.text_field(:plate_dimensions_column, :type => 'number', :min =>'1', :size => '3', :value => '12') %>
</div>
<%
=end %>
<div id="time" class="field">
<h3><span data-tooltip="Select a correctly formatted timestamp (see user manual for details). The timestamp will be used to convert the time entries into the number of hours." >Timestamp format</span></h3>
<%= f.label :timestamp_format %><br />
<%#= f.text_field(:timestamp_format, :value => '1/3600', :id => 'adam') %>
<%= f.select :timestamp_format, options_for_select(date_time_options()) %>
</div>
<div class="actions" style="margin-top:30px;">
=end %>
</li>
<li>
<div id="time" class="field">
<h3><span data-tooltip="Select a correctly formatted timestamp (see user manual for details). The timestamp will be used to convert the time entries into the number of hours." >Timestamp format</span></h3>
<%= f.label :timestamp_format %><br />
<%#= f.text_field(:timestamp_format, :value => '1/3600', :id => 'adam') %>
<%= f.select :timestamp_format, options_for_select(date_time_options()) %>
</div>
</li>
<li>
<h3><span data-tooltip="Select the range for the heatmaps for easier comparison.">Heatmap options</span></h3>
<div class="field">
<%= f.label "Enter the range for the total growth." %><br />
<%= f.text_field(:totg_min, :type => 'number', :min => '0', :size => '2') %>
<%= f.label "-" %>
<%= f.text_field(:totg_max, :type => 'number', :min => '1', :size => '2') %>
</div>
<div class="field">
<%= f.label "Enter the range for the specific growth." %><br />
<%= f.text_field(:specg_min, :type => 'number', :min => '0', :size => '2') %>
<%= f.label "-" %>
<%= f.text_field(:specg_max, :type => 'number', :min => '1', :size => '2') %>
</div>
<div class="field">
<%= f.label "Enter the range for the lag time." %><br />
<%= f.text_field(:lagT_min, :type => 'number', :min => '0', :size => '2') %>
<%= f.label "-" %>
<%= f.text_field(:lagT_max, :type => 'number', :min => '1', :size => '2') %>
</div>
</li>
<div class="actions" style="margin-top:30px; clear:both;">
<%= f.submit %>
</div>
<div class="actions" style="margin-top:30px;">
<%= mail_to "gcat.help@glbrc.wisc.edu","Please Send Any Questions To The GLBRC Help Desk And Be Sure To Include 'GCAT' In Your Subject Title", :subject => "GCAT" %>
<div class="actions" style="margin-top:30px; clear:both;">
<%= mail_to "gcat.help@glbrc.wisc.edu","Please Send Any Questions To The GLBRC Help Desk And Be Sure To Include 'GCAT' In Your Subject Title", :subject => "GCAT" %>
</div>
<div class="actions" style="margin-top:30px;">
<%= link_to "GCAT Users Manual","/resources/GCAT_users_manual.pdf" %>
</div>
<% end %>
</ul>
</section>
<% end %>
@@ -1,6 +1,21 @@
<div id="form-container">
<h1>Error</h1>
<p>Please resubmit your file.</p>
<%= link_to 'New Assay', new_assay_path%>
<h1>Error</h1>
<%= @error_msg %>
</br></br>
<button type="button" id ="show">Full console message</button>
<div id="console" style="display:none;">
<code><%= @console_msg %></code>
</div>
<script>
$(function() {
$('button#show').click(function(event){
event.preventDefault();
$('div#console').toggle();
});
});
</script>
</br>
<h5>Please resubmit your file.</h5>
<%= link_to 'New Assay', new_assay_path%>
<br><br><br>
</div>
</div>
+1 -1
View File
@@ -1,7 +1,7 @@
<div id="form-container">
<h1>Growth Curve Analysis Tool</h1>
<div style="width:25%;">
<div style="width:45%;">
This tool processes microbial growth curve data collected in a microtiter plate format and
generates a table of biologically meaningful growth curve characteristics, as well as relevant
plots. These characteristics can be used to select strains with optimal growth properties.
+1 -1
View File
@@ -39,4 +39,4 @@
</tr>
<% end %>
</table>
</div>
</div>
@@ -19,6 +19,7 @@
Copyright &copy; 2012 The Board of Regents of the University of Wisconsin System
<%= image_tag 'lgplv.jpg' %>
<%= image_tag 'GLBRC_horz_cmyk_small.jpg' %>
<%= image_tag 'DOE_Logo_Color.png', :size => "292x72" %>
</div>
</div>
</body>