Repository 'toolfactory'
hg clone https://toolshed.g2.bx.psu.edu/repos/fubar/toolfactory

Changeset 34:c6fdf2c6d0f4 (2014-08-28)
Previous changeset 33:ca60c96f0beb (2014-08-28) Next changeset 35:117a5ada6a6a (2014-08-28)
Commit message:
Citations added (thanks John!) and a few more output formats for Alistair Chilcott
added:
old.xml
rgToolFactoryMultIn.py
rgToolFactoryMultIn.xml
b
diff -r ca60c96f0beb -r c6fdf2c6d0f4 old.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/old.xml Thu Aug 28 02:33:05 2014 -0400
b
b'@@ -0,0 +1,835 @@\n+<tool id="rgedgeRpaired" name="edgeR" version="0.20">\n+  <description>1 or 2 level models for count data</description>\n+  <requirements>\n+      <requirement type="package" version="2.12">biocbasics</requirement>\n+      <requirement type="package" version="3.0.1">package_r3</requirement>\n+  </requirements>\n+  \n+  <command interpreter="python">\n+     rgToolFactory.py --script_path "$runme" --interpreter "Rscript" --tool_name "edgeR" \n+    --output_dir "$html_file.files_path" --output_html "$html_file" --output_tab "$outtab" --make_HTML "yes"\n+  </command>\n+  <inputs>\n+    <param name="input1"  type="data" format="tabular" label="Select an input matrix - rows are contigs, columns are counts for each sample"\n+       help="Use the HTSeq based count matrix preparation tool to create these matrices from BAM/SAM files and a GTF file of genomic features"/>\n+    <param name="title" type="text" value="edgeR" size="80" label="Title for job outputs" help="Supply a meaningful name here to remind you what the outputs contain">\n+      <sanitizer invalid_char="">\n+        <valid initial="string.letters,string.digits"><add value="_" /> </valid>\n+      </sanitizer>\n+    </param>\n+    <param name="treatment_name" type="text" value="Treatment" size="50" label="Treatment Name"/>\n+    <param name="Treat_cols" label="Select columns containing treatment." type="data_column" data_ref="input1" numerical="True" \n+         multiple="true" use_header_names="true" size="120" display="checkboxes">\n+        <validator type="no_options" message="Please select at least one column."/>\n+    </param>\n+    <param name="control_name" type="text" value="Control" size="50" label="Control Name"/>\n+    <param name="Control_cols" label="Select columns containing control." type="data_column" data_ref="input1" numerical="True" \n+         multiple="true" use_header_names="true" size="120" display="checkboxes" optional="true">\n+    </param>\n+    <param name="subjectids" type="text" optional="true" size="120" value = ""\n+       label="IF SUBJECTS NOT ALL INDEPENDENT! Enter integers to indicate sample pairing for every column in input"\n+       help="Leave blank if no pairing, but eg if data from sample id A99 is in columns 2,4 and id C21 is in 3,5 then enter \'1,2,1,2\'">\n+      <sanitizer>\n+        <valid initial="string.digits"><add value="," /> </valid>\n+      </sanitizer>\n+    </param>\n+    <param name="fQ" type="float" value="0.3" size="5" label="Non-differential contig count quantile threshold - zero to analyze all non-zero read count contigs"\n+     help="May be a good or a bad idea depending on the biology and the question. EG 0.3 = sparsest 30% of contigs with at least one read are removed before analysis"/>\n+    <param name="useNDF" type="boolean" truevalue="T" falsevalue="F" checked="false" size="1" \n+              label="Non differential filter - remove contigs below a threshold (1 per million) for half or more samples"\n+     help="May be a good or a bad idea depending on the biology and the question. This was the old default. Quantile based is available as an alternative"/>\n+    <conditional name="DESeq">\n+    <param name="doDESeq" type="select" \n+       label="Run the same model with DESeq2 and compare findings"\n+       help="DESeq2 is an update to the DESeq package. It uses different assumptions and methods to edgeR">\n+      <option value="F" selected="true">Do not run DESeq2</option>\n+      <option value="T">Run DESeq2 (only works if NO second GLM factor supplied at present)</option>\n+     </param>\n+     <when value="T">\n+         <param name="DESeq_fitType" type="select">\n+            <option value="parametric" selected="true">Parametric (default) fit for dispersions</option>\n+            <option value="local">Local fit - use this if parametric fails</option>\n+            <option value="mean">Mean dispersion fit- use this if you really understand what you\'re doing - read the fine manual</option>\n+         </param> \n+     </when>\n+     <when va'..b'if you have 2 pairs out of 6 samples, you need to put in unique integers for the unpaired ones\n+eg if you had 6 samples with the first two independent but the second and third pairs each being from independent subjects. you might use\n+8,9,1,1,2,2 \n+as subject IDs to indicate two paired samples from the same subject in columns 3/4 and 5/6\n+\n+**Output**\n+\n+A summary html page with links to the R source code and all the outputs, nice grids of helpful plot thumbnails, and lots\n+of logging and the top 50 rows of the topTable.\n+\n+The main topTables of results are provided as separate excelish tabular files. \n+\n+They include adjusted p values and dispersions for each region, raw and cpm sample data counts and shrunken (predicted) log fold change estimates.\n+These are provided for downstream analyses such as GSEA and are predictions of the logFC you might expect to see \n+in an independent replication of your original experiment. Higher number means more shrinkage. Shrinkage is more extreme for low coverage features \n+so downstream analyses are more robust against strong effect size estimates based on relatively little experimental information.\n+\n+**Note on prior.N**\n+\n+http://seqanswers.com/forums/showthread.php?t=5591 says:\n+\n+*prior.n*\n+\n+The value for prior.n determines the amount of smoothing of tagwise dispersions towards the common dispersion. \n+You can think of it as like a "weight" for the common value. (It is actually the weight for the common likelihood \n+in the weighted likelihood equation). The larger the value for prior.n, the more smoothing, i.e. the closer your \n+tagwise dispersion estimates will be to the common dispersion. If you use a prior.n of 1, then that gives the \n+common likelihood the weight of one observation.\n+\n+In answer to your question, it is a good thing to squeeze the tagwise dispersions towards a common value, \n+or else you will be using very unreliable estimates of the dispersion. I would not recommend using the value that \n+you obtained from estimateSmoothing()---this is far too small and would result in virtually no moderation \n+(squeezing) of the tagwise dispersions. How many samples do you have in your experiment? \n+What is the experimental design? If you have few samples (less than 6) then I would suggest a prior.n of at least 10. \n+If you have more samples, then the tagwise dispersion estimates will be more reliable, \n+so you could consider using a smaller prior.n, although I would hesitate to use a prior.n less than 5. \n+\n+\n+From Bioconductor Digest, Vol 118, Issue 5, Gordon writes:\n+\n+Dear Dorota,\n+\n+The important settings are prior.df and trend.\n+\n+prior.n and prior.df are related through prior.df = prior.n * residual.df,\n+and your experiment has residual.df = 36 - 12 = 24.  So the old setting of\n+prior.n=10 is equivalent for your data to prior.df = 240, a very large\n+value.  Going the other way, the new setting of prior.df=10 is equivalent\n+to prior.n=10/24.\n+\n+To recover old results with the current software you would use\n+\n+  estimateTagwiseDisp(object, prior.df=240, trend="none")\n+\n+To get the new default from old software you would use\n+\n+  estimateTagwiseDisp(object, prior.n=10/24, trend=TRUE)\n+\n+Actually the old trend method is equivalent to trend="loess" in the new\n+software. You should use plotBCV(object) to see whether a trend is\n+required.\n+\n+Note you could also use\n+\n+  prior.n = getPriorN(object, prior.df=10)\n+\n+to map between prior.df and prior.n.\n+\n+** Old rant on variable name changes in bioconductor versions**\n+\n+BioC authors sometimes make small mostly cosmetic changes to variable names (eg: from p.value to PValue) \n+often to make them more internally consistent or self describing. Unfortunately, these improvements\n+break existing code in ways that can take a while to track down that relies on the library in ways that can take a while to track down, \n+increasing downstream tool maintenance effort uselessly.\n+\n+Please, don\'t do that. It hurts us.\n+\n+\n+</help>\n+\n+</tool>\n+\n+\n'
b
diff -r ca60c96f0beb -r c6fdf2c6d0f4 rgToolFactoryMultIn.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rgToolFactoryMultIn.py Thu Aug 28 02:33:05 2014 -0400
[
b'@@ -0,0 +1,736 @@\n+# rgToolFactoryMultIn.py\n+# see https://bitbucket.org/fubar/galaxytoolfactory/wiki/Home\n+# \n+# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012\n+# \n+# all rights reserved\n+# Licensed under the LGPL\n+# suggestions for improvement and bug fixes welcome at https://bitbucket.org/fubar/galaxytoolfactory/wiki/Home\n+#\n+# august 2014\n+# Allows arbitrary number of input files\n+# NOTE positional parameters are now passed to script\n+# and output (may be "None") is *before* arbitrary number of inputs\n+#\n+# march 2014\n+# had to remove dependencies because cross toolshed dependencies are not possible - can\'t pre-specify a toolshed url for graphicsmagick and ghostscript\n+# grrrrr - night before a demo\n+# added dependencies to a tool_dependencies.xml if html page generated so generated tool is properly portable\n+#\n+# added ghostscript and graphicsmagick as dependencies \n+# fixed a wierd problem where gs was trying to use the new_files_path from universe (database/tmp) as ./database/tmp\n+# errors ensued\n+#\n+# august 2013\n+# found a problem with GS if $TMP or $TEMP missing - now inject /tmp and warn\n+#\n+# july 2013\n+# added ability to combine images and individual log files into html output\n+# just make sure there\'s a log file foo.log and it will be output\n+# together with all images named like "foo_*.pdf\n+# otherwise old format for html\n+#\n+# January 2013\n+# problem pointed out by Carlos Borroto\n+# added escaping for <>$ - thought I did that ages ago...\n+#\n+# August 11 2012 \n+# changed to use shell=False and cl as a sequence\n+\n+# This is a Galaxy tool factory for simple scripts in python, R or whatever ails ye.\n+# It also serves as the wrapper for the new tool.\n+# \n+# you paste and run your script\n+# Only works for simple scripts that read one input from the history.\n+# Optionally can write one new history dataset,\n+# and optionally collect any number of outputs into links on an autogenerated HTML page.\n+\n+# DO NOT install on a public or important site - please.\n+\n+# installed generated tools are fine if the script is safe.\n+# They just run normally and their user cannot do anything unusually insecure\n+# but please, practice safe toolshed.\n+# Read the fucking code before you install any tool \n+# especially this one\n+\n+# After you get the script working on some test data, you can\n+# optionally generate a toolshed compatible gzip file\n+# containing your script safely wrapped as an ordinary Galaxy script in your local toolshed for\n+# safe and largely automated installation in a production Galaxy.\n+\n+# If you opt for an HTML output, you get all the script outputs arranged\n+# as a single Html history item - all output files are linked, thumbnails for all the pdfs.\n+# Ugly but really inexpensive.\n+# \n+# Patches appreciated please. \n+#\n+#\n+# long route to June 2012 product\n+# Behold the awesome power of Galaxy and the toolshed with the tool factory to bind them\n+# derived from an integrated script model  \n+# called rgBaseScriptWrapper.py\n+# Note to the unwary:\n+#   This tool allows arbitrary scripting on your Galaxy as the Galaxy user\n+#   There is nothing stopping a malicious user doing whatever they choose\n+#   Extremely dangerous!!\n+#   Totally insecure. So, trusted users only\n+#\n+# preferred model is a developer using their throw away workstation instance - ie a private site.\n+# no real risk. The universe_wsgi.ini admin_users string is checked - only admin users are permitted to run this tool.\n+#\n+\n+import sys \n+import shutil \n+import subprocess \n+import os \n+import time \n+import tempfile \n+import optparse\n+import tarfile\n+import re\n+import shutil\n+import math\n+\n+progname = os.path.split(sys.argv[0])[1] \n+myversion = \'V001.1 March 2014\' \n+verbose = False \n+debug = False\n+toolFactoryURL = \'https://bitbucket.org/fubar/galaxytoolfactory\'\n+\n+# if we do html we need these dependencies specified in a tool_dependencies.xml file and referred to in the generated\n+# tool xml\n+toolhtmldepskel = """<?xml version="1.0"'..b'  htmlf = file(self.opts.output_html,\'w\')\n+        htmlf.write(\'\\n\'.join(html))\n+        htmlf.write(\'\\n\')\n+        htmlf.close()\n+        self.html = html\n+\n+\n+    def run(self):\n+        """\n+        scripts must be small enough not to fill the pipe!\n+        """\n+        if self.treatbashSpecial and self.opts.interpreter in [\'bash\',\'sh\']:\n+          retval = self.runBash()\n+        else:\n+            if self.opts.output_dir:\n+                ste = open(self.elog,\'w\')\n+                sto = open(self.tlog,\'w\')\n+                sto.write(\'## Toolfactory generated command line = %s\\n\' % \' \'.join(self.cl))\n+                sto.flush()\n+                p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=ste,stdin=subprocess.PIPE,cwd=self.opts.output_dir)\n+            else:\n+                p = subprocess.Popen(self.cl,shell=False,stdin=subprocess.PIPE)\n+            p.stdin.write(self.script)\n+            p.stdin.close()\n+            retval = p.wait()\n+            if self.opts.output_dir:\n+                sto.close()\n+                ste.close()\n+                err = open(self.elog,\'r\').readlines()\n+                if retval <> 0 and err: # problem\n+                    print >> sys.stderr,err\n+            if self.opts.make_HTML:\n+                self.makeHtml()\n+        return retval\n+\n+    def runBash(self):\n+        """\n+        cannot use - for bash so use self.sfile\n+        """\n+        if self.opts.output_dir:\n+            s = \'## Toolfactory generated command line = %s\\n\' % \' \'.join(self.cl)\n+            sto = open(self.tlog,\'w\')\n+            sto.write(s)\n+            sto.flush()\n+            p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,cwd=self.opts.output_dir)\n+        else:\n+            p = subprocess.Popen(self.cl,shell=False)            \n+        retval = p.wait()\n+        if self.opts.output_dir:\n+            sto.close()\n+        if self.opts.make_HTML:\n+            self.makeHtml()\n+        return retval\n+  \n+\n+def main():\n+    u = """\n+    This is a Galaxy wrapper. It expects to be called by a special purpose tool.xml as:\n+    <command interpreter="python">rgBaseScriptWrapper.py --script_path "$scriptPath" --tool_name "foo" --interpreter "Rscript"\n+    </command>\n+    """\n+    op = optparse.OptionParser()\n+    a = op.add_option\n+    a(\'--script_path\',default=None)\n+    a(\'--tool_name\',default=None)\n+    a(\'--interpreter\',default=None)\n+    a(\'--output_dir\',default=\'./\')\n+    a(\'--output_html\',default=None)\n+    a(\'--input_tab\',default=[], action="append")    \n+    a("--input_formats",default="tabular")\n+    a(\'--output_tab\',default="None")\n+    a(\'--output_format\',default=\'tabular\')\n+    a(\'--user_email\',default=\'Unknown\')\n+    a(\'--bad_user\',default=None)\n+    a(\'--make_Tool\',default=None)\n+    a(\'--make_HTML\',default=None)\n+    a(\'--help_text\',default=None)\n+    a(\'--tool_desc\',default=None)\n+    a(\'--new_tool\',default=None)\n+    a(\'--tool_version\',default=None)\n+    a(\'--include_dependencies\',default=None)   \n+    opts, args = op.parse_args()\n+    assert not opts.bad_user,\'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to admin_users in universe_wsgi.ini\' % (opts.bad_user,opts.bad_user)\n+    assert opts.tool_name,\'## Tool Factory expects a tool name - eg --tool_name=DESeq\'\n+    assert opts.interpreter,\'## Tool Factory wrapper expects an interpreter - eg --interpreter=Rscript\'\n+    assert os.path.isfile(opts.script_path),\'## Tool Factory wrapper expects a script path - eg --script_path=foo.R\'\n+    if opts.output_dir:\n+        try:\n+            os.makedirs(opts.output_dir)\n+        except:\n+            pass\n+    opts.input_tab = [x.replace(\'"\',\'\').replace("\'",\'\') for x in opts.input_tab]\n+    r = ScriptRunner(opts)\n+    if opts.make_Tool:\n+        retcode = r.makeTooltar()\n+    else:\n+        retcode = r.run()\n+    os.unlink(r.sfile)\n+    if retcode:\n+        sys.exit(retcode) # indicate failure to job runner\n+\n+\n+if __name__ == "__main__":\n+    main()\n+\n+\n'
b
diff -r ca60c96f0beb -r c6fdf2c6d0f4 rgToolFactoryMultIn.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rgToolFactoryMultIn.xml Thu Aug 28 02:33:05 2014 -0400
[
b'@@ -0,0 +1,343 @@\n+<tool id="rgTFM" name="Tool Factory Multiple Inputs" version="1.12">\n+  <description>Makes scripts into tools</description>\n+   <requirements>\n+      <requirement type="package" version="9.10">ghostscript</requirement>\n+      <requirement type="package" version="1.3.18">graphicsmagick</requirement>\n+  </requirements>\n+  <command interpreter="python">\n+#if ( $__user_email__ not in $__admin_users__ ):\n+     rgToolFactoryMultIn.py --bad_user $__user_email__\n+#else:\n+    rgToolFactoryMultIn.py --script_path "$runme" --interpreter "$interpreter" \n+     --tool_name "$tool_name"  --user_email "$__user_email__"\n+    #if $make_TAB.value=="yes":\n+          --output_tab "$output1"\n+          --output_format "$output_format"\n+    #end if\n+    #if $makeMode.make_Tool=="yes":\n+      --make_Tool "$makeMode.make_Tool"\n+      --tool_desc "$makeMode.tool_desc"\n+      --tool_version "$makeMode.tool_version"\n+      --new_tool "$new_tool"\n+      --help_text "$helpme"\n+      #if $make_HTML.value=="yes":\n+          #if $makeMode.include_deps.value=="yes":\n+             --include_dependencies "yes"\n+          #end if\n+      #end if\n+    #end if\n+    #if $make_HTML.value=="yes":\n+      --output_dir "$html_file.files_path" --output_html "$html_file" --make_HTML "yes"\n+    #else:\n+       --output_dir "."\n+    #end if\n+    #if $input1 != \'None\':\n+        --input_formats "$input_formats"\n+        #for intab in $input1:\n+          #if $add_names.value == "yes":\n+              --input_tab "$intab,$intab.name"\n+          #else:\n+              --input_tab "$intab"\n+          #end if\n+        #end for\n+        --input_formats = "$input_formats"\n+    #end if\n+#end if \n+  </command>\n+  <inputs>\n+    <param name="input1"  type="data"  label="Select an input file from your history" optional="true" size="120" multiple="true"\n+       help="Use the multiple input widget (above/right of input box) for multiple inputs - your script MUST be ready to parse the command line right - see samples below"/>\n+    <param name="input_formats" type="text" value="tabular" label="Select allowable Galaxy input formats for your inputs passed to your script - default is tabular"\n+         help="Multiple input formats are allowed as a comma separated list (eg \'tabular,txt\'), but your script must be able to deal with whatever is passed in!">\n+        <sanitizer invalid_char="">\n+            <valid initial="string.letters">\n+                <add value=","/>\n+                <add value=" "/>\n+            </valid>\n+        </sanitizer>\n+    </param>\n+    <param name="add_names" type="select" label="Pass input file(s) as path,name - useful if you need the user supplied Galaxy name for your data sets" \n+         help="Your script is responsible for parsing and dealing with these comma separated values!">\n+        <option value="yes">Pass inputs as comma separated path,name values on the script command line</option>\n+        <option value="" selected="true">Pass input parameters as path only - do not include the user supplied name</option>\n+    </param>\n+    <param name="tool_name" type="text" value="My dynamic script"   label="New tool ID and title for outputs" size="60"\n+         help="This will become the toolshed repository name so please choose thoughtfully to avoid namespace clashes with other tool writers">\n+        <sanitizer invalid_char="">\n+            <valid initial="string.letters,string.digits">\n+                <add value="_"/>\n+            </valid>\n+        </sanitizer>\n+    </param>\n+    <conditional name="makeMode">\n+        <param name="make_Tool" type="select" label="Create a tar.gz file ready for local toolshed entry" help="Ready to deploy securely!" size="60">\n+        <option value="yes">Generate a Galaxy ToolShed compatible toolshed.gz</option>\n+        <option value="" selected="true">No. Just run the script please</option>\n+        </param>\n+        <when value = "yes">\n+            <param name="tool_version" label="Tool Version - bump this to warn'..b'justed p value from a column of p values - for this script to be useful, it needs the right column for the input to be specified in the code for the\n+given input file type(s) specified when the tool is generated ::\n+\n+ # use p.adjust - assumes a HEADER row and column 1 - please fix for any real use\n+ column = 1 # adjust if necessary for some other kind of input\n+ ourargs = commandArgs(TRUE)\n+ inf = ourargs[1]\n+ outf = ourargs[2]\n+ inp = read.table(inf,head=T,row.names=NULL,sep=\'\\t\')\n+ p = inp[,column]\n+ q = p.adjust(p,method=\'BH\')\n+ outp = cbind(inp,\'BH Adjusted p-value\'=q)\n+ write.table(outp,outf, quote=FALSE, sep="\\t",row.names=F,col.names=T) \n+\n+\n+A demonstration Rscript example takes no input file but generates some random data based pdf images\n+You must make sure the option to create an HTML output file is\n+turned on for this to work. Images (pdf) are linked via thumbnails and\n+all files have a link on the resulting HTML page::\n+\n+ # note this script takes NO input or output because it generates random data\n+ for (i in 1:10) {\n+    foo = runif(100)\n+    bar = rnorm(100)\n+    bar = foo + 0.05*bar\n+    pdf(paste(\'yet\',i,"anotherplot.pdf",sep=\'_\'))\n+    plot(foo,bar,main=paste("Foo by Bar plot #",i),col="maroon", pch=3,cex=0.6)\n+    dev.off()\n+    foo = data.frame(a=runif(100),b=runif(100),c=runif(100),d=runif(100),e=runif(100),f=runif(100))\n+    bar = as.matrix(foo)\n+    pdf(paste(\'yet\',i,"anotherheatmap.pdf",sep=\'_\'))\n+    heatmap(bar,main=\'Random Heatmap\')\n+    dev.off()\n+ }\n+\n+A slight variation taking an input tabular file from which we read the first number as nreps\n+\n+# note this script takes a single parameter\n+# number of replicates\n+ourargs = commandArgs(TRUE)\n+infname = ourargs[1]\n+nreps = read.table(infname,head=F)\n+nreps = unlist(nreps)[1]\n+nreps = max(c(1,nreps))\n+nreps = min(c(20,nreps))\n+print(paste("Using nreps=",nreps))\n+for (i in 1:nreps) {\n+   foo = runif(100)\n+   bar = rnorm(100)\n+   bar = foo + 0.2*bar\n+   pdf(paste("yet",i,"anotherplot.pdf",sep="_"))\n+   plot(foo,bar,main=paste("Foo by Bar plot ",i),col="maroon", pch=3,cex=0.6)\n+   dev.off()\n+   foo = data.frame(a=runif(100),b=runif(100),c=runif(100),d=runif(100),e=runif(100),f=runif(100))\n+   bar = as.matrix(foo)\n+   pdf(paste("yet",i,"anotherheatmap.pdf",sep="_"))\n+   heatmap(bar,main="Random Heatmap")\n+   dev.off()\n+}\n+\n+A Python example that reverses each row of a tabular file (you\'ll need to remove the leading spaces \n+for this to work if cut and pasted into the script box)::\n+\n+ # reverse order of columns in a tabular file\n+ import sys\n+ inp = sys.argv[1]\n+ outp = sys.argv[2]\n+ i = open(inp,\'r\')\n+ o = open(outp,\'w\')\n+ for row in i:\n+     rs = row.rstrip().split(\'\\t\')\n+     rs.reverse()\n+     o.write(\'\\t\'.join(rs))\n+     o.write(\'\\n\')\n+ i.close()\n+ o.close()\n+ \n+A trivial shell script example to show that it works::\n+\n+ #!/bin/bash\n+ INF=$1\n+ OUTF=$2\n+ cut -c2,4,6,8,10,12 $INF > $OUTF \n+\n+A trivial perl script example to show that even perl works::\n+\n+ #\n+ # change all occurances of a string in a file to another string\n+ #\n+ $oldfile = $ARGV[0];\n+ $newfile = $ARGV[1];\n+ $old = "gene";\n+ $new = "foo";\n+ open(OF, $oldfile);\n+ open(NF, ">$newfile");\n+ # read in each line of the file\n+ while ($line = <OF>) {\n+    $line =~ s/$old/$new/;\n+    print NF $line;\n+ }\n+ close(OF);\n+ close(NF);\n+\n+]]>\n+\n+**Citation**\n+\n+\n+Paper_ :\n+\n+Creating re-usable tools from scripts: The Galaxy Tool Factory\n+Ross Lazarus; Antony Kaspi; Mark Ziemann; The Galaxy Team\n+Bioinformatics 2012; doi: 10.1093/bioinformatics/bts573\n+\n+\n+**Licensing** \n+\n+Copyright Ross Lazarus (ross period lazarus at gmail period com) May 2012\n+All rights reserved.\n+Licensed under the LGPL_\n+\n+.. _LGPL: http://www.gnu.org/copyleft/lesser.html\n+.. _GTF:  https://bitbucket.org/fubar/galaxytoolfactory\n+.. _GTFI:  https://bitbucket.org/fubar/galaxytoolfactory/issues\n+.. _Paper: http://bioinformatics.oxfordjournals.org/cgi/reprint/bts573?ijkey=lczQh1sWrMwdYWJ&amp;keytype=ref\n+\n+\n+</help>\n+\n+</tool>\n+\n+\n'