The distribution may have patches associated with it. They are available
+ from http://meme.nbcr.net/downloads/.
+-The patch file name is filename.VERSION.patch. In addition, a
+-patched file is distributed as well and can be used as a drop-in substitute
+-for the original file. The drop-in file is filename.VERSION.
+-It is necessary to download only one of the two files depending on the method used for
+-patching. All patches for a specific version should be installed. The list
+-below provides instructions for installation of availble patches for specific
+-version.
++Patch files are located in a directory named
++VERSION.patches,
++for example, meme_3.5.4.patches.
++Patch file have names like:
++VERSION.patch_SERIAL_NO, for example, meme_3.5.4.patch_3.
++
To install a patch, download the patch file from the URL given above.
++Then perform the following commands to install it:
++ $ cp PATCH_FILE VERSION $ cd VERSION
++ $ patch -p1 < PATCH_FILE
++ $ make install
++ $ make test
++
++
++For example, to install the first patch to version meme_3.5.4, you would perform the following commands:
++ $ cp meme_3.5.4.patch_1 meme_3.5.4
++ $ cd meme_3.5.4
++ $ patch -p1 < meme_3.5.4.patch_1
++ $ make install
++ $ make test
++
++
++You must install all of the patches for a specific version in serial
++number order. For example, if you wish to install patch number 3,
++you must first have installed patches number 1 and 2 for that version.
++This is easy to do. Just download all the patches for your current
++version, copy them to your current versions's directory, and then
++install them in order by repeating the patch,
++command above, with each patch file. You only need to run the
++install and
++make test commands once, after
++the last patch command.
+
+
+-
+-
+-
+-
Version
+-
Patch list
+-
Installation
+-
+-
+-
3.5.0
+-
mast-client.txt
+-
+-
+-
If downloaded a patch file mast-client.txt.3.5.0.patch:
+- # cp mast-client.txt.3.5.0 meme_3.5.0/scripts/
+- # cd meme_3.5.0/scripts/
+- # patch -p0 < mast-client.txt.3.5.0.patch
+-
+-
+-
If downloaded a patched file mast-client.txt.3.5.0:
+- # cp mast-client.txt.3.5.0 meme_3.5.0/scripts/mast-client.txt
+-
+
diff --git a/tools/meme-suite/sources/meme_3.5.4.patch_2 b/tools/meme-suite/sources/meme_3.5.4.patch_2
new file mode 100644
index 0000000000000000000000000000000000000000..cc07a98307f2712124e52fbacdc5c4f726adb58b
--- /dev/null
+++ b/tools/meme-suite/sources/meme_3.5.4.patch_2
@@ -0,0 +1,70 @@
+--- meme_3.5.4/website/cgi-bin/meme.pl 2006-09-21 19:46:29.000000000 +0000
++++ trunk/website/cgi-bin/meme.pl 2007-09-10 00:28:33.000000000 +0000
+@@ -1,6 +1,6 @@
+ #!@WHICHPERL@
+ ##
+-## $Id: meme.pl 1339 2006-09-21 19:46:28Z tbailey $
++## $Id: meme.pl 2054 2007-09-10 00:27:42Z tbailey $
+ ##
+ ## $Log$
+ ## Revision 1.12 2006/03/07 23:30:19 nadya
+@@ -467,21 +467,21 @@
+
+ # check against allowed dna letters
+ $x = $_;
+- $x =~ tr/ABCDGHKMNRSTUVWY//cd;
++ $x =~ tr/ABCDGHKMNRSTUVWY*-//cd;
+ $new = length $x;
+ if ($old == $new) {
+ "dna";
+ } else {
+ # check against allowed protein letters
+ $x = $_;
+- $x =~ tr/ABCDEFGHIKLMNPQRSTUVWXYZ//cd;
++ $x =~ tr/ABCDEFGHIKLMNPQRSTUVWXYZ*-//cd;
+ $new = length $x;
+ if ($old == $new) {
+ "protein";
+ } else {
+ # get the unknown letters
+ $x = $_;
+- $x =~ tr/ABCDEFGHIKLMNPQRSTUVWXYZ//d;
++ $x =~ tr/ABCDEFGHIKLMNPQRSTUVWXYZ*-//d;
+ &whine("
+ Your sequences contained the following unrecognized letters: $x.
+
+--- meme_3.5.4/website/cgi-bin/mast.pl 2006-09-21 19:46:29.000000000 +0000
++++ trunk/website/cgi-bin/mast.pl 2007-09-10 00:38:14.000000000 +0000
+@@ -1,6 +1,6 @@
+ #!@WHICHPERL@
+ ##
+-## $Id: mast.pl 1339 2006-09-21 19:46:28Z tbailey $
++## $Id: mast.pl 2055 2007-09-10 00:37:11Z tbailey $
+ ##
+ ## $Log$
+ ## Revision 1.8 2006/03/07 23:30:19 nadya
+@@ -479,21 +479,21 @@
+
+ # check against allowed nucleotide letters
+ $x = $_;
+- $x =~ tr/ABCDGHKMNRSTUVWY//cd;
++ $x =~ tr/ABCDGHKMNRSTUVWY*-//cd;
+ $new = length $x;
+ if ($old == $new) {
+ return("DNA");
+ } else {
+ # check against allowed protein letters
+ $x = $_;
+- $x =~ tr/ABCDEFGHIKLMNPQRSTUVWXYZ//cd;
++ $x =~ tr/ABCDEFGHIKLMNPQRSTUVWXYZ*-//cd;
+ $new = length $x;
+ if ($old == $new) {
+ return("PROTEIN");
+ } else {
+ # get the unknown letters
+ $x = $_;
+- $x =~ tr/ABCDEFGHIKLMNPQRSTUVWXYZ//d;
++ $x =~ tr/ABCDEFGHIKLMNPQRSTUVWXYZ*-//d;
+ &whine("
+ Your sequences contained the following unrecognized letters: $x.
+
diff --git a/tools/meme-suite/sources/meme_3.5.4.tar.gz b/tools/meme-suite/sources/meme_3.5.4.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..01ae8ca904c6c7d980d9abb589d084ba52edee95
--- /dev/null
+++ b/tools/meme-suite/sources/meme_3.5.4.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b753ee276bc5eafeab8ff310e6d938977da11f466d26cfd3ae9c0f0a7a91de86
+size 1045501
diff --git a/tools/meme-suite/sources/meme_3.5.7-unpatched.tar.gz b/tools/meme-suite/sources/meme_3.5.7-unpatched.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..df0422f32af5e1e0a0903156a91ad5648f918c2e
--- /dev/null
+++ b/tools/meme-suite/sources/meme_3.5.7-unpatched.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b5d84d969f69dbe02f2636e2161c53212f7c9a5b141ae2ed759f99a322f221a9
+size 1101383
diff --git a/tools/meme-suite/sources/meme_3.5.7.tar.gz b/tools/meme-suite/sources/meme_3.5.7.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..df0422f32af5e1e0a0903156a91ad5648f918c2e
--- /dev/null
+++ b/tools/meme-suite/sources/meme_3.5.7.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b5d84d969f69dbe02f2636e2161c53212f7c9a5b141ae2ed759f99a322f221a9
+size 1101383
diff --git a/tools/meme-suite/sources/meme_4.0.0-unpatched.tar.gz b/tools/meme-suite/sources/meme_4.0.0-unpatched.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..40eeda0f11bea77af9438b00e43becd1838704ba
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.0.0-unpatched.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:154ec37a7bee4f446cfba213c059893a4156538e3c8955bf52f0a175181006bc
+size 4344008
diff --git a/tools/meme-suite/sources/meme_4.0.0.tar.gz b/tools/meme-suite/sources/meme_4.0.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..40eeda0f11bea77af9438b00e43becd1838704ba
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.0.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:154ec37a7bee4f446cfba213c059893a4156538e3c8955bf52f0a175181006bc
+size 4344008
diff --git a/tools/meme-suite/sources/meme_4.1.0-unpatched.tar.gz b/tools/meme-suite/sources/meme_4.1.0-unpatched.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..7554342689693ec6bb38fa006bfd0a747c9e9a32
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.1.0-unpatched.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b80a380353144c4ea434583b9cece5f050e798c5bbe1c13f20257e53fb0b9514
+size 4490664
diff --git a/tools/meme-suite/sources/meme_4.1.0.tar.gz b/tools/meme-suite/sources/meme_4.1.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..7554342689693ec6bb38fa006bfd0a747c9e9a32
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.1.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b80a380353144c4ea434583b9cece5f050e798c5bbe1c13f20257e53fb0b9514
+size 4490664
diff --git a/tools/meme-suite/sources/meme_4.1.1-unpatched.tar.gz b/tools/meme-suite/sources/meme_4.1.1-unpatched.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..4dcd42dd04971b5f73222b8644ebf9fb1d8239f6
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.1.1-unpatched.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:681ecf3fe56cf5822365d3abd9727ae3c5503d49f8817bb0fe328d9f07b91011
+size 4662066
diff --git a/tools/meme-suite/sources/meme_4.1.1.tar.gz b/tools/meme-suite/sources/meme_4.1.1.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..4dcd42dd04971b5f73222b8644ebf9fb1d8239f6
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.1.1.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:681ecf3fe56cf5822365d3abd9727ae3c5503d49f8817bb0fe328d9f07b91011
+size 4662066
diff --git a/tools/meme-suite/sources/meme_4.10.0.tar.gz b/tools/meme-suite/sources/meme_4.10.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..5ec88f66825ace4d52081c0f553296d85751f01d
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.10.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f5e4d6c898f7a0002b679020c912ef41c3ae3985faf9a88631f8aab506ad952e
+size 16387193
diff --git a/tools/meme-suite/sources/meme_4.10.0_4.tar.gz b/tools/meme-suite/sources/meme_4.10.0_4.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..0301a31a24bacc29a5e6cfa91417fe6df68e0e22
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.10.0_4.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2e0266102f5a510ed75b9275e8c1d138891bb8012ee4261a7f9f5c011c315a50
+size 16573961
diff --git a/tools/meme-suite/sources/meme_4.10.1.tar.gz b/tools/meme-suite/sources/meme_4.10.1.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..0a04af8a1752dc5025373bbe33575f61ca2a4cc3
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.10.1.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:642838908e9f26eabea04c8fea2f9f2f4d24def5603436d3db1e96c954fc92eb
+size 16336694
diff --git a/tools/meme-suite/sources/meme_4.10.1_4.tar.gz b/tools/meme-suite/sources/meme_4.10.1_4.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..c7815b58d724df620ba0f095125005621a6ce684
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.10.1_4.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:cc17de16cce0f8ba6bdf4b57a9ea47b2b1130ede7ce30882d077b24ef0f7e1cd
+size 16472636
diff --git a/tools/meme-suite/sources/meme_4.10.2.tar.gz b/tools/meme-suite/sources/meme_4.10.2.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..d8242a360086006320c71c3834ea3dec01c8b474
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.10.2.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f280270d9ff95a0f863aac4362d35d4183e2df62dc2a090a5d704ab6a231193c
+size 16156712
diff --git a/tools/meme-suite/sources/meme_4.11.0.tar.gz b/tools/meme-suite/sources/meme_4.11.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..9052c56e6793c00601b3be19866b2b4240325808
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.11.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5dc4841f4816ef25bdb4bd088c76606c1b42726e7d65cc417f0f8c49fe7e237f
+size 14378600
diff --git a/tools/meme-suite/sources/meme_4.11.1.tar.gz b/tools/meme-suite/sources/meme_4.11.1.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..c27fd416f59c4bb8b0e82673522c8317368acd7c
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.11.1.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:62602045b25c8422c59f441025b710629c2fbb602bf618fffeeab5654f521088
+size 17752135
diff --git a/tools/meme-suite/sources/meme_4.11.2.tar.gz b/tools/meme-suite/sources/meme_4.11.2.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..11be9a50e5976ff26b4b7d60f02b749a8dc59171
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.11.2.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6e3ff843366588ea13fa8060306be9e2c144521912dfb268f03638003bcdd581
+size 18004930
diff --git a/tools/meme-suite/sources/meme_4.11.2_2.tar.gz b/tools/meme-suite/sources/meme_4.11.2_2.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..e619806e104a4c7a76622b51572ad3a3dbd5ca50
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.11.2_2.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:377238c2a9dda64e01ffae8ecdbc1492c100df9b0f84132d50c1cf2f68921b22
+size 18003628
diff --git a/tools/meme-suite/sources/meme_4.11.3.tar.gz b/tools/meme-suite/sources/meme_4.11.3.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..7f16199da0a7a9437ea32760cff112939d31511f
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.11.3.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3a6875ce940113b56c10fdd664f25fd40b83e2f44b8acb3b29c3b628ebf60322
+size 19130156
diff --git a/tools/meme-suite/sources/meme_4.11.3_1.tar.gz b/tools/meme-suite/sources/meme_4.11.3_1.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..d00a6b492e9cc535a27f832052c7dabe6ade389f
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.11.3_1.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:eca526fa1c06f07ed255bbb111091e0f02d74eae97ea44cec06a851f1f27ae21
+size 19155825
diff --git a/tools/meme-suite/sources/meme_4.11.4.tar.gz b/tools/meme-suite/sources/meme_4.11.4.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..04d5a616e5a13d24e988826340cb3e4ea402f220
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.11.4.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3e869ff57e327a9c8615dbef784e3f1095f7f7a0120cecd55efe10c3f2ee8eb3
+size 19499190
diff --git a/tools/meme-suite/sources/meme_4.11.4_1.tar.gz b/tools/meme-suite/sources/meme_4.11.4_1.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..0493592923c2c31db82a7f4c566cc4552e8dd27f
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.11.4_1.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:418c4f4c3a56a852ee277445f0c16157e02fd6ebb0e01b6a7d7190cbce338ddb
+size 20384384
diff --git a/tools/meme-suite/sources/meme_4.12.0.tar.gz b/tools/meme-suite/sources/meme_4.12.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..478451813c19a0a8424d31222c578f569571bf94
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.12.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:49ff80f842b59d328588acfcd1d15bf94c55fed661d22b0f95f37430cc363a06
+size 21134349
diff --git a/tools/meme-suite/sources/meme_4.2.0-unpatched.tar.gz b/tools/meme-suite/sources/meme_4.2.0-unpatched.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..f5a2f265b7f2f8ee0049d0b55456cbe83f6acc45
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.2.0-unpatched.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9a74d976288f6b0a0f49bd126d14efbdc5be60812d53d1ec88f506f3b16d8cff
+size 4581167
diff --git a/tools/meme-suite/sources/meme_4.2.0.tar.gz b/tools/meme-suite/sources/meme_4.2.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..f5a2f265b7f2f8ee0049d0b55456cbe83f6acc45
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.2.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9a74d976288f6b0a0f49bd126d14efbdc5be60812d53d1ec88f506f3b16d8cff
+size 4581167
diff --git a/tools/meme-suite/sources/meme_4.3.0.tar.gz b/tools/meme-suite/sources/meme_4.3.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..516f7dc999184f4a5d7563458c2e815ba5d04701
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.3.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6a6a04f168f8ac6dbba022461701e0327bc8ececcb375b2dd387a084cd8ba17b
+size 4658395
diff --git a/tools/meme-suite/sources/meme_4.4.0.patch_1 b/tools/meme-suite/sources/meme_4.4.0.patch_1
new file mode 100644
index 0000000000000000000000000000000000000000..07609dd27681398766f9be049b5cf2669532906d
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.4.0.patch_1
@@ -0,0 +1,660 @@
+Index: scripts/ama-qvalues.txt
+===================================================================
+--- scripts/ama-qvalues.txt (revision 0)
++++ scripts/ama-qvalues.txt (revision 4529)
+@@ -0,0 +1,128 @@
++#!@WHICHPERL@
++# AUTHOR: Timothy L. Bailey
++# CREATE DATE: May 7, 2010
++#use strict;
++use File::Basename;
++
++$PGM = $0; # name of program
++$PGM =~ s#.*/##; # remove part up to last slash
++#@args = @ARGV; # arguments to program
++$| = 1; # flush after all prints
++$SIG{'INT'} = \&cleanup; # interrupt handler
++# Note: so that interrupts work, always use for system calls:
++# if ($status = system("$command")) {&cleanup($status)}
++
++# requires
++push(@INC, split(":", $ENV{'PATH'})); # look in entire path
++
++# defaults
++my $seed = 1;
++my $bootstraps = 1000;
++
++my $usage = <] seed for random numbers; default: $seed
++ [-bootstraps ] number of bootstraps to perform
++ while computing pi_0; default: 1000
++
++ Read an AMA output file and output each sequence name, p-value
++ and q-value. At the end of file, the value of pi_0 (number of
++ sequences not showing significant binding to motif) is shown,
++ unless there are fewer than 100 p-values in the input.
++
++ Reads standard input.
++ Writes standard output.
++
++ Copyright
++ (2010) The University of Queensland
++ All Rights Reserved.
++ Author: Timothy L. Bailey
++USAGE
++
++$nargs = 0; # number of required args
++if ($#ARGV+1 < $nargs) { &print_usage("$usage", 1); }
++
++# get input arguments
++while ($#ARGV >= 0) {
++ $_ = shift;
++ if ($_ eq "-h") { # help
++ &print_usage("$usage", 0);
++ } elsif ($_ eq "-seed") {
++ $seed = shift;
++ } elsif ($_ eq "-bootstraps") {
++ $bootstraps = shift;
++ } else {
++ &print_usage("$usage", 1);
++ }
++}
++
++# open a pipe to the qvalue program, reading standard input
++$pzfile = "$PGM.$$.pzfile.tmp";
++open(QVALUE, "|qvalue --append --column 2 --pi-zero-file $pzfile --seed $seed --bootstraps $bootstraps -") ||
++ die("Can't open qvalue program.\n");
++
++# compute the qvalues
++print "# sequence_name\t\t\tp-value\t\tq-value\n";
++my($pvalue, @w, $name);
++my $npvalues = 0;
++while () {
++ if (/pvalue="([^"]*)"/) {
++ $pvalue = $1;
++ /name="([^"]*)"/;
++ $name = $1;
++ print(QVALUE "$name\t$pvalue\n");
++ $npvalues++;
++ }
++};
++close(QVALUE);
++
++printf("# Fraction of sequences not showing significant binding: ");
++system("cat $pzfile") if ($npvalues >= 100);
++unlink $pzfile;
++
++$status = 1;
++
++# cleanup files
++&cleanup($status, "");
++
++################################################################################
++# Subroutines #
++################################################################################
++
++################################################################################
++#
++# print_usage
++#
++# Print the usage message and exit.
++#
++################################################################################
++sub print_usage {
++ my($usage, $status) = @_;
++
++ if (-c STDOUT) { # standard output is a terminal
++ open(C, "| more");
++ print C $usage;
++ close C;
++ } else { # standard output not a terminal
++ print STDERR $usage;
++ }
++
++ exit $status;
++}
++
++################################################################################
++# cleanup
++#
++# cleanup stuff
++#
++################################################################################
++sub cleanup {
++ my($status, $msg) = @_;
++ if ($status eq "INT") {
++ exit(1);
++ } else {
++ if ($status && "$msg") {print STDERR "$msg: $status\n";}
++ }
++}
+Index: scripts/fasta-subsample.txt
+===================================================================
+--- scripts/fasta-subsample.txt (revision 0)
++++ scripts/fasta-subsample.txt (revision 4529)
+@@ -0,0 +1,142 @@
++#!/usr/bin/perl
++##!@WHICHPERL@
++
++my $pgm = $0; # name of program
++$pgm =~ s#.*/##; # remove part up to last slash
++my $seed = 1; # random number seed
++my $line_size = 50; # size of lines to print
++my $off = 1; # first position of sequence to print
++my $len = -1; # maximum length of sequence to print
++my $rest = ""; # file to receive remainder of seqs
++
++$usage = < [-seed ] [-rest ]
++ [-off ] [-len ]
++
++ name of FASTA sequence file
++ number of sequences to output
++ [-seed ] random number seed; default: $seed
++ [-rest ] name of file to receive the FASTA
++ sequences not being output; default: none
++ [-off ] print starting at position in each
++ sequence; default: $off
++ [-len ] print up to characters for each
++ sequence; default: print entire sequence
++
++ Output a random subsample of size of the sequences in
++ a FASTA sequence file. The seed of the random generator can be
++ changed using -seed, otherwise the same subset of sequences will
++ always be output. If requested, the remaining sequences will
++ be output to a file named , which is useful for
++ cross-validation.
++
++ You can also choose to only output portions of each sequence
++ using the -off and -len switches.
++
++ Writes to standard output.
++USAGE
++
++if ($#ARGV+1 < 2) { # wrong number of arguments
++ die $usage;
++}
++
++# get input arguments
++my $fasta = shift; # name of fasta file
++my $n = shift; # size of subsample
++while ($#ARGV >= 0) {
++ $_ = shift;
++ if ($_ eq "-seed") { # random seed
++ $seed = shift;
++ } elsif ($_ eq "-rest") { # rest file name
++ $rest = shift;
++ } elsif ($_ eq "-off") { # offset
++ $off = shift;
++ } elsif ($_ eq "-len") { # maximum length
++ $len = shift;
++ } elsif ($_ eq "-rest") { # file for remainder
++ $rest = shift;
++ } else {
++ die $usage;
++ }
++}
++
++# read in FASTA file and make index
++open(FASTA, "<$fasta") || die "Couldn't open file `$fasta'.\n";
++my $byte = 0;
++my %index; # ID-to-start index
++my $id; # sequence ID
++my @rest; # dummy
++my @id_list; # list of all IDs
++while () {
++ if (/^>/) {
++ ($id, @rest) = split;
++ $index{$id} = $byte; # start of sequence record
++ push @id_list, $id;
++ }
++ $byte += length;
++} # read FASTA file
++
++# check that there are enough IDs
++my $nseqs = @id_list;
++die ("Not enough sequences ($nseqs); $n requested.\n") if ($nseqs < $n);
++
++# shuffle the list of IDs
++srand($seed);
++shuffle(\@id_list);
++#print join " ", @id_list, "\n";
++
++# output the requested number of FASTA sequences to STDOUT
++foreach $id (@id_list[0..$n-1]) {
++ print_fasta_seq_portion(*FASTA, *STDOUT, $id, $off, $len, \%index);
++} # id
++
++# output the remainder of the sequences if requested
++# to the "rest" file
++if ($rest) {
++ open(REST, ">$rest") || die("Can't open file `$rest'.\n");
++ foreach $id (@id_list[$n..$nseqs-1]) {
++ print_fasta_seq_portion(*FASTA, *REST, $id, $off, $len, \%index);
++ }
++}
++
++################################################################################
++# print (a portion of) a FASTA sequence
++# Assumes FASTA file is open and the index contains
++# the file byte offset for a given ID.
++sub print_fasta_seq_portion {
++ my ($fasta, $output, $id, $off, $len, $index) = @_;
++
++ my $addr = $index{$id}; # address of sequence
++ die "Can't find target $id.\n" if ($addr eq undef);
++ seek($fasta, $addr, 0); # move to start of target
++ $_ = <$fasta>;
++ print $output $_; # print ID for this sequence
++ my $seq = "";
++ # read in sequence lines for this sequence
++ while (<$fasta>) { # read sequence lines
++ if (/^>/) {last} # start of next sequence
++ chop;
++ $seq .= $_;
++ }
++ # print sequence in lines of length $line_size
++ # get portion of sequence to print if -off and/or -len given
++ if ($off != 1 || $len != -1) {
++ if ($len == -1) {
++ $seq = substr($seq, $off-1);
++ } else {
++ $seq = substr($seq, $off-1, $len);
++ }
++ }
++ for ($i=0; $i $@
++ama-qvalues: ama-qvalues.txt Makefile
++ $(SED) $(SEDSPEC) $< > $@
+ cat_max: cat_max.txt Makefile
+ $(SED) $(SEDSPEC) $< > $@
+ chen2meme: chen2meme.pl Makefile
+@@ -134,6 +140,8 @@
+ $(SED) $(SEDSPEC) $< > $@
+ fasta-shuffle-letters: fasta-shuffle-letters.txt Makefile
+ $(SED) $(SEDSPEC) $< > $@
++fasta-subsample: fasta-subsample.txt Makefile
++ $(SED) $(SEDSPEC) $< > $@
+ fasta-unique-names: fasta-unique-names.txt Makefile
+ $(SED) $(SEDSPEC) $< > $@
+ get_db_csv: get_db_csv.txt Makefile
+
+Index: doc/release-notes.html
+===================================================================
+--- doc/release-notes.html (revision 4519)
++++ doc/release-notes.html (working copy)
+@@ -28,6 +28,29 @@
+
MEME Suite System Release Notes
+
+
++ MEME version NEXT
++
++
++
++ fasta-subsample --
++ New script for extracting a random sampling of the sequences
++ in a FASTA file. This is especially useful for ChIP-seq
++ peak datasets to be input to MEME. Using this script, a
++ FASTA file containing a subset of the ChIP-seq peak sequences
++ (or any other FASTA file) can be created. The total
++ number of sequences should be less than 1000 (peferably less
++ than 500), and the total sequence length should be less
++ than a few hundred thousand. MEME typically takes about 20 minutes
++ per motif with files of 100,000 characters (DNA, both strands, ZOOPS model),
++ and scales quadratically in the total sequence length (so a file of
++ 200,000 characters will take four times as long.)
++ This new script can also output the remaining sequences (in a sepqrate
++ file) for use in cross-validation.
++
+@@ -113,7 +114,8 @@
+ for human viewing. The text format is available for backwards compatibility
+ though due to design decisions made to optimise the xml for html generation
+ the output for separate scoring mode is not identical and some options were
+- removed.
++ removed. The text format will be unsupported in future releases and so we
++ recommend you migrate any programs reading mast output to the xml format.
+
+-Convert a mast xml file into a mast text file.
++Provides backwards compatibility by converting a mast xml file into a mast text file.
++Warning: Mast text format will not be supported in the next release.
+
+
Input:
+
<mast xml file> - An xml file created by the mast program.
+Index: src/mast2txt.c
+===================================================================
+--- src/mast2txt.c (revision 4529)
++++ src/mast2txt.c (working copy)
+@@ -15,7 +15,7 @@
+ #include "utils.h"
+
+ /*debugging macros {{{*/
+-VERBOSE_T verbosity = HIGH_VERBOSE;
++VERBOSE_T verbosity = QUIET_VERBOSE;
+ BOOLEAN_T status = TRUE;
+ time_t status_last = 0; //last time a status message was output
+ time_t status_delay = 5; //minimum time between status messages
+@@ -2234,7 +2234,7 @@
+
+
+ int main(int argc, char **argv) {
+-
++ int result;
+ //Using SAX scan through the xml document
+ //load the model parameters,
+ //load the alphabet
+@@ -2244,11 +2244,12 @@
+ //keep a ordered tree of scores which haven't been inserted yet and write out the data to file
+ //and keep a pointer to it,
+ if (argc == 3) {
+- parse_xml_file(argv[1], argv[2]);
++ result = parse_xml_file(argv[1], argv[2]);
+ } else {
+ fprintf(stdout, "mast2txt \n");
++ result = 1;
+ }
+
+- return 0;
++ return result;
+ }
+ /*}}}*/
+Index: src/mast.c
+===================================================================
+--- src/mast.c (revision 4529)
++++ src/mast.c (working copy)
+@@ -98,6 +98,8 @@
+ static const char *XML_FILENAME = "mast.xml";
+ static const char *HTML_STYLESHEET = "mast-to-html.xsl";
+ static const char *HTML_FILENAME = "mast.html";
++static const char *TXT_FILENAME = "mast.txt";
++static const char *MAST2TXT_FILENAME = "mast2txt";
+
+ /* MAST DTD */
+ /*{{{*/
+@@ -1692,6 +1694,7 @@
+ BOOLEAN lump = FALSE; /* combine spacings into one p-value */
+ BOOLEAN status = TRUE; /* show progress */
+ BOOLEAN html = TRUE; /* generate html output */
++ BOOLEAN mast2txt = TRUE; /* run mast2txt on the xml output */
+ STYPE stype = Combine; /* handling of DNA strands */
+ BOOLEAN translate_dna = FALSE; /* don't translate DNA sequences */
+ BOOLEAN best_motifs = FALSE; /* only print best motif in diagrams */
+@@ -1803,6 +1806,7 @@
+ DATA_OPTN(1, minseqs, , \tlower bound on number of sequences in db,
+ min_seqs = atoi(_OPTION_));
+ FLAG_OPTN(1, nostatus, \tdo not print progress report, status = FALSE);
++ FLAG_OPTN(1, notext, \tdo not generate text output, mast2txt = FALSE);
+ FLAG_OPTN(1, nohtml, \tdo not generate html output, html = FALSE);
+ // DEBUG AND EXPERIMENTAL OPTIONS
+ FLAG_OPTN(EXP, shuffle, \tshuffle columns of motifs, shuffle = TRUE);
+@@ -2004,6 +2008,27 @@
+ // finish xml output
+ if (mast_out != stdout) fclose(mast_out);
+
++ // finish status report
++ if (status) fprintf(stderr, "\n");
++
++ //cleanup
++ for (i = 0; i < arraylst_size(sequences); ++i) {
++ SSEQ_T *sseq = (SSEQ_T*)arraylst_get(i, sequences);
++ sseq_destroy(sseq, nmotifs);
++ }
++ arraylst_destroy(sequences);
++ for (i = 0; i < arraylst_size(databases); ++i) {
++ DATABASE_T *db = (DATABASE_T*)arraylst_get(i, databases);
++ myfree(db->source);
++ myfree(db->name);
++ myfree(db->link);
++ if (db->save) fclose(db->save);
++ if (db->file != stdin) fclose(db->file);
++ myfree(db);
++ }
++ arraylst_destroy(databases);
++
++ //output alternate formats
+ if (xml_path && html) {
+ char *stylesheet_path, *html_path;
+ stylesheet_path = make_path_to_file(ETC_DIR, HTML_STYLESHEET);
+@@ -2022,28 +2047,30 @@
+ myfree(stylesheet_path);
+ myfree(html_path);
+ }
++ if (xml_path && mast2txt) {
++ char *mast2txt_path, *txt_path;
++ mast2txt_path = make_path_to_file(BIN_DIR, MAST2TXT_FILENAME);
++ txt_path = make_path_to_file(out_dir, TXT_FILENAME);
++ if (file_exists(mast2txt_path)) {
++ char *cmd;
++ int len;
++ len = strlen(mast2txt_path) + strlen(xml_path) + strlen(txt_path) + 9;
++ cmd = mm_malloc(sizeof(char) * len);
++ snprintf(cmd, len, "\"%s\" \"%s\" \"%s\"", mast2txt_path, xml_path, txt_path);
++ if (system(cmd)) {
++ fprintf(stderr, "Warning: program mast2txt failed to run.\n");
++ }
++ myfree(cmd);
++ } else {
++ if (verbosity >= NORMAL_VERBOSE)
++ fprintf(stderr, "Warning: could not find the program \"%s\" required for transformation of xml to txt. Have you installed %s correctly?\n",
++ mast2txt_path, program_name);
++ }
++ myfree(mast2txt_path);
++ myfree(txt_path);
++ }
+
+- // finish status report
+- if (status) fprintf(stderr, "\n");
+-
+- //cleanup
+- for (i = 0; i < arraylst_size(sequences); ++i) {
+- SSEQ_T *sseq = (SSEQ_T*)arraylst_get(i, sequences);
+- sseq_destroy(sseq, nmotifs);
+- }
+- arraylst_destroy(sequences);
+- for (i = 0; i < arraylst_size(databases); ++i) {
+- DATABASE_T *db = (DATABASE_T*)arraylst_get(i, databases);
+- myfree(db->source);
+- myfree(db->name);
+- myfree(db->link);
+- if (db->save) fclose(db->save);
+- if (db->file != stdin) fclose(db->file);
+- myfree(db);
+- }
+- arraylst_destroy(databases);
+ myfree(xml_path);
+-
+ return 0;
+ } /* main */
+
+Index: etc/mast.sh.in
+===================================================================
+--- etc/mast.sh.in (revision 4529)
++++ etc/mast.sh.in (working copy)
+@@ -86,6 +86,7 @@
+ echo "
+
+Index: website/cgi-bin/meme_request.pl
+===================================================================
+--- website/cgi-bin/meme_request.pl (revision 4579)
++++ website/cgi-bin/meme_request.pl (working copy)
+@@ -258,8 +258,8 @@
+ # write the motifs to a temporary file that will be deleted when perl exits
+ my ($fh, $tmpname);
+ ($fh, $tmpname) = tempfile(UNLINK => 1);
+- $fh->print($motifs);
+- $fh->close();
++ print($fh $motifs);
++ close($fh);
+
+ #print "Content-type: text/plain", "\n\n";
+ #print "cat $tmpname", "\n";
diff --git a/tools/meme-suite/sources/meme_4.4.0.patch_4 b/tools/meme-suite/sources/meme_4.4.0.patch_4
new file mode 100644
index 0000000000000000000000000000000000000000..a782c66b2dc67828d86a3c95ce8c9e845467df0c
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.4.0.patch_4
@@ -0,0 +1,153 @@
+Index: src/cisml.c
+===================================================================
+--- src/cisml.c (revision 4587)
++++ src/cisml.c (working copy)
+@@ -7,6 +7,7 @@
+ ********************************************************************/
+
+ #include
++#include
+ #include
+ #include
+ #include
+@@ -1508,27 +1509,62 @@
+ pattern->name
+ );
+ }
+- // Delete least significant items.
+- double max_sig_pvalue = 1.0;
++ // Delete least significant matched elements.
++ double min_pvalue_discarded = 1.0;
+ MATCHED_ELEMENT_T *victim = NULL;
+ int deletion_count = 0;
+ for (deletion_count = 0; deletion_count < num_elements_to_delete; ++deletion_count) {
+ victim = (MATCHED_ELEMENT_T *) pop_heap_root(heap);
+- max_sig_pvalue = *(victim->pvalue);
++ min_pvalue_discarded = *(victim->pvalue);
+ --pattern->num_stored_matches;
+ free_matched_element(victim);
+ }
+
+- // Delete further elements with pvalue equal the to the
+- // minimum pvalue of the removed elements.
+- while (*(((MATCHED_ELEMENT_T *) get_node(heap, 1))->pvalue) >= max_sig_pvalue) {
++ // Keep deleting matched elements until we find an element more
++ // significant then the elements we've already deleted.
++ while (*(((MATCHED_ELEMENT_T *) get_node(heap, 1))->pvalue)
++ >= min_pvalue_discarded) {
+ victim = (MATCHED_ELEMENT_T *) pop_heap_root(heap);
++ assert(victim != NULL);
+ --pattern->num_stored_matches;
+ free_matched_element(victim);
++ if (get_num_nodes(heap) == 0) {
++ // All the matched elements have been deleted!
++ break;
++ }
+ }
+
++ if (verbosity >= NORMAL_VERBOSE) {
++ fprintf(
++ stderr,
++ "Warning: Reached max stored scores (%d).\n"
++ "Motif matches with p-value >= %3.2g have been "
++ "deleted to reclaim memory.\n",
++ pattern->max_stored_matches,
++ min_pvalue_discarded
++ );
++ }
++
++ if (get_num_nodes(heap) > 0) {
++ // Get the largest p-value retained from the top element of the heap.
++ pattern->max_pvalue_retained = *((MATCHED_ELEMENT_T *) get_node(heap, 1))->pvalue;
++ }
++ else {
++ // All items have been deleted!
++ fprintf(
++ stderr,
++ "Warning: there are no motif matches with p-value < %3.2g.\n"
++ "Use --max-stored-scores to allocate more space for "
++ "storing motif matches.\n",
++ min_pvalue_discarded
++ );
++ // Set the largest p-value retained to something
++ // slightly less the smallest p-value discarded.
++ pattern->max_pvalue_retained
++ = get_next_smaller_double(min_pvalue_discarded);
++ }
++
+ set_pattern_has_all_pvalues(pattern, FALSE);
+- pattern->max_pvalue_retained = *((MATCHED_ELEMENT_T *) get_node(heap, 1))->pvalue;
+ }
+
+ /**********************************************************************
+Index: src/utils.c
+===================================================================
+--- src/utils.c (revision 4597)
++++ src/utils.c (working copy)
+@@ -532,8 +532,32 @@
+ return(lower_value + interpolation);
+ }
+
++/**************************************************************************
++ * Return the nearest double smaller then the given double
++ **************************************************************************/
++double get_next_smaller_double(double x) {
++ // IEEE doubles run in lexigraphical order
++ // so if we want the next smaller double
++ // we just need to cast to integer type and
++ // decrement.
++ *(long long *) &x = *(long long *) &x - 1;
++ return x;
++}
+
+ /**************************************************************************
++ * Return the nearest double larger then the given double
++ **************************************************************************/
++double get_next_larger_double(double x) {
++ // IEEE doubles run in lexigraphical order
++ // so if we want the next larger double
++ // we just need to cast to integer type and
++ // increment.
++ *(long long *) &x = *(long long *) &x + 1;
++ return x;
++}
++
++
++/**************************************************************************
+ * See .h file for description.
+ **************************************************************************/
+ BOOLEAN_T is_zero
+Index: src/utils.h
+===================================================================
+--- src/utils.h (revision 4597)
++++ src/utils.h (working copy)
+@@ -267,6 +267,16 @@
+ )
+
+ /**************************************************************************
++ * Return the nearest double smaller then the given double
++ **************************************************************************/
++double get_next_smaller_double(double x);
++
++/**************************************************************************
++ * Return the nearest double larger then the given double
++ **************************************************************************/
++double get_next_larger_double(double x);
++
++/**************************************************************************
+ * Test for zero on a value that may be either a log or a raw float.
+ **************************************************************************/
+ BOOLEAN_T is_zero
+Index: website/html/meme-suite-menu.in
+===================================================================
+--- website/html/meme-suite-menu.in (revision 4587)
++++ website/html/meme-suite-menu.in (working copy)
+@@ -33,7 +33,7 @@
+ ['Downloads', html_path+'downloads.html',
+ ['Download MEME Suite Software', html_path+'meme-download.html'],
+ ['Copyright', html_path+'COPYRIGHT.html'],
+- ['Commercial Licenses', 'http://invent.ucsd.edu/technology/cases/2002/SD2002-802.htm'],
++ ['Commercial Licenses', 'http://invent.ucsd.edu/technology/cases/2010/SD2010-808.shtml'],
+ //['Download GLAM2/GLAM2SCAN software separately', glam2_web.concat('/archive')]
+ ],
+ ['User Support', html_path+'resources.html',
diff --git a/tools/meme-suite/sources/meme_4.4.0.patch_5 b/tools/meme-suite/sources/meme_4.4.0.patch_5
new file mode 100644
index 0000000000000000000000000000000000000000..3ccdb94b7bc3875e6ea7b93e1ee77c49aedb8922
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.4.0.patch_5
@@ -0,0 +1,113 @@
+Index: website/html/search.in
+===================================================================
+--- website/html/search.in (revision 4698)
++++ website/html/search.in (working copy)
+@@ -9,7 +9,7 @@
+
+
+
+-
++
+
+
+
+Index: website/cgi-bin/Utils.pm.in
+===================================================================
+--- website/cgi-bin/Utils.pm.in (revision 4698)
++++ website/cgi-bin/Utils.pm.in (working copy)
+@@ -994,13 +994,15 @@
+
+ # get list of databases as option fields from dbnames_url
+ my $ua = LWP::UserAgent->new();
+- my $req = HTTP::Request->new(GET => $db_cat_url);
++ #need full url for this request
++ my $req = HTTP::Request->new(GET => "@SITE_URL@/cgi-bin/$db_cat_url");
+ my $response = $ua->request($req);
+ my @db_categories = split("\n", $response->content());
+ my $categories = "";
+ my $databases = "";
+ if (@db_categories == 1) {
+- $req = HTTP::Request->new(GET => $dbnames_url);
++ #need full url for this request
++ $req = HTTP::Request->new(GET => "@SITE_URL@/cgi-bin/$dbnames_url");
+ $response = $ua->request($req);
+ my @db_names = split("\n", $response->content());
+ foreach (@db_names) {
+Index: website/cgi-bin/mcast.pl
+===================================================================
+--- website/cgi-bin/mcast.pl (revision 4698)
++++ website/cgi-bin/mcast.pl (working copy)
+@@ -24,7 +24,7 @@
+ $email_contact = '@contact@';
+ $names_file = "fasta_db.csv";
+ $short_dna_only = 0; # MCAST can scan long DNA sequences
+-$dbnames_url = "@SITE_URL@/cgi-bin/get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
++$dbnames_url = "get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
+ $db_doc_url = $dbnames_url . "&doc=1";
+
+ # get the parameters for the query
+Index: website/cgi-bin/glam2scan.pl
+===================================================================
+--- website/cgi-bin/glam2scan.pl (revision 4698)
++++ website/cgi-bin/glam2scan.pl (working copy)
+@@ -25,7 +25,7 @@
+ $email_contact = '@contact@';
+ $names_file = "fasta_db.csv";
+ $short_dna_only = 0; # GLAM2SCAN can scan long DNA sequences
+-$dbnames_url = "@SITE_URL@/cgi-bin/get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
++$dbnames_url = "get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
+ $db_doc_url = $dbnames_url . "&doc=1";
+
+ # defaults
+Index: website/cgi-bin/tomtom.pl
+===================================================================
+--- website/cgi-bin/tomtom.pl (revision 4698)
++++ website/cgi-bin/tomtom.pl (working copy)
+@@ -21,7 +21,7 @@
+ $bin_dir = "$dir/bin"; # directory for executables
+ $out_dir = "../output"; # directory for results
+ $names_file = "motif_db.csv";
+-$dbnames_url = "@SITE_URL@/cgi-bin/get_db_list.cgi?db_names=$names_file";
++$dbnames_url = "get_db_list.cgi?db_names=$names_file";
+ $db_doc_url = $dbnames_url . "&doc=1";
+ $REFRESH = 20;
+ $email_contact = '@contact@';
+Index: website/cgi-bin/fimo.pl
+===================================================================
+--- website/cgi-bin/fimo.pl (revision 4698)
++++ website/cgi-bin/fimo.pl (working copy)
+@@ -24,7 +24,7 @@
+ $email_contact = '@contact@';
+ $names_file = "fasta_db.csv";
+ $short_dna_only = 0; # FIMO can scan long DNA sequences
+-$dbnames_url = "@SITE_URL@/cgi-bin/get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
++$dbnames_url = "get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
+ $db_doc_url = $dbnames_url . "&doc=1";
+
+ # get the parameters for the query
+Index: website/cgi-bin/gomo.pl
+===================================================================
+--- website/cgi-bin/gomo.pl (revision 4698)
++++ website/cgi-bin/gomo.pl (working copy)
+@@ -19,7 +19,7 @@
+ $service_url = "@OPAL@/GOMO_@S_VERSION@";
+ $email_contact = '@contact@';
+ $names_file = "gomo_db.csv";
+-$dbnames_url = "@SITE_URL@/cgi-bin/get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
++$dbnames_url = "get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
+ $db_doc_url = $dbnames_url . "&doc=1";
+
+ # defaults
+Index: website/cgi-bin/mast.pl
+===================================================================
+--- website/cgi-bin/mast.pl (revision 4698)
++++ website/cgi-bin/mast.pl (working copy)
+@@ -25,7 +25,7 @@
+ $email_contact = '@contact@';
+ $short_dna_only = 1; # MAST cannot scan long DNA sequences
+ $names_file = 'fasta_db.csv';
+-$dbnames_url = "@SITE_URL@/cgi-bin/get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
++$dbnames_url = "get_db_list.cgi?db_names=$names_file&short_only=$short_dna_only";
+ $db_doc_url = $dbnames_url . "&doc=1";
+
+ # defaults
diff --git a/tools/meme-suite/sources/meme_4.4.0.patch_6 b/tools/meme-suite/sources/meme_4.4.0.patch_6
new file mode 100644
index 0000000000000000000000000000000000000000..e1534d5dcdd595c009b9b00027e32af705363813
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.4.0.patch_6
@@ -0,0 +1,89 @@
+Index: website/html/selectdb.js
+===================================================================
+--- website/html/selectdb.js (revision 4699)
++++ website/html/selectdb.js (working copy)
+@@ -31,10 +31,7 @@
+ }
+ }
+ //add an status line
+- var emptyOpt = document.createElement("option");
+- emptyOpt.value = "";
+- emptyOpt.text = "loading";
+- list.appendChild(emptyOpt);
++ list.options[list.options.length] = new Option("loading", "");
+ //now send the request
+ url += "&mode=categories_xml";
+ var req = get_request_obj();
+@@ -68,18 +65,12 @@
+ }
+ }
+ //add an empty line
+- var emptyOpt = document.createElement("option");
+- emptyOpt.value = "";
+- emptyOpt.text = "";
+- list.appendChild(emptyOpt);
++ list.options[list.options.length] = new Option("", "");
+ //fill with loaded data
+ var cats = xmlDoc.getElementsByTagName("category");
+ for (var i = 0; i < cats.length; i++) {
+ var cat = cats[i];
+- var opt = document.createElement("option");
+- opt.value = "" + (i+1);
+- opt.text = cat.getAttribute("name");
+- list.appendChild(opt);
++ list.options[list.options.length] = new Option(cat.getAttribute("name"), "" + (i+1));
+ }
+ list.disabled = false;
+ }
+@@ -100,17 +91,11 @@
+ //exit if no category to query
+ if (catid == "") {
+ //add an empty line
+- var emptyOpt = document.createElement("option");
+- emptyOpt.value = "";
+- emptyOpt.text = "";
+- list.appendChild(emptyOpt);
++ list.options[list.options.length] = new Option("", "");
+ return;
+ }
+ //add an status line
+- var emptyOpt = document.createElement("option");
+- emptyOpt.value = "";
+- emptyOpt.text = "loading";
+- list.appendChild(emptyOpt);
++ list.options[list.options.length] = new Option("loading", "");
+ //now send the request
+ url += "&mode=xml&catid=" + catid;
+ var req = get_request_obj();
+@@ -145,9 +130,7 @@
+ }
+ //add an empty line
+ var emptyOpt = document.createElement("option");
+- emptyOpt.value = "";
+- emptyOpt.text = "";
+- list.appendChild(emptyOpt);
++ list.options[list.options.length] = new Option("", "");
+ //fill with loaded data
+ var dbs = xmlDoc.getElementsByTagName("db");
+ for (var i = 0; i < dbs.length; i++) {
+@@ -171,17 +154,14 @@
+ (is_short ? "yes" : "no") + "," +
+ db.getAttribute("menu") + "," +
+ db.getAttribute("desc") + "," +
+- (db.hasAttribute("start") ? db.getAttribute("start") : "") + "," +
+- (db.hasAttribute("end") ? db.getAttribute("end") : "");
++ (db.getAttribute("start") ? db.getAttribute("start") : "") + "," +
++ (db.getAttribute("end") ? db.getAttribute("end") : "");
+ var cmpdbs = db.getElementsByTagName("cmp_db");
+ for (var j = 0; j < cmpdbs.length; j++) {
+ var cmpdb = cmpdbs[j];
+ optvalue += "," + cmpdb.getAttribute("base");
+ }
+- var opt = document.createElement("option");
+- opt.value = optvalue;
+- opt.text = opttext;
+- list.appendChild(opt);
++ list.options[list.options.length] = new Option(opttext, optvalue);
+ }
+ list.disabled = false;
+ }
diff --git a/tools/meme-suite/sources/meme_4.4.0.patch_7 b/tools/meme-suite/sources/meme_4.4.0.patch_7
new file mode 100644
index 0000000000000000000000000000000000000000..e27c59ed277f5b37a951b0d38aacc73dc34ed9ef
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.4.0.patch_7
@@ -0,0 +1,13 @@
+Index: website/html/search.in
+===================================================================
+--- website/html/search.in (revision 4698)
++++ website/html/search.in (revision 4794)
+@@ -9,7 +9,7 @@
+
+
+
+-
++
+
+
+
diff --git a/tools/meme-suite/sources/meme_4.4.0.tar.gz b/tools/meme-suite/sources/meme_4.4.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..11772eccbc002c848bd7f915b2414edf142d3dae
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.4.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3b61e1f4513da4ff60fd0c516d4edcefeb9c9e07a3ab7fa42c059576d6a0f992
+size 4673815
diff --git a/tools/meme-suite/sources/meme_4.5.0.patch_1 b/tools/meme-suite/sources/meme_4.5.0.patch_1
new file mode 100644
index 0000000000000000000000000000000000000000..df45616decbeef0882b4035367f6e1a145f5bb2f
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.5.0.patch_1
@@ -0,0 +1,587 @@
+diff -uNr meme_4.5.0/configure meme_4.5.0.patch_1/configure
+--- meme_4.5.0/configure 2010-10-14 08:47:03.000000000 +1000
++++ meme_4.5.0.patch_1/configure 2010-12-03 11:08:37.000000000 +1000
+@@ -12157,16 +12157,17 @@
+
+
+ # Check for compiler-specific settings
++LARGE_FILE_SUPPORT=`getconf LFS_CFLAGS`
+ if test "${CC}" = "gcc"; then
+ ac_cc_opt="-O3"
+ ac_cc_warn="-Wall -Wno-unused"
+ ac_cc_debug="-ggdb"
+- CFLAGS="$ac_cc_warn -DUNIX -D__USE_FIXED_PROTOTYPES__"
++ CFLAGS="$ac_cc_warn -DUNIX -D__USE_FIXED_PROTOTYPES__ $LARGE_FILE_SUPPORT"
+ else
+ ac_cc_opt="-O"
+ ac_cc_warn=""
+ ac_cc_debug="-g"
+- CFLAGS="$ac_cc_warn -DUNIX -D__USE_FIXED_PROTOTYPES__"
++ CFLAGS="$ac_cc_warn -DUNIX -D__USE_FIXED_PROTOTYPES__ $LARGE_FILE_SUPPORT"
+ fi
+
+ # Set up default libxml2 settings
+diff -uNr meme_4.5.0/configure.ac meme_4.5.0.patch_1/configure.ac
+--- meme_4.5.0/configure.ac 2010-10-07 10:01:46.000000000 +1000
++++ meme_4.5.0.patch_1/configure.ac 2010-12-03 09:54:53.000000000 +1000
+@@ -60,16 +60,17 @@
+ AM_CONDITIONAL(WANT_STRLCPY, test ["$have_strlcpy" = no])
+
+ # Check for compiler-specific settings
++LARGE_FILE_SUPPORT=`getconf LFS_CFLAGS`
+ if test "${CC}" = "gcc"; then
+ ac_cc_opt="-O3"
+ ac_cc_warn="-Wall -Wno-unused"
+ ac_cc_debug="-ggdb"
+- CFLAGS="$ac_cc_warn -DUNIX -D__USE_FIXED_PROTOTYPES__"
++ CFLAGS="$ac_cc_warn -DUNIX -D__USE_FIXED_PROTOTYPES__ $LARGE_FILE_SUPPORT"
+ else
+ ac_cc_opt="-O"
+ ac_cc_warn=""
+ ac_cc_debug="-g"
+- CFLAGS="$ac_cc_warn -DUNIX -D__USE_FIXED_PROTOTYPES__"
++ CFLAGS="$ac_cc_warn -DUNIX -D__USE_FIXED_PROTOTYPES__ $LARGE_FILE_SUPPORT"
+ fi
+
+ # Set up default libxml2 settings
+diff -uNr meme_4.5.0/etc/tomtom-to-html.xsl meme_4.5.0.patch_1/etc/tomtom-to-html.xsl
+--- meme_4.5.0/etc/tomtom-to-html.xsl 2010-09-06 11:18:05.000000000 +1000
++++ meme_4.5.0.patch_1/etc/tomtom-to-html.xsl 2010-12-03 09:54:53.000000000 +1000
+@@ -391,6 +391,9 @@
+
+
+
++
++ ()
++
+
+
+ ,
+@@ -571,7 +574,8 @@
+
+
+
+- logo__
++ align__
++ _
+ +
+ -
+ .png
+diff -uNr meme_4.5.0/scripts/meme2meme.pl meme_4.5.0.patch_1/scripts/meme2meme.pl
+--- meme_4.5.0/scripts/meme2meme.pl 2010-09-03 15:14:40.000000000 +1000
++++ meme_4.5.0.patch_1/scripts/meme2meme.pl 2010-12-03 10:01:12.000000000 +1000
+@@ -516,11 +516,14 @@
+ my @motif_list = ();
+ my $motif = {};
+ my $index = 0;
++ my $new_pssm_ref;
++ my $new_pspm_ref;
+ while ($line) {
+
+ #look for the start of a motif
+ if ($line =~ m/^MOTIF\s+(.*)$/) {
+ my @words = split(/\s+/, $1);
++ die("Motif $index in $file missing motif name.\n") unless scalar(@words) > 0 && $words[0] ne "";
+ # if there was a previous motif then add it to the list
+ push(@motif_list, $motif) if $motif->{id};
+
+@@ -530,22 +533,25 @@
+ $pssm{$letter} = [];
+ $pspm{$letter} = [];
+ }
++ $new_pssm_ref = \%pssm;
++ $new_pspm_ref = \%pspm;
+
+ my $id = $words[0];
+- my $alt = ($words[1] ne "width" ? $words[1] : "");
++ my $alt = (scalar(@words) > 1 && $words[1] ne "width" ? $words[1] : "");
+
+ my $url = $url_pattern;
+ $url =~ s/MOTIF_NAME/$id/g; #use the original id in the url
+
+ $motif = {id => $id, alt => $alt, bg => \%bg,
+- strands => $strands, url => $url, width => 0, sites => 0, pseudo => 0, evalue => 0,
+- pssm => \%pssm, pspm => \%pspm};
+-
++ strands => $strands, url => $url, width => 0, sites => 0, pseudo => 0, evalue => 0};
++
++ $index += 1;
+ }
+ #look for the start of a log odds matrix
+ elsif ($line =~ m/log-odds matrix:\s+(.*)$/) {
+ $line = $1;
+ $line =~ s/\s+$//; #trim right
++ $motif->{pssm} = $new_pssm_ref;
+ my %motif_params = split(/\s+/, $line);
+ #check that we have the parameters we require
+ die("Motif $index in $file is missing required parameter(s) in log-odds matrix.\n")
+@@ -569,6 +575,7 @@
+ elsif ($line =~ m/^letter-probability matrix:\s+(.*)$/) {
+ $line = $1;
+ $line =~ s/\s+$//; #trim right
++ $motif->{pspm} = $new_pspm_ref;
+ my %motif_params = split(/\s+/, $line);
+ #check that we have the parameters we require
+ die("Motif $index in $file is missing required parameter(s) in letter-probability matrix.\n")
+diff -uNr meme_4.5.0/scripts/runcheck_p.in meme_4.5.0.patch_1/scripts/runcheck_p.in
+--- meme_4.5.0/scripts/runcheck_p.in 2010-09-03 15:11:51.000000000 +1000
++++ meme_4.5.0.patch_1/scripts/runcheck_p.in 2010-12-03 10:04:14.000000000 +1000
+@@ -1,40 +1,8 @@
+ #!/bin/sh
+
+-# runcheck - for testing of meme and mast
++# runcheck_p - for testing of the parallel version of MEME.
+ #
+ # $Id: runcheck 1537 2007-01-12 21:48:56Z cegrant $
+-#
+-# $Log$
+-# Revision 1.7 2006/03/08 20:50:11 nadya
+-# merge chamges from v3_5_2 branch
+-#
+-# Revision 1.6.4.2 2006/01/24 02:24:29 nadya
+-# EXT is obsoleted by using printf()
+-#
+-# Revision 1.6.4.1 2006/01/24 02:04:55 nadya
+-# source meme_config to set needed environment
+-# make output table-like
+-#
+-# Revision 1.6 2005/10/07 02:54:28 nadya
+-# clean debugging output, fix typo
+-#
+-# Revision 1.5 2005/10/04 20:03:23 nadya
+-# changes to accommodate sh on solaris:
+-# substitute array with awk parsing and initialize err.
+-#
+-# Revision 1.4 2005/10/04 00:02:04 nadya
+-# change to "-f", the option "-e" does not run solaris
+-#
+-# Revision 1.3 2005/10/02 05:09:39 nadya
+-# add extension ".bin" to executables names for meme and mast
+-#
+-# Revision 1.2 2005/09/01 00:42:05 nadya
+-# call executables from $topdir befiore they are installed
+-# update sed regexpr
+-#
+-# Revision 1.1 2005/08/31 04:51:55 nadya
+-# create script and target for "make check"
+-#
+
+ # set meme environment
+ top=`pwd`/..
+@@ -44,7 +12,6 @@
+ testdir=$top/tests
+ fi
+ meme=$top/src/parallel/meme_p
+-mast=$top/src/mast
+
+ echo "****************************************"
+ echo "Now Running Test for Parallel Version..."
+@@ -57,35 +24,9 @@
+ exit 1
+ fi
+
+-if [ ! -x $mast ] ; then
+- echo "$mast does not exist or is not executable"
+- echo "Run 'make' before running 'make check'"
+- exit 1
+-fi
+-
+ ####################################################################
+-# define functions
++# define functions
+ ####################################################################
+-# run mast tests
+-func_run_mast () {
+- echo ""
+- echo " Mast test for "
+- echo " ---------------------------------"
+- echo " Dataset Model result "
+- echo " ---------------------------------"
+-
+- for mod in $models
+- do
+- memefile=meme/meme.$dset.$mod$suffix
+- mastfile=mast/mast.$dset.$mod$suffix
+- database="$dir/common/$dset.s"
+- params="$dir/$memefile $database -oc $dirout/mast -nohtml -nostatus"
+- $mast $params
+- mv $dirout/mast/mast.xml $dirout/$mastfile
+- func_diff $mastfile "mast"
+- done
+-}
+-
+ # run meme tests
+ func_run_meme () {
+ meme="@mpirun@ 2 $meme "
+@@ -117,22 +58,8 @@
+ e10="/Last updated/d"
+ e11="/MPI/d"
+ e12="/^$/d"
+- e13="/^mast /d"
+ sed -e "$e1" -e "$e2" -e "$e3" -e "$e4" -e "$e5" -e "$e6" -e "$e7" \
+- -e "$e8" -e "$e9" -e "$e10" -e "$e11" -e "$e12" -e "$e13" $1 > $1.sed
+-}
+-
+-func_xml_sed() {
+- e1='s///'
+- e2='s|[^<]*||'
+- e3='s|[^<]*||'
+- e4='s|[^<]*||'
+- e5='s|||'
+- e6='s/last_mod_date="[^"]*"/last_mod_date=""/'
+- e7='s/source="[^"]*"/source=""/'
+- e8='s/ $1.sed
++ -e "$e8" -e "$e9" -e "$e10" -e "$e11" -e "$e12" $1 > $1.sed
+ }
+
+ # checks two files for differences. Arguments - a filename
+@@ -154,13 +81,8 @@
+ echo "$str" "SKIPPED"
+ return
+ fi
+- if [ "$2" = "mast" ]; then
+- func_xml_sed $f1
+- func_xml_sed $f2
+- else
+- func_sed $f1
+- func_sed $f2
+- fi
++ func_sed $f1
++ func_sed $f2
+ num=`diff $f1.sed $f2.sed | wc -l`
+ status=$?
+ if [ $status -eq 0 -a $num -eq 0 ]; then
+@@ -179,13 +101,6 @@
+ params="-text -dna -revcomp -nostatus -nmotifs 2 -minw 8"
+ dir=$top/tests
+ dirout=$top/tests/results
+- if [ ! -d $dirout/mast ]; then
+- cmd=`mkdir -p $dirout/mast`
+- status=$?
+- if [ $status -eq 1 ] ; then
+- exit 1
+- fi
+- fi
+ if [ ! -d $dirout/meme ]; then
+ cmd=`mkdir -p $dirout/meme`
+ status=$?
+@@ -225,7 +140,6 @@
+ # run tests
+ func_set
+ func_run_meme
+-func_run_mast
+ func_clean
+
+ exit $err
+diff -uNr meme_4.5.0/src/background.c meme_4.5.0.patch_1/src/background.c
+--- meme_4.5.0/src/background.c 2010-09-03 15:14:05.000000000 +1000
++++ meme_4.5.0.patch_1/src/background.c 2010-12-03 09:34:19.000000000 +1000
+@@ -494,7 +494,7 @@
+ // get the total probability of this prefix summed over all suffixes
+ if (wa % index_alen == 0) {
+ int j;
+- for (j=0, total_w_prob=0; jmaxima;
+ int n_psites = model->nsites_dis;
+ fprintf(stdout,
+- "PREDICTED SITES AFTER EM FROM STARTING POINT WITH W = %i AND"
++ "\nPREDICTED SITES AFTER EM FROM STARTING POINT WITH W = %i AND"
+ " NSITES = %f:\n", s_point->w0, s_point->nsites0); //model->w, n_psites);
+ print_site_array(pred_sites, n_psites, stdout, model->w, dataset);
+ double sig = dataset->objfun==Pv ? model->logpv : model->logev;
+@@ -617,6 +617,7 @@
+
+ /* initialize the new motif */
+ strcpy(model->cons0, s_point->cons0);
++ if (VERBOSE) { fprintf(stderr, "\nStarting point: %s\n", model->cons0); }
+ w0 = model->w = model->pw = s_point->w0;
+ init_theta(model->theta, s_point->e_cons0, w0, dataset->map,dataset->alength);
+
+diff -uNr meme_4.5.0/src/pmp_bf.c meme_4.5.0.patch_1/src/pmp_bf.c
+--- meme_4.5.0/src/pmp_bf.c 2010-09-03 15:11:50.000000000 +1000
++++ meme_4.5.0.patch_1/src/pmp_bf.c 2010-12-03 09:54:08.000000000 +1000
+@@ -100,7 +100,8 @@
+ strcat(usage, " --pseudocount (default=0.1)\n");
+ strcat(usage, " --ustar
";
+- if ($outputdir) {
+- $outputdir = $outputdir."/"; # add path separator
+- } else { # make sure it's empty string, not undefined
+- $outputdir = "";
++ ($lowercase?$command:uc($command))." output"):"").":";
++ if (-s $errorfile) {
++ $outputstring .= " ".$indent."(";
++ if ($status) {
++ $outputstring .= "Errors Occurred";
++ } else {
++ $outputstring .= "Warnings";
++ }
++ $outputstring .= ")";
+ }
+- my $emptyseen = 0;
++
++ $outputstring .= "";
+ foreach my $filespec (@$outputs) {
+- my $format = $filespec;
+- # only report nonempty outputs, but leave space for the empty ones
+- $outputstring .= "
" unless $emptyseen;
+- # if $filespec is empty or undefined don't add the path
+- if ($filespec) {
+- $filespec = $outputdir."$filespec" ; # add the path if any
+- if (-s $filespec) {
+- my $totalwidth = &fixwidth($emptyseen, $filewidth);
+- if ($emptyseen) { # finish off the empty cells, start full one
+- $outputstring .= "
";
+- $emptyseen = 0;
+- } else { # although specified output doesn't exist: empty cell
+- $emptyseen++;
+- }
+- } else { # no output specified: empty cell
+- $emptyseen++;
+- }
+- }
+-
+- if ($emptyseen) {
+- # patch this in here because an empty string at the end of outputs can
+- # be missed by the foreach loop
+- $outputstring .= "
" unless $outputstring =~ /FIXWIDTH/;
+- my $totalwidth = &fixwidth($emptyseen, $filewidth);
+- $outputstring =~ s/FIXWIDTH/$totalwidth/;
++ my $format = $filespec;
++ # only report nonempty outputs, but leave space for the empty ones
++ $outputstring .= "
";
++ # if $filespec is empty or undefined don't add the path
++ if ($filespec) {
++ $filespec = $outputdir."$filespec" ; # add the path if any
++ if (-s $filespec) {
++ if ($format =~ /^([\w-.]+)\.([\w-]+)$/) {
++ $format = uc $2;
++ $format = "plain text" if $format eq "TXT";
++ }
++ $outputstring .= "$format";
++ }
++ }
+ $outputstring .= "
";
+ }
+ $outputstring .= "
$comment
" if ($comment);
+@@ -734,14 +759,6 @@
+ return $outputstring;
+ }
+
+-sub fixwidth {
+- my ($emptyseen, $width) = @_;
+- return $width if $emptyseen < 1;
+- # for each veritical line we lose, we lose its width + 1 px padding either side
+- return $width * $emptyseen + ($emptyseen - 1)*3;
+-}
+-
+-
+ ################################################################################
+ #
+ # create_HTML_header
+@@ -759,25 +776,25 @@
+ MEME ChIP Output
+
+
+@@ -852,7 +869,7 @@
+ $htmlstartlist ."\n
\n". $htmlreportinputs . "
\n" . $htmlendlist;
+
+ print $htmlfile "
Commands
\n".
+- $htmlstartlist."\n".
++ $htmlstartlist."\n".
+ $htmlreportcommands.$endcommandlist."\n".$htmlendlist;
+
+ &finish_html (\*HTMLFILE);
+@@ -864,7 +881,7 @@
+ # command_list
+ #
+ # put a command line into a HTML code format, with
+-# any redirects sanitised
++# any redirects sanitised
+ # arguments:
+ # $command: string to turn into HTML
+ # returns:
diff --git a/tools/meme-suite/sources/meme_4.6.0.tar.gz b/tools/meme-suite/sources/meme_4.6.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..8ca7a47357589d92c78afcc00c2448f4b7024d9c
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.6.0.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e25fee23edc74188723d331b71ce0f73fd3fc18ba0a7538236752ab93b5edd36
+size 10651898
diff --git a/tools/meme-suite/sources/meme_4.6.1.patch_1 b/tools/meme-suite/sources/meme_4.6.1.patch_1
new file mode 100644
index 0000000000000000000000000000000000000000..ac97cfcf217bf23e3df9df7dd67652c4ed15cd33
--- /dev/null
+++ b/tools/meme-suite/sources/meme_4.6.1.patch_1
@@ -0,0 +1,3102 @@
+diff -uNr meme_4.6.1/etc/fimo-to-wiggle.xsl meme_4.6.1_patch_1/etc/fimo-to-wiggle.xsl
+--- meme_4.6.1/etc/fimo-to-wiggle.xsl 2011-02-04 05:23:17.000000000 +1000
++++ meme_4.6.1_patch_1/etc/fimo-to-wiggle.xsl 2011-05-23 16:02:16.304185313 +1000
+@@ -35,7 +35,7 @@
+ and the width of the item. The second line contain
+ the starting position and the score.
+ -->
+- variablestep
++ variableStep
+ chrom=
+
+ span=
+diff -uNr meme_4.6.1/etc/motif_logo.js meme_4.6.1_patch_1/etc/motif_logo.js
+--- meme_4.6.1/etc/motif_logo.js 2011-02-04 05:23:17.000000000 +1000
++++ meme_4.6.1_patch_1/etc/motif_logo.js 2011-05-23 17:30:58.324182960 +1000
+@@ -41,6 +41,12 @@
+ this.freqs[pos] = (+freq);
+ }
+ }
++ } else {
++ //assume uniform background
++ var freq = 1.0 / this.letter_count;
++ for (var pos = 0; pos < this.letter_count; pos++) {
++ this.freqs[pos] = freq;
++ }
+ }
+ }
+
+@@ -210,16 +216,18 @@
+ //======================================================================
+ // start Pspm object
+ //======================================================================
+- function Pspm(pssm, name, ltrim, rtrim) {
++ function Pspm(pspm, name, ltrim, rtrim, nsites, evalue) {
+ if (ltrim === undefined) ltrim = 0;
+ if (rtrim === undefined) rtrim = 0;
++ if (nsites === undefined) nsites = 0;
++ if (evalue === undefined) evalue = 0;
+ //variable prototype
+ this.alph_length = 0;
+ this.motif_length = 0;
+- this.pspm = new Array();
++ this.pspm = null;
+ this.name = (typeof name == "string" ? name : "");
+- this.nsites = 0;
+- this.evalue = 0;
++ this.nsites = nsites;
++ this.evalue = evalue;
+ this.ltrim = ltrim;
+ this.rtrim = rtrim;
+ //function prototype
+@@ -231,62 +239,86 @@
+ this.get_alph_length = Pspm_get_alph_length;
+ this.get_left_trim = Pspm_get_left_trim;
+ this.get_right_trim = Pspm_get_right_trim;
++ this.as_pspm = Pspm_as_pspm;
++ this.as_pssm = Pspm_as_pssm;
+ this.toString = Pspm_to_string;
+ //construct
+- var pspm_header = /letter-probability matrix:\s+alength=\s+(\d+)\s+w=\s+(\d+)(\s+nsites=\s+(\S+))?(\s+E=\s+(\S+))?\s*/;
+- var is_empty = /^\s*$/;
+- var lines = pssm.split(/\s*\n\s*/);
+- var read_pssm = false;
+- var line_num = 0;
+- var col_num = 0;
+- for (line_index in lines) {
+- //exclude inherited properties and undefined properties
+- if (!lines.hasOwnProperty(line_index) || lines[line_index] === undefined) continue;
++ if (typeof pspm == "string") {
++ var pspm_header = /letter-probability matrix:\s+alength=\s+(\d+)\s+w=\s+(\d+)(\s+nsites=\s+(\S+))?(\s+E=\s+(\S+))?\s*/;
++ var lines = pspm.split(/\n/);
++ var read_pspm = false;
++ var line_num = 0;
++ var col_num = 0;
++ this.pspm = new Array();
++ for (line_index in lines) {
++ //exclude inherited properties and undefined properties
++ if (!lines.hasOwnProperty(line_index) || lines[line_index] === undefined) continue;
+
+- var line = lines[line_index];
+- if (is_empty.test(line)) {
+- continue;
+- }
+- if (!read_pssm) {
+- var header_match = pspm_header.exec(line);
+- if (header_match != null) {
+- read_pssm = true;
+- this.alph_length = (+header_match[1]);
+- this.motif_length = (+header_match[2]);
+- if (header_match[4]) this.nsites = parseFloat(header_match[4]);//not always an integer
+- if (header_match[6]) this.evalue = parseFloat(header_match[6]);
+- this.pspm = new Array(this.motif_length);
++ var line = trim(lines[line_index]);
++ if (line == '') {
++ continue;
++ }
++ if (!read_pspm) {
++ var header_match = pspm_header.exec(line);
++ if (header_match != null) {
++ read_pspm = true;
++ this.alph_length = (+header_match[1]);
++ this.motif_length = (+header_match[2]);
++ if (header_match[4]) this.nsites = parseFloat(header_match[4]);//not always an integer
++ if (header_match[6]) this.evalue = parseFloat(header_match[6]);
++ this.pspm = new Array(this.motif_length);
++ }
++ continue;
+ }
+- continue;
++ if (line_num >= this.motif_length) {
++ throw "TOO_MANY_ROWS";
++ }
++ this.pspm[line_num] = new Array(this.alph_length);
++ col_num = 0;
++ var parts = line.split(/\s+/);
++ for (part_index in parts) {
++ //exclude inherited properties and undefined properties
++ if (!parts.hasOwnProperty(part_index) || parts[part_index] === undefined) continue;
++
++ var prob = parts[part_index];
++ if (col_num >= this.alph_length) {
++ throw "TOO_MANY_COLS";
++ }
++ this.pspm[line_num][col_num] = (+prob);
++ //check the probability is within bounds
++ if (this.pspm[line_num][col_num] > 1 || this.pspm[line_num][col_num] < 0) {
++ throw "NUM_NOT_PROB";
++ }
++ col_num++;
++ }
++ if (col_num != this.alph_length) {
++ throw "TOO_FEW_COLS";
++ }
++ line_num++;
+ }
+- if (line_num >= this.motif_length) {
+- throw "TOO_MANY_ROWS";
++ if (line_num != this.motif_length) {
++ throw "TOO_FEW_ROWS";
+ }
+- this.pspm[line_num] = new Array(this.alph_length);
+- col_num = 0;
+- var parts = line.split(/\s+/);
+- for (part_index in parts) {
+- //exclude inherited properties and undefined properties
+- if (!parts.hasOwnProperty(part_index) || parts[part_index] === undefined) continue;
+-
+- var prob = parts[part_index];
+- if (col_num >= this.alph_length) {
+- throw "TOO_MANY_COLS";
++ } else {
++ // assume pspm is a nested array
++ this.motif_length = pspm.length;
++ this.alpha_length = (pspm.length > 0 ? pspm[0].length : 0);
++ this.pspm = new Array(this.motif_length);
++ // copy pspm and check
++ for (var row = 0; row < this.motif_length; row++) {
++ if (this.alpha_length != pspm[row].length) throw "COLUMN_MISMATCH";
++ this.pspm[row] = new Array(this.alpha_length);
++ var row_sum = 0;
++ for (var col = 0; col < this.alpha_length; col++) {
++ row_sum += this.pspm[row][col];
++ this.pspm[row][col] = 0 + pspm[row][col];
+ }
+- this.pspm[line_num][col_num] = (+prob);
+- //check the probability is within bounds
+- if (this.pspm[line_num][col_num] > 1 || this.pspm[line_num][col_num] < 0) {
+- throw "NUM_NOT_PROB";
++ var delta = 0.1
++ if ((row_sum > 1 && (row_sum - 1) > delta) ||
++ (row_sum < 1 && (1 - row_sum) > delta)) {
++ throw "INVALID_SUM";
+ }
+- col_num++;
+ }
+- if (col_num != this.alph_length) {
+- throw "TOO_FEW_COLS";
+- }
+- line_num++;
+- }
+- if (line_num != this.motif_length) {
+- throw "TOO_FEW_ROWS";
+ }
+ }
+
+@@ -413,6 +445,46 @@
+ return this.rtrim;
+ }
+
++ function Pspm_as_pspm() {
++ var out = "letter-probability matrix: alength= " + this.alph_length +
++ " w= " + this.motif_length + " nsites= " + this.nsites +
++ " E= " + this.evalue.toExponential() + "\n";
++ for (var row = 0; row < this.motif_length; row++) {
++ for (var col = 0; col < this.alph_length; col++) {
++ if (col != 0) out += " ";
++ out += this.pspm[row][col].toFixed(6);
++ }
++ out += "\n";
++ }
++ return out;
++ }
++
++ function Pspm_as_pssm(alphabet, pseudo) {
++ if (typeof pseudo != "number") pseudo = 0.1;
++ var out = "log-odds matrix: alength= " + this.alph_length +
++ " w= " + this.motif_length +
++ " E= " + this.evalue.toExponential() + "\n";
++ var log2 = Math.log(2);
++ var total = this.nsites + pseudo;
++ for (var row = 0; row < this.motif_length; row++) {
++ for (var col = 0; col < this.alph_length; col++) {
++ if (col != 0) out += " ";
++ var p = this.pspm[row][col];
++ // to avoid log of zero we add a pseudo count
++ var bg = alphabet.get_bg_freq(col);
++ var p2 = (p * this.nsites + bg * pseudo) / total;
++ // now calculate the score
++ var score = -10000;
++ if (p2 > 0) {
++ score = Math.round((Math.log(p2 / bg) / log2) * 100)
++ }
++ out += score;
++ }
++ out += "\n";
++ }
++ return out;
++ }
++
+ function Pspm_to_string() {
+ var str = "";
+ for (row_index in this.pspm) {
+@@ -1007,10 +1079,17 @@
+ cwidth = metrics.summed_width * scale;
+ cheight = metrics.summed_height * scale;
+ } else {
+- if (cwidth == 0 || cheight == 0 || scale == 0) {
++ if (cwidth == 0 && cheight == 0) {
+ throw "CANVAS_MUST_HAVE_DIMENSIONS";
++ } else if (cwidth == 0) {
++ scale = cheight / metrics.summed_height;
++ cwidth = metrics.summed_width * scale;
++ } else if (cheight == 0) {
++ scale = cwidth / metrics.summed_width;
++ cheight = metrics.summed_height * scale;
++ } else {
++ scale = Math.min(cwidth / metrics.summed_width, cheight / metrics.summed_height);
+ }
+- scale = Math.min(cwidth / metrics.summed_width, cheight / metrics.summed_height);
+ }
+ var raster = new RasterizedAlphabet(logo.alphabet, metrics.stack_font, metrics.stack_width * scale * 2);
+ if (cwidth != canvas.width || cheight != canvas.height) {
+@@ -1169,3 +1248,17 @@
+ element.parentNode.replaceChild(canvas, element);
+ }
+
++ /*
++ * Fast string trimming implementation found at
++ * http://blog.stevenlevithan.com/archives/faster-trim-javascript
++ *
++ * Note that regex is good at removing leading space but
++ * bad at removing trailing space as it has to first go through
++ * the whole string.
++ */
++ function trim (str) {
++ str = str.replace(/^\s\s*/, '');
++ var ws = /\s/, i = str.length;
++ while (ws.test(str.charAt(--i)));
++ return str.slice(0, i + 1);
++ }
+diff -uNr meme_4.6.1/etc/tomtom-to-html.xsl meme_4.6.1_patch_1/etc/tomtom-to-html.xsl
+--- meme_4.6.1/etc/tomtom-to-html.xsl 2011-02-04 05:23:17.000000000 +1000
++++ meme_4.6.1_patch_1/etc/tomtom-to-html.xsl 2011-05-23 16:16:34.574184933 +1000
+@@ -1,6 +1,7 @@
+
+
++
+
+
+
+@@ -44,12 +45,24 @@
+ span.C {font-size:20px; color:blue}
+ span.G {font-size:20px; color:orange}
+ span.T {font-size:20px; color:green}
+- .pt {padding: 0 10px}
++ table.targets td {padding: 0 10px;}
++ table.preview td {padding: 0 10px;}
++ table.preview tbody td {padding-bottom: 10px;}
+ .ac {text-align: center;}
+ .downloadTd {padding-left:20px;}
+ div.logo_container {position:relative; width:99%; height:285px; padding:0px; margin:0px;}
+ img.logo {position:absolute; z-index:2; max-width:100%;}
+ tr.tspace th, tr.tspace td {padding-top: 20px;}
++ /* motif list link, first style */
++ a.ml1 {
++ background-color: #FFF;
++ }
++ a.ml2 {
++ background-color: #FFF;
++ }
++ td.ml {
++ line-height: 1.8em;
++ }
+
+
+
+@@ -335,40 +348,40 @@
+
+
+
+-
++
+
+
+
+
+
+
+
+
+diff -uNr meme_4.6.1/scripts/meme2meme.pl.in meme_4.6.1_patch_1/scripts/meme2meme.pl.in
+--- meme_4.6.1/scripts/meme2meme.pl.in 2011-02-04 05:23:03.000000000 +1000
++++ meme_4.6.1_patch_1/scripts/meme2meme.pl.in 2011-05-23 16:09:52.274185111 +1000
+@@ -490,18 +490,30 @@
+ while ($line = <$fp>) {
+ if ($line =~ m/Background letter frequencies \(from(\s+[^\)]*)?/) {
+ my $source = $1;
++ my $alphindex = 0;
++ my @freqs = ();
+ $source =~ s/^\s*//; #trim left
+ # read the background frequencies
+- do {
++ while ($alphindex < scalar(@alphabet)) {
+ $line = <$fp>;
+- } while (defined($line) && $line =~ m/^\s*$/);# skip empty lines
+- die("Expected background frequencies on line following landmark \"Background letter frequencies (\" but got EOF.") unless defined($line);
+- my @freqs = split(/\s+/, $line);
+- for (my $i = 0; $i < scalar(@alphabet); $i++) {
+- die("Failed parsing background from \"$line\" in \"$file\", letter " . uc($freqs[$i*2]). " doesn't match expected " . $alphabet[$i] . ".\n")
+- if (uc($freqs[$i*2]) ne $alphabet[$i]);
+- my $freq = parse_double($freqs[$i*2 + 1]);
+- $bg{$alphabet[$i]} = $freq;
++ die("Encountered EOF while reading background frequencies.")
++ unless defined $line;
++ chomp($line); # remove EOL
++ $line =~ s/^\s*//; # trim left
++ $line =~ s/\s*$//; # trim right
++ my @line_freqs = split(/\s+/, $line);
++ push(@freqs, @line_freqs);
++ while(scalar(@freqs) > 2 and $alphindex < scalar(@alphabet)) {
++ my $letter = uc(shift(@freqs));
++ if ($letter ne $alphabet[$alphindex]) {
++ die("Failed parsing background from \"$line\" in \"$file\", " .
++ "letter \"" . $letter. "\" doesn't match expected " .
++ $alphabet[$alphindex] . ".\n");
++ }
++ my $freq = parse_double(shift(@freqs));
++ $bg{$alphabet[$alphindex]} = $freq;
++ $alphindex++;
++ }
+ }
+ $bg{source} = $source;
+ $bg{dna} = $is_dna;
+diff -uNr meme_4.6.1/scripts/meme-chip.pl.in meme_4.6.1_patch_1/scripts/meme-chip.pl.in
+--- meme_4.6.1/scripts/meme-chip.pl.in 2011-03-30 08:36:37.000000000 +1000
++++ meme_4.6.1_patch_1/scripts/meme-chip.pl.in 2011-05-23 16:50:42.064184029 +1000
+@@ -9,7 +9,7 @@
+ use Fcntl qw(O_CREAT O_WRONLY O_TRUNC SEEK_SET);
+ use File::Basename qw(fileparse);
+ use File::Temp qw(tempfile);
+-use File::Spec::Functions qw(abs2rel catfile catdir);
++use File::Spec::Functions qw(abs2rel catfile catdir splitdir tmpdir);
+ use Getopt::Long;
+ use HTML::Template;
+ use List::Util qw(min max);
+@@ -34,6 +34,8 @@
+ -ccut : maximum size of a sequence before it is cut down to a centered section
+ -desc : description of the job
+ -fdesc : file containing plain text description of the job
++ -run-mast : run MAST - motif alignment & search tool
++ -run-ama : run AMA - Average motif affinity.
+ -noecho : don't echo the commands run
+ -tar : create a tar.gz file of the outputs
+ -help : display this help message
+@@ -70,6 +72,9 @@
+ my $bindir = '@BINDIR@';
+ my $site_url = '@SITE_URL@';
+ my $template_file = '@APPCONFIGDIR@/meme-chip.tmpl';
++my $tmpdir = '@TMP_DIR@';
++# use the perl default if none is supplied or the replace fails
++$tmpdir = &tmpdir() if ($tmpdir eq '' || $tmpdir =~ m/^\@TMP[_]DIR\@$/);
+
+ # Required Argument
+ my $sequences;
+@@ -78,6 +83,8 @@
+ my $help = 0; # FALSE
+ my $echo = 1; # TRUE
+ my $tar = 0; # FALSE
++my $run_mast = 0; # FALSE
++my $run_ama = 0; # FALSE
+ my $appverbosity = 1; #all the applications write to stderr currently so had to disable this
+ my $clobber = 1; # TRUE
+ my $outdir = 'memechip_out';
+@@ -101,7 +108,6 @@
+
+ # Derived Globals
+ my $outfile;
+-my $tarfile;
+ my $stderr_txt;
+ my $stdout_txt;
+ my @tomtom_dbnames = ();
+@@ -120,14 +126,16 @@
+ eval {
+ # redirect stderr to a temp file as we want to log it
+ my $olderr;
+- my ($tmperr, $tnmerr) = tempfile(UNLINK => 1);
+- open $olderr, ">&STDERR" or die("Can't dup STDERR: $!");
+- open STDERR, '>', $tnmerr or die("Can't dredirect STDERR to temp file: $!");
++ my $tmperr = tempfile('GetOptions_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1);
++ open($olderr, ">&STDERR") or die("Can't dup STDERR: $!");
++ open(STDERR, '>&', $tmperr) or die("Can't redirect STDERR to temp file: $!");
+ # parse options
+ $options_success = GetOptions(
+ 'help|?' => \$help,
+ 'noecho' => sub {$echo = 0},
+ 'tar' => \$tar,
++ 'run-mast' => \$run_mast,
++ 'run-ama' => \$run_ama,
+ 'o=s' => sub {$clobber = 0; shift; $outdir = shift},
+ 'oc=s' => \$outdir,
+ 'desc=s' => \$desc,
+@@ -153,7 +161,7 @@
+ 'meme-pal' => \$meme_palindromes,
+ );
+ # reset STDERR
+- open STDERR, ">&", $olderr, or die("Can't reset STDERR: $!");
++ open(STDERR, ">&", $olderr) or die("Can't reset STDERR: $!");
+ # slurp errors
+ seek($tmperr, SEEK_SET, 0);
+ chomp($options_err = do {local ($/); <$tmperr>});
+@@ -256,7 +264,6 @@
+ }
+ # calculate some file names
+ $outfile = catfile($outdir, 'index.html');
+- $tarfile = catfile($outdir, 'meme-chip.tar.gz');
+ $stdout_txt = catfile($outdir,'stdout.txt');
+ $stderr_txt = catfile($outdir, 'stderr.txt');
+ };
+@@ -271,8 +278,7 @@
+ &main();
+ &write_html("", 0); # html to go in tar
+ if ($tar) {
+- &tar_output();
+- my $tarname = fileparse($tarfile);
++ my $tarname = &tar_output();
+ &write_html("", 0, undef, $tarname); # index which links to tar
+ }
+ };
+@@ -340,8 +346,18 @@
+ $i--;
+ }
+ }
++ # we want to tar including the outdir to avoid a tarbomb
++ # find the real name of the outdir (user could have passed '.')
++ my $folder = (splitdir(abs_path($outdir)))[-1];
++ my $folder_dir = abs_path(catdir($outdir, '..'));
++ # append the folder to the outfiles
++ for (my $i = 0; $i < scalar(@outfiles); $i++) {
++ $outfiles[$i] = catfile($folder, $outfiles[$i]);
++ }
++ my $tarname = $folder . ".tar.gz";
++ my $tarfile = catfile($outdir, $tarname);
+ # run tar
+- system('tar', '-czf', $tarfile, '-C', $outdir, @outfiles);
++ system('tar', '-czf', $tarfile, '-C', $folder_dir, @outfiles);
+ my $errmsg = '';
+ if ($? == -1) {
+ $errmsg = "Failed to execute tar: $!";
+@@ -352,6 +368,7 @@
+ $errmsg = sprintf("tar exited with value %d indicating failure.", $? >> 8);
+ }
+ die($errmsg) if $errmsg;
++ return $tarname;
+ }
+
+ ################################################################################
+@@ -470,28 +487,32 @@
+ ##################################################################
+ # Run MAST on MEME motifs
+ ##################################################################
+- my $mast_prog = "mast";
+- my $mast_outdir = "meme_mast_out";
+- my @mast_args = ('-oc', catdir($outdir, $mast_outdir), $meme_motifs, $sequences, '-ev', $num_centered_sequences);
+- push(@mast_args, '-bfile', $bfile) if defined($bfile);
+- push(@mast_args,'-nostatus') unless $appverbosity >= 2;
+- my $mast_outputs = ["mast.html", "mast.txt", "mast.xml"];
+- my $mast_comment = 'Predicted locations of all MEME motifs (p < 0.0001) in the input sequences.';
+- &report_and_run(\@report_commands, \@report_outputs,
+- $level, $bindir, $mast_prog, \@mast_args, $mast_outputs, $mast_outdir, $mast_comment);
++ if ($run_mast) {
++ my $mast_prog = "mast";
++ my $mast_outdir = "meme_mast_out";
++ my @mast_args = ('-oc', catdir($outdir, $mast_outdir), $meme_motifs, $sequences, '-ev', $num_centered_sequences);
++ push(@mast_args, '-bfile', $bfile) if defined($bfile);
++ push(@mast_args,'-nostatus') unless $appverbosity >= 2;
++ my $mast_outputs = ["mast.html", "mast.txt", "mast.xml"];
++ my $mast_comment = 'Predicted locations of all MEME motifs (p < 0.0001) in the input sequences.';
++ &report_and_run(\@report_commands, \@report_outputs,
++ $level, $bindir, $mast_prog, \@mast_args, $mast_outputs, $mast_outdir, $mast_comment);
++ }
+ ##################################################################
+ # Run AMA on MEME motifs
+ ##################################################################
+- my $ama_prog = "ama";
+- my $ama_outdir = "meme_ama_out";
+- my @ama_args = ('--verbosity', $appverbosity, '--oc', catdir($outdir, $ama_outdir));
+- push(@ama_args, '--sdbg', 0) unless defined($bfile);
+- push(@ama_args, $meme_motifs, $sequences);
+- push(@ama_args, $bfile) if defined($bfile);
+- my $ama_outputs = ["", "ama.txt", "ama.xml"];
+- my $ama_comment = 'Estimated binding affinity of each MEME motif to each input sequence.';
+- &report_and_run(\@report_commands, \@report_outputs,
+- $level, $bindir, $ama_prog, \@ama_args, $ama_outputs, $ama_outdir, $ama_comment);
++ if ($run_ama) {
++ my $ama_prog = "ama";
++ my $ama_outdir = "meme_ama_out";
++ my @ama_args = ('--verbosity', $appverbosity, '--oc', catdir($outdir, $ama_outdir));
++ push(@ama_args, '--sdbg', 0) unless defined($bfile);
++ push(@ama_args, $meme_motifs, $sequences);
++ push(@ama_args, $bfile) if defined($bfile);
++ my $ama_outputs = ["", "ama.txt", "ama.xml"];
++ my $ama_comment = 'Estimated binding affinity of each MEME motif to each input sequence.';
++ &report_and_run(\@report_commands, \@report_outputs,
++ $level, $bindir, $ama_prog, \@ama_args, $ama_outputs, $ama_outdir, $ama_comment);
++ }
+
+ $level--;
+ }
+@@ -532,28 +553,32 @@
+ ##################################################################
+ # Run MAST on DREME motifs
+ ##################################################################
+- my $mast_prog = "mast";
+- my $mast_outdir = "dreme_mast_out";
+- my @mast_args = ('-oc', catdir($outdir, $mast_outdir), $dreme_motifs, $sequences, '-ev', $num_centered_sequences);
+- push(@mast_args, '-bfile', $bfile) if defined($bfile);
+- push(@mast_args, '-nostatus') unless $appverbosity >= 2;
+- my $mast_outputs = ["mast.html", "mast.txt", "mast.xml"];
+- my $mast_comment = 'Predicted locations of all DREME motifs (p < 0.0001) in the input sequences.';
+- &report_and_run(\@report_commands, \@report_outputs,
+- $level, $bindir, $mast_prog, \@mast_args, $mast_outputs, $mast_outdir, $mast_comment);
++ if ($run_mast) {
++ my $mast_prog = "mast";
++ my $mast_outdir = "dreme_mast_out";
++ my @mast_args = ('-oc', catdir($outdir, $mast_outdir), $dreme_motifs, $sequences, '-ev', $num_centered_sequences);
++ push(@mast_args, '-bfile', $bfile) if defined($bfile);
++ push(@mast_args, '-nostatus') unless $appverbosity >= 2;
++ my $mast_outputs = ["mast.html", "mast.txt", "mast.xml"];
++ my $mast_comment = 'Predicted locations of all DREME motifs (p < 0.0001) in the input sequences.';
++ &report_and_run(\@report_commands, \@report_outputs,
++ $level, $bindir, $mast_prog, \@mast_args, $mast_outputs, $mast_outdir, $mast_comment);
++ }
+ ##################################################################
+ # Run AMA on DREME motifs
+ ##################################################################
+- my $ama_prog = "ama";
+- my $ama_outdir = "dreme_ama_out";
+- my @ama_args = ('--verbosity', $appverbosity, '--oc', catdir($outdir, $ama_outdir));
+- push(@ama_args, '--sdbg', 0) unless defined($bfile);
+- push(@ama_args, $dreme_motifs, $sequences);
+- push(@ama_args, $bfile) if defined($bfile);
+- my $ama_outputs = ["", "ama.txt", "ama.xml"];
+- my $ama_comment = 'Estimated binding affinity of each DREME motif to each input sequence.';
+- &report_and_run(\@report_commands, \@report_outputs,
+- $level, $bindir, $ama_prog, \@ama_args, $ama_outputs, $ama_outdir, $ama_comment);
++ if ($run_ama) {
++ my $ama_prog = "ama";
++ my $ama_outdir = "dreme_ama_out";
++ my @ama_args = ('--verbosity', $appverbosity, '--oc', catdir($outdir, $ama_outdir));
++ push(@ama_args, '--sdbg', 0) unless defined($bfile);
++ push(@ama_args, $dreme_motifs, $sequences);
++ push(@ama_args, $bfile) if defined($bfile);
++ my $ama_outputs = ["", "ama.txt", "ama.xml"];
++ my $ama_comment = 'Estimated binding affinity of each DREME motif to each input sequence.';
++ &report_and_run(\@report_commands, \@report_outputs,
++ $level, $bindir, $ama_prog, \@ama_args, $ama_outputs, $ama_outdir, $ama_comment);
++ }
+
+ $level--;
+ }
+@@ -589,40 +614,37 @@
+ my ($filename) = @_;
+ # redirect stdout to a temp file
+ my $oldout;
+- my ($tmpout, $tnmout) = tempfile(UNLINK => 1);
+- open $oldout, ">&STDOUT" or die("Can't dup STDOUT: $!");
+- open STDOUT, '>', $tnmout or die("Can't redirect STDOUT to temp file: $!");
++ my $tmpout = tempfile('getsize_stdout_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1);
++ open($oldout, ">&STDOUT") or die("Can't dup STDOUT: $!");
++ open(STDOUT, '>&', $tmpout) or die("Can't redirect STDOUT to temp file: $!");
+ # redirect stderr to a temp file
+ my $olderr;
+- my ($tmperr, $tnmerr) = tempfile(UNLINK => 1);
+- open $olderr, ">&STDERR" or die("Can't dup STDERR: $!");
+- open STDERR, '>', $tnmerr or die("Can't dredirect STDERR to temp file: $!");
++ my $tmperr = tempfile('getsize_stderr_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1);
++ open($olderr, ">&STDERR") or die("Can't dup STDERR: $!");
++ open(STDERR, '>&', $tmperr) or die("Can't dredirect STDERR to temp file: $!");
+
+ # run command
+ system($bindir.'/getsize', $filename);
+ # copy status
+ my $status = $?;
+ # reset stderr
+- open STDERR, ">&", $olderr, or die("Can't reset STDERR: $!");
++ open(STDERR, ">&", $olderr) or die("Can't reset STDERR: $!");
+ # reset stdout
+- open STDOUT, ">&", $oldout or die("Can't reset STDOUT: $!");
++ open(STDOUT, ">&", $oldout) or die("Can't reset STDOUT: $!");
+
+ # slurp output and errors
+- my $lineterm = $/;
+- undef $/;
+- seek($tmpout, SEEK_SET, 0);
+- my $output = <$tmpout>;
++ seek($tmpout, 0, SEEK_SET);
++ my $output = do {local $/ = undef; <$tmpout>};
+ close($tmpout);
+- seek($tmperr, SEEK_SET, 0);
+- my $errors = <$tmperr>;
++ seek($tmperr, 0, SEEK_SET);
++ my $errors = do {local $/ = undef; <$tmperr>};
+ close($tmperr);
+- $/ = $lineterm;
+
+ #log errors
+ if ($errors) {
+- my $msg = "'getsize $filename': ".$errors;
++ my $msg = "'getsize $filename': " . $errors;
+ $logger->error($msg) if ($logger);
+- print STDERR $msg, "\n";
++ print(STDERR $msg, "\n");
+ }
+
+ # check status
+diff -uNr meme_4.6.1/scripts/meme-chip_webservice.pl.in meme_4.6.1_patch_1/scripts/meme-chip_webservice.pl.in
+--- meme_4.6.1/scripts/meme-chip_webservice.pl.in 2011-03-30 08:35:54.000000000 +1000
++++ meme_4.6.1_patch_1/scripts/meme-chip_webservice.pl.in 2011-05-23 16:37:38.394184374 +1000
+@@ -23,6 +23,8 @@
+ meme-chip_webservice [options]
+
+ Options:
++ -run-mast : run MAST - motif alignment & search tool
++ -run-ama : run AMA - average motif affinity
+ -bfile : background file
+
+ MEME Specific Options:
+@@ -45,6 +47,8 @@
+ my $log_file = 'memechip-log';
+
+ # Options
++my $run_mast = 0; # FALSE
++my $run_ama = 0; #FALSE
+ my $bfile = undef;
+ my $meme_mod = undef;
+ my $meme_minw = undef;
+@@ -73,6 +77,8 @@
+
+ eval {
+ GetOptions(
++ 'run-mast' => \$run_mast,
++ 'run-ama' => \$run_ama,
+ 'bfile=s' => \$bfile,
+ 'meme-mod=s' => \$meme_mod,
+ 'meme-minw=i' => \$meme_minw,
+@@ -122,6 +128,8 @@
+ my $exe = catfile($bin_dir, 'meme-chip');
+ # prepare meme-chip arguments
+ my @args = ('-noecho', '-tar', '-oc', '.', '-meme-time', $MAXTIME);
++push(@args, '-run-mast') if $run_mast;
++push(@args, '-run-ama') if $run_ama;
+ push(@args, '-fdesc', 'description') if (-e 'description');
+ push(@args, '-bfile', $bfile) if $bfile;
+ foreach my $db (@motif_dbs) {
+diff -uNr meme_4.6.1/scripts/MemeWebUtils.pm.in meme_4.6.1_patch_1/scripts/MemeWebUtils.pm.in
+--- meme_4.6.1/scripts/MemeWebUtils.pm.in 2011-03-10 08:31:41.000000000 +1000
++++ meme_4.6.1_patch_1/scripts/MemeWebUtils.pm.in 2011-05-23 16:50:42.064184029 +1000
+@@ -13,22 +13,37 @@
+ valid_address valid_meme_version add_status_msg update_status loggable_args loggable_date write_invocation_log invoke);
+
+ use Cwd;
+-use Fcntl qw(O_APPEND O_CREAT O_WRONLY SEEK_SET);
++use Fcntl qw(O_APPEND O_CREAT O_WRONLY O_TRUNC SEEK_SET);
+ use File::Basename qw(fileparse);
+ use File::Copy qw(copy);
+-use File::Spec::Functions qw(catfile splitdir);
++use File::Spec::Functions qw(catfile splitdir tmpdir);
+ use File::Temp qw(tempfile);
+ use HTTP::Request::Common qw(GET);
+ use XML::Simple;
+ use HTML::PullParser;
+ use HTML::Template;
+ use Sys::Hostname;
++use Time::HiRes qw(gettimeofday tv_interval);
+
+ use lib qw(@PERLLIBDIR@);
+ use CatList qw(load_categories load_entry);
+
++# Setup logging
++my $logger = undef;
++eval {
++ require Log::Log4perl;
++ Log::Log4perl->import();
++};
++unless ($@) {
++ Log::Log4perl::init('@APPCONFIGDIR@/logging.conf');
++ $logger = Log::Log4perl->get_logger('meme.cgi.utils');
++}
++
+ my $template_dir = '@WEB_DIR@/cgi-bin';
+ my $service_invocation_log_dir = '@MEMELOGS@';
++my $tmpdir = '@TMP_DIR@';
++# use the perl default if none is supplied or the replace fails
++$tmpdir = &tmpdir() if ($tmpdir eq '' || $tmpdir =~ m/^\@TMP[_]DIR\@$/);
+ ##############################################################################
+ # Functions
+ ##############################################################################
+@@ -98,6 +113,17 @@
+ sub is_numeric { defined &getnum($_[0]) }
+
+ #
++# Output large integers with commas
++#
++#
++sub commify {
++ my $input = shift;
++ $input = reverse $input;
++ $input =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
++ return reverse $input;
++}
++
++#
+ # get the alphabet of a string: DNA or PROTEIN
+ #
+ # Used in
+@@ -227,8 +253,8 @@
+ push(@found_files, $entry) if (defined($file) && -e $file && -s $file);
+ }
+
+- my $fh; # I'm suspicious that the 0777 may be too permissive (but that's what we had before)
+- sysopen($fh, $output_file, O_CREAT | O_WRONLY, 0777) or die("Failed to open \"$output_file\".");
++ my $fh;
++ sysopen($fh, $output_file, O_CREAT | O_WRONLY | O_TRUNC) or die("Failed to open \"$output_file\".");
+ my $template = HTML::Template->new(filename => "$template_dir/job_status.tmpl");
+ $template->param(program => $program, refresh => $refresh, files => \@found_files, msgs => $msg_list, status => $status);
+ print $fh $template->output;
+@@ -342,21 +368,36 @@
+ # PROG => program name
+ # BIN => program directory
+ # ARGS => reference to array of program arguments
+-# IN_FILE => file to set as stdin
++# IN_FILE => file name or handle to set as stdin
+ # IN_VAR => variable (or reference to variable) to feed in as stdin
+-# OUT_FILE => file to store stdout
++# IN_NAME => the displayed name for the source of stdin
++# ALL_FILE => file name or handle to store stdout and stderr
++# ALL_VAR => reference to variable to store stdout and stderr
++# ALL_NAME => the displayed name for the destination of output
++# OUT_FILE => file name or handle to store stdout
+ # OUT_VAR => reference to variable to store stdout
+-# ERR_FILE => file to store stderr
++# OUT_NAME => the displayed name for the destination of stdout
++# ERR_FILE => file name or handle to store stderr
+ # ERR_VAR => reference to variable to store stderr
++# ERR_NAME => the displayed name for the destination of stderr
+ # CHECK_STATUS => true to die on bad status codes
++# TRUNCATE => true to truncate output files if they exist
+ # CMD => reference to store a human readable form of the command run
++# TIME => reference to store the running time in seconds (floating point)
++# TMPDIR => directory to create temporary files
+ #
+ sub invoke {
+ my %opts = @_;
++ my $logger = $opts{LOGGER};
++ $logger->trace("sub invoke") if $logger;
++ # output truncates?
++ my $dir = ($opts{TRUNCATE} ? '>' : '>>'); #direction
++ # temp file directory
++ my $tmpdir = ($opts{TMPDIR} ? $opts{TMPDIR} : &tmpdir());
+ # get program
+ my $prog = $opts{PROG};
+- my $exe = (defined($opts{BIN}) ? catfile($opts{BIN}, $prog) : $prog);
+- die("No program passed to _invoke") unless defined($prog);
++ die("No program passed to invoke") unless defined($prog);
++ my $exe = (defined($opts{BIN}) ? &catfile($opts{BIN}, $prog) : $prog);
+ # get args
+ my $args_ref = $opts{ARGS};
+ my @args = ();
+@@ -364,85 +405,161 @@
+ @args = @{$args_ref};
+ }
+ # make command line for printing
+- my $cmd = loggable_args($prog, @args);
++ my $cmd = &loggable_args($prog, @args);
++ # do redirection
++ my $display_name;
+ # check if we're redirecting stdin
+ my ($in_old, $in_tmp, $in_nam);
+ if (defined($opts{IN_FILE}) || defined($opts{IN_VAR})) {
+- #save stdin
++ $logger->trace("invoke - redirecing stdin") if $logger;
++ # save stdin
+ open($in_old, "<&STDIN") or die("Can't dup STDIN: $!");
++ # redirect stdin
+ if (defined($opts{IN_FILE})) { # read stdin from specified file
+- $in_nam = $opts{IN_FILE};
+- $cmd .= ' < '.loggable_arg($in_nam);
++ if (ref($opts{IN_FILE})) { # file handle (we hope)
++ my $handle = $opts{IN_FILE};
++ open(STDIN, '<&', $handle) or die("Can't redirect STDIN: $!");
++ $display_name = 'input_file';
++ } else { # file name (we hope)
++ my $name = $opts{IN_FILE};
++ open(STDIN, '<', $name) or die("Can't redirect STDIN: $!");
++ $display_name = &loggable_arg($name);
++ }
+ } else { # read stdin from a temp file which we preload with the var
+- # make a temporary file
+- ($in_tmp, $in_nam) = tempfile(UNLINK => 1);
+- # write the variable to the file
+- my $var = $opts{IN_VAR};
++ $in_tmp = &tempfile('stdin_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1); # make a temporary file
++ my $var = $opts{IN_VAR}; # variable could be passed as a ref or scalar
+ my $var_ref = (ref($var) ? $var : \$var);
+- print $in_tmp ${$var_ref};
+- $cmd .= ' < $input';
++ print $in_tmp ${$var_ref}; # write variable to file
++ seek($in_tmp, 0, SEEK_SET); # rewind file
++ open(STDIN, '<&', $in_tmp) or die("Can't redirect STDIN: $!");
++ $display_name = '$input';
+ }
+- open(STDIN, '<', $in_nam) or die("Can't redirect STDIN: $!");
++ $display_name = $opts{IN_NAME} if defined($opts{IN_NAME});
++ $cmd .= ' < ' . $display_name;
+ }
+- # check if we're redirecting stdout
+- my ($out_old, $out_tmp, $out_nam);
+- if (defined($opts{OUT_FILE}) || defined($opts{OUT_VAR})) {
+- #save stdout
++ # check for output redirection
++ my ($out_old, $err_old);
++ my ($all_tmp, $out_tmp, $err_tmp);
++ if (defined($opts{ALL_FILE}) || defined($opts{ALL_VAR})) {
++ $logger->trace("invoke - redirecing output") if $logger;
++ # save stdout and stderr
+ open($out_old, ">&STDOUT") or die("Can't dup STDOUT: $!");
+- if (defined($opts{OUT_FILE})) { # send stdout to specified file
+- $out_nam = $opts{OUT_FILE};
+- $cmd .= ' 1> '.loggable_arg($out_nam);
+- } else { # send stdout to a temp file which we can read in to the var
+- # make a temporary file
+- ($out_tmp, $out_nam) = tempfile(UNLINK => 1);
+- $cmd .= ' 1> $output';
+- }
+- open(STDOUT, '>', $out_nam) or die("Can't redirect STDOUT: $!");
+- }
+- # check if we're redirecting stderr
+- my ($err_old, $err_tmp, $err_nam);
+- if (defined($opts{ERR_FILE}) || defined($opts{ERR_VAR})) {
+- #save stderr
+ open($err_old, ">&STDERR") or die("Can't dup STDERR: $!");
+- if (defined($opts{ERR_FILE})) { # send stderr to specified file
+- $err_nam = $opts{ERR_FILE};
+- $cmd .= ' 2> '.loggable_arg($err_nam);
+- } else { # send stderr to a temp file which we can read in to the var
+- # make a temporary file
+- ($err_tmp, $err_nam) = tempfile(UNLINK => 1);
+- $cmd .= ' 2> $error';
++ # redirect stdout and stderr
++ if (defined($opts{ALL_FILE})) { # send output to specified file
++ truncate($opts{ALL_FILE}, 0) if ($opts{TRUNCATE});
++ if (ref($opts{ALL_FILE})) { # file handle (we hope)
++ my $handle = $opts{ALL_FILE};
++ open(STDOUT, '>>&', $handle) or die("Can't redirect STDOUT: $!");
++ open(STDERR, '>>&', $handle) or die("Can't redirect STDERR: $!");
++ $display_name = 'output_file';
++ } else { # file name (we hope)
++ my $name = $opts{ALL_FILE};
++ open(STDOUT, '>>', $name) or die("Can't redirect STDOUT: $!");
++ open(STDERR, '>>', $name) or die("Can't redirect STDERR: $!");
++ $display_name = &loggable_arg($name);
++ }
++ } else {
++ $all_tmp = &tempfile('allout_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1); # make a temporary file
++ open(STDOUT, '>>&', $all_tmp) or die("Can't redirect STDOUT: $!");
++ open(STDERR, '>>&', $all_tmp) or die("Can't redirect STDERR: $!");
++ $display_name = '$all_messages';
++ }
++ # turn off buffering so output order is maintained
++ my $oldfh;
++ $oldfh = select(STDOUT);
++ $| = 1;
++ select(STDERR);
++ $| = 1;
++ select($oldfh);
++ # update command
++ $display_name = $opts{ALL_NAME} if defined($opts{ALL_NAME});
++ $cmd .= ' &'. $dir . ' ' . $display_name;
++ } else {
++ # check if we're redirecting stdout
++ if (defined($opts{OUT_FILE}) || defined($opts{OUT_VAR})) {
++ $logger->trace("invoke - redirecing stdout") if $logger;
++ # save stdout
++ open($out_old, ">&STDOUT") or die("Can't dup STDOUT: $!");
++ # redirect stdout
++ if (defined($opts{OUT_FILE})) { # send stdout to specified file
++ if (ref($opts{OUT_FILE})) { # file handle (we hope)
++ my $handle = $opts{OUT_FILE};
++ open(STDOUT, $dir.'&', $handle) or die("Can't redirect STDOUT: $!");
++ $display_name = 'output_file';
++ } else { # file name (we hope)
++ my $name = $opts{OUT_FILE};
++ open(STDOUT, $dir, $name) or die("Can't redirect STDOUT: $!");
++ $display_name = &loggable_arg($name);
++ }
++ } else { # send stdout to a temp file which we can read in to the var
++ $out_tmp = &tempfile('stdout_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1); # make a temporary file
++ open(STDOUT, '>&', $out_tmp) or die("Can't redirect STDOUT: $!");
++ $display_name = '$output_messages';
++ }
++ $display_name = $opts{OUT_NAME} if defined($opts{OUT_NAME});
++ $cmd .= ' 1'. $dir . ' ' . $display_name;
++ }
++ # check if we're redirecting stderr
++ if (defined($opts{ERR_FILE}) || defined($opts{ERR_VAR})) {
++ $logger->trace("invoke - redirecing stderr") if $logger;
++ # save stderr
++ open($err_old, ">&STDERR") or die("Can't dup STDERR: $!");
++ # redirect stderr
++ if (defined($opts{ERR_FILE})) { # send stderr to specified file
++ if (ref($opts{ERR_FILE})) { # file handle (we hope)
++ my $handle = $opts{ERR_FILE};
++ open(STDERR, $dir.'&', $handle) or die("Can't redirect STDERR: $!");
++ $display_name = 'error_file';
++ } else { # file name (we hope)
++ my $name = $opts{ERR_FILE};
++ open(STDERR, $dir, $name) or die("Can't redirect STDERR: $!");
++ $display_name = &loggable_arg($name);
++ }
++ } else { # send stderr to a temp file which we can read in to the var
++ $err_tmp = &tempfile('stderr_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1); # make a temporary file
++ open(STDERR, '>&', $err_tmp) or die("Can't redirect STDERR: $!");
++ $display_name = '$error_messages';
++ }
++ $display_name = $opts{ERR_NAME} if defined($opts{ERR_NAME});
++ $cmd .= ' 2' . $dir . ' ' . $display_name;
+ }
+- open(STDERR, '>', $err_nam) or die("Can't redirect STDERR: $!");
+ }
++ # record the time before starting the program
++ $logger->trace("invoke - recording start time") if $logger;
++ my $t0 = [&gettimeofday()];
+ # run the command
++ $logger->trace("invoke - running") if $logger;
+ my $status = system($exe, @args);
+- # reset stdin
++ # record the time after completing the program
++ $logger->trace("invoke - recording end time") if $logger;
++ my $t1 = [&gettimeofday()];
++ # check if the caller wants the elapsed time
++ if (defined($opts{TIME})) {
++ ${$opts{TIME}} = &tv_interval($t0, $t1);
++ }
++ # reset file descriptors
+ if (defined($in_old)) {
++ $logger->trace("invoke - reseting stdin") if $logger;
+ open(STDIN, "<&", $in_old) or die("Can't reset STDIN: $!");
+ }
+- # reset stdout
+ if (defined($out_old)) {
++ $logger->trace("invoke - reseting stdout") if $logger;
+ open(STDOUT, ">&", $out_old) or die("Can't reset STDOUT: $!");
+ }
+- # reset stderr
+ if (defined($err_old)) {
++ $logger->trace("invoke - reseting stderr") if $logger;
+ open(STDERR, ">&", $err_old) or die("Can't reset STDERR: $!");
+ }
+- # clean up stdin temp file
+- if (defined($in_tmp)) {
+- close($in_tmp);
+- }
+- # read and close stdout temp file
+- if (defined($out_tmp)) {
+- ${$opts{OUT_VAR}} = do {local $/ = undef; <$out_tmp>};
+- close($out_tmp);
+- }
+- # read and close stderr temp file
+- if (defined($err_tmp)) {
+- ${$opts{ERR_VAR}} = do {local $/ = undef; <$err_tmp>};
+- close($err_tmp);
+- }
++ # close stdin temporary file
++ close($in_tmp) if (defined($in_tmp));
++ # rewind, slurp and close temporary files
++ ${$opts{ALL_VAR}} = &rewind_slurp_close($all_tmp) if (defined($all_tmp));
++ ${$opts{OUT_VAR}} = &rewind_slurp_close($out_tmp) if (defined($out_tmp));
++ ${$opts{ERR_VAR}} = &rewind_slurp_close($err_tmp) if (defined($err_tmp));
++
+ if ($opts{CHECK_STATUS}) {
++ $logger->trace("invoke - checking status") if $logger;
+ # check status
+ if ($status == -1) {
+ die("Failed to execute command '". $cmd . "': $!");
+@@ -458,9 +575,19 @@
+ ${$opts{CMD}} = $cmd;
+ }
+
++ $logger->trace("invoke - returning") if $logger;
+ return $status;
+ }
+
++# utility used by invoke
++sub rewind_slurp_close {
++ my ($fh) = @_;
++ seek($fh, 0, SEEK_SET);
++ my $content = do {local $/ = undef; <$fh>};
++ close($fh);
++ return $content;
++}
++
+ ##############################################################################
+ # Object Methods
+ ##############################################################################
+@@ -639,6 +766,20 @@
+ }
+ } # check_description
+
++#
++# I wanted to use the unlink1 used by File::Temp
++# but for some reason they don't allow it to be
++# exported. It shouldn't matter that I don't
++# get the stat compare before the delete though
++# as there shouldn't be any doubt that they
++# refer to the same file.
++#
++sub unlink1 {
++ $logger->trace("sub unlink1") if $logger;
++ my ($fh, $filename) = @_;
++ close($fh);
++ unlink($filename);
++}
+
+ #
+ # get sequence data
+@@ -657,6 +798,7 @@
+ # glam2.pl
+ #
+ sub get_sequence_data {
++ $logger->trace("sub get_sequence_data") if $logger;
+ my $self = shift;
+ die("Expected Utils object") unless ref($self) eq 'MemeWebUtils';
+ my $PROGRAM = $self->{PROGRAM};
+@@ -668,7 +810,11 @@
+ $shuffle, # shuffle sequences if true
+ $purge_score, # if nonempty the score for purge
+ $dust_cutoff, # if nonempty the cutoff for dust
++ $dataset_name # if nonempty the name of the dataset used in messages
+ ) = @_;
++ $logger->debug('get_sequence_data - file: "' . $file . '" file size: ' . (-s $file)) if $logger;
++
++ $dataset_name = 'input dataset' unless defined($dataset_name);
+ # return values
+ my $fasta_data = ""; # sequence data in FASTA format
+ my $alphabet = "UNRECOGNIZED"; # sequence alphabet DNA/PROTEIN
+@@ -688,14 +834,16 @@
+ my ($fasta_tmp, $fasta_nam);
+
+ # other vars
+- my ($status, $error);
++ my ($status, $errors, $size, $has_problems);
+
+ # check that sequence data was provided
+ if (!$file && !$data) {
+ $self->whine(
+- "You haven't entered any sequence data. ",
+- "If you still wish to submit a query, please go back and enter the",
+- "name of a sequence file or the actual sequences."
++ "No data was entered for the $dataset_name but $PROGRAM requires the ",
++ "$dataset_name to run. ",
++ "If you still wish to submit a query, please go back and either select ",
++ "a sequence file to upload or paste the actual sequences for the ",
++ "$dataset_name."
+ );
+ goto DONE;
+ }
+@@ -703,128 +851,135 @@
+ # don't allow both datafile and data
+ if ($file && $data) {
+ $self->whine(
+- "You may not enter both the name of a sequence file and sequences. ",
+- "If you still wish to submit a query, please go back and erase either",
+- "what you have written in the name of a file field or",
+- "in the actual sequences field."
++ "Both the sequence file and actual sequences were entered for the ",
++ "$dataset_name. ",
++ "If you still wish to submit a query, please go back and either clear",
++ "the file selection or erase the content of the actual sequences field."
+ );
+ goto DONE;
+ }
+
+ # don't allow empty sequence files
+ if ($file && (-s $file) == 0) {
+- $self->whine("Your sequence file is empty.");
++ $self->whine(
++ "The sequence file entered for the $dataset_name is empty ",
++ "but $PROGRAM requires at least 1 sequence to run. ",
++ "If you still wish to submit a query, please go back and select ",
++ "a non-empty sequence file to upload or paste actual sequences for ",
++ "the $dataset_name."
++ );
+ goto DONE;
+ }
+
+- #
+- # create a file containing the raw sequences
+- #
+-
+- # slurp the uploaded file into a scalar if there was no textbox data
+- $data = do {local $/; <$file>} unless ($data);
+-
+- # convert to UNIX EOL
+- $data =~ s/\r\n/\n/g; # Windows -> UNIX eol
+- $data =~ s/\r/\n/g; # MacOS -> UNIX eol
+-
+ # print raw sequences to a file
+- ($raw_tmp, $raw_nam) = tempfile(UNLINK => 1);
+- print $raw_tmp $data;
+-
+- #
+- # convert raw sequences to FASTA format using READSEQ
+- #
+- ($cooked_tmp, $cooked_nam) = tempfile(UNLINK => 1);
+- $status = &invoke(BIN => $BIN_DIR, PROG => 'readseq', ARGS => ['-a', '-f=8', $raw_nam], OUT_FILE => $cooked_nam, ERR_VAR => \$error);
+-
+- # check for errors
+- if ($status) {
+- $self->whine(
+- "An error occurred when the READSEQ program attempted to convert",
+- "your dataset to FASTA format. ",
+- "READSEQ returned:
$error
"
+- );
+- goto DONE;
++ ($raw_tmp, $raw_nam) = tempfile('raw_seqs_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1);
++ $logger->debug('get_sequence_data - $raw_tmp: ' . $raw_nam) if $logger;
++ if ($data) {
++ # convert to UNIX EOL
++ $data =~ s/\r\n/\n/g; # Windows -> UNIX eol
++ $data =~ s/\r/\n/g; # MacOS -> UNIX eol
++ # print to file
++ print $raw_tmp $data;
++ } else {
++ # copy the file changing to UNIX EOL
++ my $line;
++ while ($line = <$file>) {
++ chomp($line);
++ print $raw_tmp $line, "\n";
++ }
+ }
+
+- #
+- # get information on sequences
+- #
+- my($getsize_seqs, $getsize_cooked);
++ # run GETSIZE on the raw sequences and see if it reports any errors
++ $status = &invoke(BIN => $BIN_DIR, PROG => 'getsize', ARGS => [$raw_nam],
++ OUT_VAR => \$size, ERR_VAR => \$errors, LOGGER => $logger);
++ $logger->debug('get_sequence_data - GETSIZE on raw seqs: ' . $size) if $logger;
++
++ if ($errors || $status) {
++ # maybe the file is not FASTA format? Attempt to convert it using READSEQ
++ ($cooked_tmp, $cooked_nam) = tempfile('cooked_seqs_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1);
++ $status = &invoke(BIN => $BIN_DIR, PROG => 'readseq', ARGS =>
++ ['-a', '-f=8', $raw_nam], OUT_FILE => $cooked_nam, ERR_VAR => \$errors);
+
+- # Run the 'getsize' program to get information on the raw sequence data.
+- &invoke(BIN => $BIN_DIR, PROG => 'getsize', ARGS => [$raw_nam], OUT_VAR => \$getsize_seqs, ERR_FILE => '/dev/null');
++ # check for errors
++ if ($status) {
++ $self->whine(
++ "The sequences submitted for the $dataset_name could not be read as ",
++ "FASTA format and automatic conversion using the READSEQ program ",
++ "failed. ",
++ "READSEQ returned:
$errors
",
++ "If you still wish to submit a query, please go back and select ",
++ "a FASTA formatted sequence file to upload or paste actual ",
++ "sequences in FASTA format for the $dataset_name."
++ );
++ goto DONE;
++ }
+
+- # Run the 'getsize' program to get information on converted data; will
+- # be unchanged if it is FASTA (note -nd means do not print warnings about duplicate sequences)
+- $status = &invoke(BIN => $BIN_DIR, PROG => 'getsize', ARGS => ['-nd', $cooked_nam], OUT_VAR => \$getsize_cooked, ERR_VAR => \$error);
++ #run GETSIZE on the converted sequences
++ #(note -nd means do not print warnings about duplicate sequences)
++ $status = &invoke(BIN => $BIN_DIR, PROG => 'getsize', ARGS =>
++ ['-nd', $cooked_nam], OUT_VAR => \$size,
++ ERR_VAR => \$errors);
++ $logger->debug('get_sequence_data - GETSIZE on cooked seqs: ' . $size) if $logger;
+
+- # check for errors
+- if ($error || $status) {
+- $self->whine(
+- "After converting to FASTA format using the READSEQ program,",
+- "the following errors in your dataset were detected:
$error
",
+- " Make sure all your sequences are in the same format since READSEQ",
+- "assumes that all sequences are in the same format as the first sequence.",
+- );
+- goto DONE;
+- }
+-
+- # choose between the original and the cooked version
+- if ($getsize_seqs ne $getsize_cooked) {
+- # use cooked dataset
+- $getsize_seqs = $getsize_cooked;
++ # check for errors
++ if ($errors || $status) {
++ $self->whine(
++ "The sequences submitted for the $dataset_name were converted to ",
++ "FASTA format but in the process of detecting the alphabet and size ",
++ "the following errors in your dataset were detected:
$errors
",
++ " Make sure all your sequences are in the same format since READSEQ",
++ "assumes that all sequences are in the same format as the first sequence."
++ );
++ goto DONE;
++ }
++ # use converted dataset
+ ($fasta_tmp, $fasta_nam) = ($cooked_tmp, $cooked_nam);
+- close($raw_tmp);
++ &unlink1($raw_tmp, $raw_nam); # this should be done when perl exits as well
+ } else {
+ # use original dataset
+ ($fasta_tmp, $fasta_nam) = ($raw_tmp, $raw_nam);
+- close($cooked_tmp);
+ }
+- $raw_tmp = undef;
+- $raw_nam = undef;
+- $cooked_tmp = undef;
+- $cooked_nam = undef;
++ # just so we don't close a file twice later
++ $raw_tmp = undef; $raw_nam = undef; $cooked_tmp = undef; $cooked_nam = undef;
+
+ # extract out the sequence stats from getsize's response
+ my $letters;
+- ($nseqs, $min, $max, $ave, $total, $letters) = split (' ', $getsize_seqs);
++ ($nseqs, $min, $max, $ave, $total, $letters) = split (' ', $size);
++
++ $has_problems = 0;
+
+- #
+- # final checks
+- #
+ # check for problem reading the dataset
+ if ($nseqs <= 0) {
+ $self->whine(
+- "Your dataset appears to be in a format that $PROGRAM does not recognize.",
+- " Please check to be sure that your data is",
++ "The sequences submitted for the $dataset_name appear to be ",
++ "in a format that $PROGRAM does not recognize. ",
++ "Please check to be sure that your data is ",
+ "formatted properly."
+ );
+- goto DONE;
++ $has_problems = 1;
+ }
+ # check for bad sequences
+ if ($nseqs > 0 && $min == 0) {
+ $self->whine(
+- "Your dataset appears to contain one or more zero-length sequences.",
+- " Please check to be sure that your data is",
++ "The sequences submitted for the $dataset_name appear to ",
++ "contain one or more zero-length sequences. ",
++ "Please check to be sure that your data is ",
+ " formatted properly."
+ );
+- goto DONE;
++ $has_problems = 1;
+ }
+ # Make sure there isn't too much data.
+ if ($total > $maxsize) {
+ $self->whine(
+- "The data you have entered contains more than $maxsize characters.",
+- "$PROGRAM cannot process it at this time. ",
++ "The sequences submitted for the $dataset_name contain ",
++ &commify($total) . " characters but $PROGRAM can only accept ",
++ &commify($maxsize) . " characters. ",
+ "Please submit a smaller dataset."
+ );
+- goto DONE;
++ $has_problems = 1;
+ }
+
+- #
+ # prepare sequences and alphabet and do filtering if requested
+- #
+
+ # calculate the alphabet
+ my $bad_symbols;
+@@ -837,31 +992,35 @@
+
+ my @bad_lines = $self->find_bad_sequence_data($bad_symbols, $data);
+ $self->whine(
+- "Your sequences contained the following unrecognized letters: $bad_symbols. ",
++ "The sequences submitted for the $dataset_name contained the ",
++ "following unrecognized letters: $bad_symbols. ",
+ "The unrecognized letters occurred in the following locations:",
+ @bad_lines,
+ " ",
+ "Please convert your sequences to one of the recognized sequence",
+ "alphabets."
+ );
+- goto DONE;
++ $has_problems = 1;
+ }
+
++ goto DONE if $has_problems;
++
+ # shuffle sequences if requested
+ if ($shuffle) {
+- ($shuffled_tmp, $shuffled_nam) = tempfile(UNLINK => 1);
++ ($shuffled_tmp, $shuffled_nam) = tempfile('shuffled_seqs_XXXXXXXXXX', DIR => $tmpdir, UNLINK => 1);
+
+ $status = &invoke(BIN => $BIN_DIR, PROG => 'fasta-shuffle-letters', ARGS => ['-tod'],
+- IN_FILE => $fasta_nam, OUT_FILE => $shuffled_nam, ERR_VAR => \$error);
++ IN_FILE => $fasta_nam, OUT_FILE => $shuffled_nam, ERR_VAR => \$errors);
+
+- if ($error || $status) {
++ if ($errors || $status) {
+ $self->whine(
+- "After shuffling, the following errors resulted:
$error
",
++ "When shuffling the $dataset_name, the following errors ",
++ "resulted:
$errors
",
+ " Please check your sequences."
+ );
+ goto DONE;
+ }
+- close($fasta_tmp);
++ &unlink1($fasta_tmp, $fasta_nam); # this should be done when perl exits as well
+ ($fasta_tmp, $fasta_nam) = ($shuffled_tmp, $shuffled_nam);
+ $shuffled_tmp = undef;
+ $shuffled_nam = undef;
+@@ -876,20 +1035,21 @@
+ # instead it always writes to a file called .
+ my $purge_out = $fasta_nam . '.' . $purge_score;
+ die("Purge output file already exists!") if (-e $purge_out);
+- $status = &invoke(BIN => $BIN_DIR, PROG => 'purge', ARGS => \@purge_args, ERR_VAR => \$error);
++ $status = &invoke(BIN => $BIN_DIR, PROG => 'purge', ARGS => \@purge_args, ERR_VAR => \$errors);
+ # check for errors
+- if ($error || $status) {
+- $self->whine("From purge, the following errors resulted:
$error
");
++ if ($errors || $status) {
++ $self->whine("When calling purge on the $dataset_name, the following ",
++ "errors resulted: