# HG changeset patch # User fubar # Date 1708598881 0 # Node ID 0183cad9d13be1acb94da25cd4d1a050f0a8450d # Parent 2beaae16651e96d48555d805134bd9da51b6c757 planemo upload diff -r 2beaae16651e -r 0183cad9d13b abslen_bed/abslen_bed.python.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/abslen_bed/abslen_bed.python.txt Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,14 @@ +#raw +import sys +inp = [] +for line in sys.stdin: + if line.strip() > '': + ls = line.split() + if len(ls) > 2: + x = abs(int(ls[2]) - int(ls[1])) + ls.append((str(x))) + inp.append('\t'.join(ls)) + else: + break +sys.stdout.write('\n'.join(inp)) +#end raw diff -r 2beaae16651e -r 0183cad9d13b abslen_bed/abslen_bed.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/abslen_bed/abslen_bed.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,56 @@ + + + + Returns a file of absolute values from differences + + python + + + +$absout]]> + + '': + ls = line.split() + if len(ls) > 2: + x = abs(int(ls[2]) - int(ls[1])) + ls.append((str(x))) + inp.append('\t'.join(ls)) + else: + break +sys.stdout.write('\n'.join(inp)) +#end raw]]> + + + + + + + + + + + + + + + 10.1093/bioinformatics/bts573 + + + diff -r 2beaae16651e -r 0183cad9d13b abslen_bed/test-data/absin_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/abslen_bed/test-data/absin_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,4 @@ +mm10_knownGene_uc008xda.1 900 959 +mm10_knownGene_uc008xda.1 1009 1038 +mm10_knownGene_uc008xda.1 1088 1166 +mm10_knownGene_uc008xda.1 1216 1252 diff -r 2beaae16651e -r 0183cad9d13b abslen_bed/test-data/absout_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/abslen_bed/test-data/absout_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,4 @@ +mm10_knownGene_uc008xda.1 900 959 59 +mm10_knownGene_uc008xda.1 1009 1038 29 +mm10_knownGene_uc008xda.1 1088 1166 78 +mm10_knownGene_uc008xda.1 1216 1252 36 \ No newline at end of file diff -r 2beaae16651e -r 0183cad9d13b hictk/hictk.bash.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hictk/hictk.bash.txt Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1 @@ +hictk convert -f --output-fmt 'hic' '$incool' '$outhic' diff -r 2beaae16651e -r 0183cad9d13b hictk/hictk.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hictk/hictk.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,70 @@ + + + + cool to hic binary + + hictk + + + + + + + + + + + + + + + + + + + + License: MIT + + **hictk** + + ---- + + hictk is a blazing fast toolkit to work with .hic and .cool files. + + This repository hosts `hictk`: a set of CLI tools to work with Cooler, as well as `libhictk`: the C++ library underlying `hictk`. + + Python bindings for `libhictk` are available at https://github.com/paulsengroup/hictkpy. + + hictk is capable of reading files in `.cool`, `.mcool`, `.scool` and `.juicebox_hic` format (including hic v9) as well as writing `.cool` and `.mcool` files. + + **Installing hictk** + + hictk is developed on Linux and tested on Linux, MacOS and Windows. + + hictk can be installed using containers, bioconda or directly from source. + Refer to https://hictk.readthedocs.io/en/latest/installation.html for more information. + + **Running hictk** + + hictk provides the following subcommands but this tool implements only *convert* + + Refer to https://hictk.readthedocs.io/en/latest/cli_reference.html for more details. + + ]]> + + @article{hictk, +author = {Roberto Rossini}, +year = {2023}, +url = {https://github.com/paulsengroup/hictk}, +title = {hictk: blazing fast toolkit to work with .hic and .cool files} +} + 10.1093/bioinformatics/bts573 + + + diff -r 2beaae16651e -r 0183cad9d13b hictk/test-data/incool_sample Binary file hictk/test-data/incool_sample has changed diff -r 2beaae16651e -r 0183cad9d13b hictk/test-data/outhic_sample Binary file hictk/test-data/outhic_sample has changed diff -r 2beaae16651e -r 0183cad9d13b jb2.tar.gz Binary file jb2.tar.gz has changed diff -r 2beaae16651e -r 0183cad9d13b local_tool_conf.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/local_tool_conf.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,14 @@ + +
+ + + + + + + + + + +
+
diff -r 2beaae16651e -r 0183cad9d13b mashmap.tgz Binary file mashmap.tgz has changed diff -r 2beaae16651e -r 0183cad9d13b mashmap/.shed.yml --- a/mashmap/.shed.yml Thu Feb 22 07:24:04 2024 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -category: ToolFactory generated Tools -description: ToolFactory autogenerated tool -name: mashmap -owner: fubar2 -synopsis: Fast local alignment boundaries -type: unrestricted diff -r 2beaae16651e -r 0183cad9d13b mashmap/mashmap.xml --- a/mashmap/mashmap.xml Thu Feb 22 07:24:04 2024 +0000 +++ b/mashmap/mashmap.xml Thu Feb 22 10:48:01 2024 +0000 @@ -1,6 +1,6 @@ - + Fast local alignment boundaries mashmap @@ -16,19 +16,19 @@ --dense \ #end if #if len($reflist) == 1: - -r $reflist -q '$query' + -r '$reflist' -q '$query' #else rm -rf 'reflist' #for i, mash in enumerate($reflist): #if i == 0: - echo $mash > 'reflist' + echo '$mash' > 'reflist' #else: - echo $mash >> 'reflist' + echo '$mash' >> 'reflist' #end if #end for --rl 'reflist' -q '$query' #end if -cp 'mashmap.out' $mashout]]> +cp 'mashmap.out' '$mashout']]> diff -r 2beaae16651e -r 0183cad9d13b planemo_lint/planemo_lint.bash.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/planemo_lint/planemo_lint.bash.txt Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,7 @@ +#raw +cp $1 foo.tar +tar -xvf foo.tar +TOOLNAME=`find . -name "*.xml"` +echo "$$$$$TOOLNAME = $TOOLNAME" > $2 +planemo lint $TOOLNAME >> $2 +#end raw diff -r 2beaae16651e -r 0183cad9d13b planemo_lint/planemo_lint.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/planemo_lint/planemo_lint.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,41 @@ + + + + + + planemo + + + + + $2 +planemo lint $TOOLNAME >> $2 +#end raw]]> + + + + + + + + + + + + + + + 10.1093/bioinformatics/bts573 + + + diff -r 2beaae16651e -r 0183cad9d13b planemo_lint/test-data/Toolshed_archive_to_be_linted_sample Binary file planemo_lint/test-data/Toolshed_archive_to_be_linted_sample has changed diff -r 2beaae16651e -r 0183cad9d13b planemotest/planemotest.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/planemotest/planemotest.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,77 @@ + + + + Tests a ToolFactory archive containing a new tool + + planemo + + + + + + + + STDOUT +cp $REP $2 + +#end raw]]> + + + + + + + + + + + + + $LOG + planemo test --update_test_data --test_output $REP $TOOLNAME >> $LOG + cp $REP $2 + +]]> + + 10.1093/bioinformatics/bts573 + + + diff -r 2beaae16651e -r 0183cad9d13b planemotest/test-data/Toolshed_archive_to_be_tested_sample Binary file planemotest/test-data/Toolshed_archive_to_be_tested_sample has changed diff -r 2beaae16651e -r 0183cad9d13b planemotest/test-data/test_output_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/planemotest/test-data/test_output_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,291 @@ + + + + + + + Test Results (powered by Planemo) + + + + + + + + + + +
+
+
+
+ + + + + + + \ No newline at end of file diff -r 2beaae16651e -r 0183cad9d13b plants.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plants.sh Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1 @@ +planemo shed_update --shed_target toolshed --owner fubar --name mashmap --shed_key bbfaa3d1d522066d41a4250dc419cc6f ./ diff -r 2beaae16651e -r 0183cad9d13b pyrev_pos_test/pyrev_pos_test.python.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyrev_pos_test/pyrev_pos_test.python.txt Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,17 @@ +#raw +## reverse order of text by row +## ToolFactory demonstration +## positional parameters +import sys +inp = sys.argv[1] +outp = sys.argv[2] +i = open(inp,'r').readlines() +o = open(outp,'w') +for row in i: + rs = row.rstrip() + rs = list(rs) + rs.reverse() + o.write(''.join(rs)) + o.write('\n') +o.close() +#end raw diff -r 2beaae16651e -r 0183cad9d13b pyrev_pos_test/pyrev_pos_test.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyrev_pos_test/pyrev_pos_test.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + 10.1093/bioinformatics/bts573 + + + diff -r 2beaae16651e -r 0183cad9d13b pyrev_pos_test/test-data/Input_text_file_to_be_reversed_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyrev_pos_test/test-data/Input_text_file_to_be_reversed_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1210 @@ +# see https://github.com/fubar2/toolfactory +# +# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012 +# +# all rights reserved +# Licensed under the LGPL +# suggestions for improvement and bug fixes welcome at +# https://github.com/fubar2/toolfactory +# +# march 2022: Refactored into two tools - generate and test/install +# as part of GTN tutorial development and biocontainer adoption +# The tester runs planemo on a non-tested archive, creates the test outputs +# and returns a new proper tool with test. + + + +import argparse +import copy +import fcntl +import json +import os +import re +import shlex +import shutil +import subprocess +import sys +import tarfile +import tempfile +import time + +from bioblend import galaxy + +import galaxyxml.tool as gxt +import galaxyxml.tool.parameters as gxtp + +import lxml.etree as ET + +import yaml + +myversion = "V2.4 March 2022" +verbose = True +debug = True +toolFactoryURL = "https://github.com/fubar2/toolfactory" +FAKEEXE = "~~~REMOVE~~~ME~~~" +# need this until a PR/version bump to fix galaxyxml prepending the exe even +# with override. + + +def timenow(): + """return current time as a string""" + return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) + + +cheetah_escape_table = {"$": "\\$", "#": "\\#"} + + +def cheetah_escape(text): + """Produce entities within text.""" + return "".join([cheetah_escape_table.get(c, c) for c in text]) + + +def parse_citations(citations_text): + """""" + citations = [c for c in citations_text.split("**ENTRY**") if c.strip()] + citation_tuples = [] + for citation in citations: + if citation.startswith("doi"): + citation_tuples.append(("doi", citation[len("doi") :].strip())) + else: + citation_tuples.append(("bibtex", citation[len("bibtex") :].strip())) + return citation_tuples + + +class Tool_Factory: + """Wrapper for an arbitrary script + uses galaxyxml + + """ + + def __init__(self, args=None): # noqa + """ + prepare command line cl for running the tool here + and prepare elements needed for galaxyxml tool generation + """ + self.local_tools = os.path.join(args.galaxy_root,'local_tools') + self.ourcwd = os.getcwd() + self.collections = [] + if len(args.collection) > 0: + try: + self.collections = [ + json.loads(x) for x in args.collection if len(x.strip()) > 1 + ] + except Exception: + print( + f"--collections parameter {str(args.collection)} is malformed - should be a dictionary" + ) + try: + self.infiles = [ + json.loads(x) for x in args.input_files if len(x.strip()) > 1 + ] + except Exception: + print( + f"--input_files parameter {str(args.input_files)} is malformed - should be a dictionary" + ) + try: + self.outfiles = [ + json.loads(x) for x in args.output_files if len(x.strip()) > 1 + ] + except Exception: + print( + f"--output_files parameter {args.output_files} is malformed - should be a dictionary" + ) + assert (len(self.outfiles) + len(self.collections)) > 0, 'No outfiles or output collections specified. The Galaxy job runner will fail without an output of some sort' + try: + self.addpar = [ + json.loads(x) for x in args.additional_parameters if len(x.strip()) > 1 + ] + except Exception: + print( + f"--additional_parameters {args.additional_parameters} is malformed - should be a dictionary" + ) + try: + self.selpar = [ + json.loads(x) for x in args.selecttext_parameters if len(x.strip()) > 1 + ] + except Exception: + print( + f"--selecttext_parameters {args.selecttext_parameters} is malformed - should be a dictionary" + ) + self.args = args + self.cleanuppar() + self.lastxclredirect = None + self.xmlcl = [] + self.is_positional = self.args.parampass == "positional" + if self.args.sysexe: + if " " in self.args.sysexe: + self.executeme = shlex.split(self.args.sysexe) + else: + self.executeme = [ + self.args.sysexe, + ] + else: + if self.args.packages: + self.executeme = [ + self.args.packages.split(",")[0].split(":")[0].strip(), + ] + else: + self.executeme = None + aXCL = self.xmlcl.append + assert args.parampass in [ + "0", + "argparse", + "positional", + ], 'args.parampass must be "0","positional" or "argparse"' + self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name) + self.tool_id = self.tool_name + self.newtool = gxt.Tool( + self.tool_name, + self.tool_id, + self.args.tool_version, + self.args.tool_desc, + FAKEEXE, + ) + self.tooloutdir = "./tfout" + self.repdir = "./toolgen" + self.newtarpath = args.untested_tool_out # os.path.join(self.tooloutdir, "%s_not_tested_toolshed.gz" % self.tool_name) + self.testdir = os.path.join(self.tooloutdir, "test-data") + if not os.path.exists(self.tooloutdir): + os.mkdir(self.tooloutdir) + if not os.path.exists(self.testdir): + os.mkdir(self.testdir) + if not os.path.exists(self.repdir): + os.mkdir(self.repdir) + self.tlog = os.path.join(self.repdir,'%s_TF_run_log.txt' % self.tool_name) + self.tinputs = gxtp.Inputs() + self.toutputs = gxtp.Outputs() + self.testparam = [] + if self.args.script_path: + self.prepScript() + if self.args.command_override: + scos = open(self.args.command_override, "r").readlines() + self.command_override = [x.rstrip() for x in scos] + else: + self.command_override = None + if self.args.test_override: + stos = open(self.args.test_override, "r").readlines() + self.test_override = [x.rstrip() for x in stos] + else: + self.test_override = None + if self.args.script_path: + for ex in self.executeme: + aXCL(ex) + aXCL("$runme") + else: + for ex in self.executeme: + aXCL(ex) + + if self.args.parampass == "0": + self.clsimple() + else: + if self.args.parampass == "positional": + self.prepclpos() + self.clpositional() + else: + self.prepargp() + self.clargparse() + + def clsimple(self): + """no parameters or repeats - uses < and > for i/o""" + aXCL = self.xmlcl.append + if len(self.infiles) > 0: + aXCL("<") + aXCL("$%s" % self.infiles[0]["infilename"]) + if len(self.outfiles) > 0: + aXCL(">") + aXCL("$%s" % self.outfiles[0]["name"]) + if self.args.cl_user_suffix: # DIY CL end + clp = shlex.split(self.args.cl_user_suffix) + for c in clp: + aXCL(c) + + def prepargp(self): + xclsuffix = [] + for i, p in enumerate(self.infiles): + nam = p["infilename"] + if p["origCL"].strip().upper() == "STDIN": + xappendme = [ + nam, + nam, + "< $%s" % nam, + ] + else: + rep = p["repeat"] == "1" + over = "" + if rep: + over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for' + xappendme = [p["CL"], "$%s" % p["CL"], over] + xclsuffix.append(xappendme) + for i, p in enumerate(self.outfiles): + if p["origCL"].strip().upper() == "STDOUT": + self.lastxclredirect = [">", "$%s" % p["name"]] + else: + xclsuffix.append([p["name"], "$%s" % p["name"], ""]) + for p in self.addpar: + nam = p["name"] + rep = p["repeat"] == "1" + if rep: + over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for' + else: + over = p["override"] + xclsuffix.append([p["CL"], '"$%s"' % nam, over]) + for p in self.selpar: + xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]]) + self.xclsuffix = xclsuffix + + def prepclpos(self): + xclsuffix = [] + for i, p in enumerate(self.infiles): + if p["origCL"].strip().upper() == "STDIN": + xappendme = [ + "999", + p["infilename"], + "< $%s" % p["infilename"], + ] + else: + xappendme = [p["CL"], "$%s" % p["infilename"], ""] + xclsuffix.append(xappendme) + for i, p in enumerate(self.outfiles): + if p["origCL"].strip().upper() == "STDOUT": + self.lastxclredirect = [">", "$%s" % p["name"]] + else: + xclsuffix.append([p["CL"], "$%s" % p["name"], ""]) + for p in self.addpar: + nam = p["name"] + rep = p["repeat"] == "1" # repeats make NO sense + if rep: + print( + f"### warning. Repeats for {nam} ignored - not permitted in positional parameter command lines!" + ) + over = p["override"] + xclsuffix.append([p["CL"], '"$%s"' % nam, over]) + for p in self.selpar: + xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]]) + xclsuffix.sort() + self.xclsuffix = xclsuffix + + def prepScript(self): + rx = open(self.args.script_path, "r").readlines() + rx = [x.rstrip() for x in rx] + rxcheck = [x.strip() for x in rx if x.strip() > ""] + assert len(rxcheck) > 0, "Supplied script is empty. Cannot run" + self.script = "\n".join(rx) + fhandle, self.sfile = tempfile.mkstemp( + prefix=self.tool_name, suffix="_%s" % (self.executeme[0]) + ) + tscript = open(self.sfile, "w") + tscript.write(self.script) + tscript.close() + self.spacedScript = [f" {x}" for x in rx if x.strip() > ""] + rx.insert(0, "#raw") + rx.append("#end raw") + self.escapedScript = rx + art = "%s.%s" % (self.tool_name, self.executeme[0]) + artifact = open(art, "wb") + artifact.write(bytes(self.script, "utf8")) + artifact.close() + + def cleanuppar(self): + """ positional parameters are complicated by their numeric ordinal""" + if self.args.parampass == "positional": + for i, p in enumerate(self.infiles): + assert ( + p["CL"].isdigit() or p["CL"].strip().upper() == "STDIN" + ), "Positional parameters must be ordinal integers - got %s for %s" % ( + p["CL"], + p["label"], + ) + for i, p in enumerate(self.outfiles): + assert ( + p["CL"].isdigit() or p["CL"].strip().upper() == "STDOUT" + ), "Positional parameters must be ordinal integers - got %s for %s" % ( + p["CL"], + p["name"], + ) + for i, p in enumerate(self.addpar): + assert p[ + "CL" + ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % ( + p["CL"], + p["name"], + ) + for i, p in enumerate(self.infiles): + infp = copy.copy(p) + infp["origCL"] = infp["CL"] + if self.args.parampass in ["positional", "0"]: + infp["infilename"] = infp["label"].replace(" ", "_") + else: + infp["infilename"] = infp["CL"] + self.infiles[i] = infp + for i, p in enumerate(self.outfiles): + outfp = copy.copy(p) + outfp["origCL"] = outfp["CL"] # keep copy + self.outfiles[i] = outfp + for i, p in enumerate(self.addpar): + addp = copy.copy(p) + addp["origCL"] = addp["CL"] + self.addpar[i] = addp + + def clpositional(self): + # inputs in order then params + aXCL = self.xmlcl.append + for (k, v, koverride) in self.xclsuffix: + aXCL(v) + if self.lastxclredirect: + for cl in self.lastxclredirect: + aXCL(cl) + if self.args.cl_user_suffix: # DIY CL end + clp = shlex.split(self.args.cl_user_suffix) + for c in clp: + aXCL(c) + + def clargparse(self): + """argparse style""" + aXCL = self.xmlcl.append + # inputs then params in argparse named form + + for (k, v, koverride) in self.xclsuffix: + if koverride > "": + k = koverride + aXCL(k) + else: + if len(k.strip()) == 1: + k = "-%s" % k + else: + k = "--%s" % k + aXCL(k) + aXCL(v) + if self.lastxclredirect: + for cl in self.lastxclredirect: + aXCL(cl) + if self.args.cl_user_suffix: # DIY CL end + clp = shlex.split(self.args.cl_user_suffix) + for c in clp: + aXCL(c) + + def getNdash(self, newname): + if self.is_positional: + ndash = 0 + else: + ndash = 2 + if len(newname) < 2: + ndash = 1 + return ndash + + def doXMLparam(self): # noqa + """Add all needed elements to tool""" + for p in self.outfiles: + newname = p["name"] + newfmt = p["format"] + newcl = p["CL"] + test = p["test"] + oldcl = p["origCL"] + test = test.strip() + ndash = self.getNdash(newcl) + aparm = gxtp.OutputData( + name=newname, format=newfmt, num_dashes=ndash, label=newname + ) + aparm.positional = self.is_positional + if self.is_positional: + if oldcl.upper() == "STDOUT": + aparm.positional = 9999999 + aparm.command_line_override = "> $%s" % newname + else: + aparm.positional = int(oldcl) + aparm.command_line_override = "$%s" % newname + self.toutputs.append(aparm) + ld = None + if test.strip() > "": + if test.strip().startswith("diff"): + c = "diff" + ld = 0 + if test.split(":")[1].isdigit: + ld = int(test.split(":")[1]) + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + lines_diff=ld, + ) + elif test.startswith("sim_size"): + c = "sim_size" + tn = test.split(":")[1].strip() + if tn > "": + if "." in tn: + delta = None + delta_frac = min(1.0, float(tn)) + else: + delta = int(tn) + delta_frac = None + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + delta=delta, + delta_frac=delta_frac, + ) + else: + c = test + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + ) + self.testparam.append(tp) + for p in self.infiles: + newname = p["infilename"] + newfmt = p["format"] + ndash = self.getNdash(newname) + reps = p.get("repeat", "0") == "1" + if not len(p["label"]) > 0: + alab = p["CL"] + else: + alab = p["label"] + aninput = gxtp.DataParam( + newname, + optional=False, + label=alab, + help=p["help"], + format=newfmt, + multiple=False, + num_dashes=ndash, + ) + aninput.positional = self.is_positional + if self.is_positional: + if p["origCL"].upper() == "STDIN": + aninput.positional = 9999998 + aninput.command_line_override = "< $%s" % newname + else: + aninput.positional = int(p["origCL"]) + aninput.command_line_override = "$%s" % newname + if reps: + repe = gxtp.Repeat( + name=f"R_{newname}", title=f"Add as many {alab} as needed" + ) + repe.append(aninput) + self.tinputs.append(repe) + tparm = gxtp.TestRepeat(name=f"R_{newname}") + tparm2 = gxtp.TestParam(newname, value="%s_sample" % newname) + tparm.append(tparm2) + self.testparam.append(tparm) + else: + self.tinputs.append(aninput) + tparm = gxtp.TestParam(newname, value="%s_sample" % newname) + self.testparam.append(tparm) + for p in self.addpar: + newname = p["name"] + newval = p["value"] + newlabel = p["label"] + newhelp = p["help"] + newtype = p["type"] + newcl = p["CL"] + oldcl = p["origCL"] + reps = p["repeat"] == "1" + if not len(newlabel) > 0: + newlabel = newname + ndash = self.getNdash(newname) + if newtype == "text": + aparm = gxtp.TextParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "integer": + aparm = gxtp.IntegerParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "float": + aparm = gxtp.FloatParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "boolean": + aparm = gxtp.BooleanParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + else: + raise ValueError( + 'Unrecognised parameter type "%s" for\ + additional parameter %s in makeXML' + % (newtype, newname) + ) + aparm.positional = self.is_positional + if self.is_positional: + aparm.positional = int(oldcl) + if reps: + repe = gxtp.Repeat( + name=f"R_{newname}", title=f"Add as many {newlabel} as needed" + ) + repe.append(aparm) + self.tinputs.append(repe) + tparm = gxtp.TestRepeat(name=f"R_{newname}") + tparm2 = gxtp.TestParam(newname, value=newval) + tparm.append(tparm2) + self.testparam.append(tparm) + else: + self.tinputs.append(aparm) + tparm = gxtp.TestParam(newname, value=newval) + self.testparam.append(tparm) + for p in self.selpar: + newname = p["name"] + newval = p["value"] + newlabel = p["label"] + newhelp = p["help"] + newtype = p["type"] + newcl = p["CL"] + if not len(newlabel) > 0: + newlabel = newname + ndash = self.getNdash(newname) + if newtype == "selecttext": + newtext = p["texts"] + aparm = gxtp.SelectParam( + newname, + label=newlabel, + help=newhelp, + num_dashes=ndash, + ) + for i in range(len(newval)): + anopt = gxtp.SelectOption( + value=newval[i], + text=newtext[i], + ) + aparm.append(anopt) + aparm.positional = self.is_positional + if self.is_positional: + aparm.positional = int(newcl) + self.tinputs.append(aparm) + tparm = gxtp.TestParam(newname, value=newval) + self.testparam.append(tparm) + else: + raise ValueError( + 'Unrecognised parameter type "%s" for\ + selecttext parameter %s in makeXML' + % (newtype, newname) + ) + for p in self.collections: + newkind = p["kind"] + newname = p["name"] + newlabel = p["label"] + newdisc = p["discover"] + collect = gxtp.OutputCollection(newname, label=newlabel, type=newkind) + disc = gxtp.DiscoverDatasets( + pattern=newdisc, directory=f"{newname}", visible="false" + ) + collect.append(disc) + self.toutputs.append(collect) + try: + tparm = gxtp.TestOutputCollection(newname) # broken until PR merged. + self.testparam.append(tparm) + except Exception: + print( + "#### WARNING: Galaxyxml version does not have the PR merged yet - tests for collections must be over-ridden until then!" + ) + + def doNoXMLparam(self): + """filter style package - stdin to stdout""" + if len(self.infiles) > 0: + alab = self.infiles[0]["label"] + if len(alab) == 0: + alab = self.infiles[0]["infilename"] + max1s = ( + "Maximum one input if parampass is 0 but multiple input files supplied - %s" + % str(self.infiles) + ) + assert len(self.infiles) == 1, max1s + newname = self.infiles[0]["infilename"] + aninput = gxtp.DataParam( + newname, + optional=False, + label=alab, + help=self.infiles[0]["help"], + format=self.infiles[0]["format"], + multiple=False, + num_dashes=0, + ) + aninput.command_line_override = "< $%s" % newname + aninput.positional = True + self.tinputs.append(aninput) + tp = gxtp.TestParam(name=newname, value="%s_sample" % newname) + self.testparam.append(tp) + if len(self.outfiles) > 0: + newname = self.outfiles[0]["name"] + newfmt = self.outfiles[0]["format"] + anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0) + anout.command_line_override = "> $%s" % newname + anout.positional = self.is_positional + self.toutputs.append(anout) + tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname) + self.testparam.append(tp) + + def makeXML(self): # noqa + """ + Create a Galaxy xml tool wrapper for the new script + Uses galaxyhtml + Hmmm. How to get the command line into correct order... + """ + if self.command_override: + self.newtool.command_override = self.command_override # config file + else: + self.newtool.command_override = self.xmlcl + cite = gxtp.Citations() + acite = gxtp.Citation(type="doi", value="10.1093/bioinformatics/bts573") + cite.append(acite) + self.newtool.citations = cite + safertext = "" + if self.args.help_text: + helptext = open(self.args.help_text, "r").readlines() + safertext = "\n".join([cheetah_escape(x) for x in helptext]) + if len(safertext.strip()) == 0: + safertext = ( + "Ask the tool author (%s) to rebuild with help text please\n" + % (self.args.user_email) + ) + if self.args.script_path: + if len(safertext) > 0: + safertext = safertext + "\n\n------\n" # transition allowed! + scr = [x for x in self.spacedScript if x.strip() > ""] + scr.insert(0, "\n\nScript::\n") + if len(scr) > 300: + scr = ( + scr[:100] + + [" >300 lines - stuff deleted", " ......"] + + scr[-100:] + ) + scr.append("\n") + safertext = safertext + "\n".join(scr) + self.newtool.help = safertext + self.newtool.version_command = f'echo "{self.args.tool_version}"' + std = gxtp.Stdios() + std1 = gxtp.Stdio() + std.append(std1) + self.newtool.stdios = std + requirements = gxtp.Requirements() + self.condaenv = [] + if self.args.packages: + try: + for d in self.args.packages.split(","): + ver = None + packg = None + d = d.replace("==", ":") + d = d.replace("=", ":") + if ":" in d: + packg, ver = d.split(":") + ver = ver.strip() + packg = packg.strip() + else: + packg = d.strip() + ver = None + if ver == "": + ver = None + if packg: + requirements.append( + gxtp.Requirement("package", packg.strip(), ver) + ) + self.condaenv.append(d) + except Exception: + print( + "### malformed packages string supplied - cannot parse =", + self.args.packages, + ) + sys.exit(2) + self.newtool.requirements = requirements + if self.args.parampass == "0": + self.doNoXMLparam() + else: + self.doXMLparam() + self.newtool.outputs = self.toutputs + self.newtool.inputs = self.tinputs + if self.args.script_path: + configfiles = gxtp.Configfiles() + configfiles.append( + gxtp.Configfile(name="runme", text="\n".join(self.escapedScript)) + ) + self.newtool.configfiles = configfiles + tests = gxtp.Tests() + test_a = gxtp.Test() + for tp in self.testparam: + test_a.append(tp) + tests.append(test_a) + self.newtool.tests = tests + self.newtool.add_comment( + "Created by %s at %s using the Galaxy Tool Factory." + % (self.args.user_email, timenow()) + ) + self.newtool.add_comment("Source in git at: %s" % (toolFactoryURL)) + exml0 = self.newtool.export() + exml = exml0.replace(FAKEEXE, "") # temporary work around until PR accepted + if ( + self.test_override + ): # cannot do this inside galaxyxml as it expects lxml objects for tests + part1 = exml.split("")[0] + part2 = exml.split("")[1] + fixed = "%s\n%s\n%s" % (part1, "\n".join(self.test_override), part2) + exml = fixed + with open("%s.xml" % self.tool_name, "w") as xf: + xf.write(exml) + xf.write("\n") + # galaxy history item + + def writeShedyml(self): + """for planemo""" + yuser = self.args.user_email.split("@")[0] + yfname = os.path.join(self.tooloutdir, ".shed.yml") + yamlf = open(yfname, "w") + odict = { + "name": self.tool_name, + "owner": yuser, + "type": "unrestricted", + "description": self.args.tool_desc, + "synopsis": self.args.tool_desc, + "category": "TF Generated Tools", + } + yaml.dump(odict, yamlf, allow_unicode=True) + yamlf.close() + + def makeTool(self): + """write xmls and input samples into place""" + if self.args.parampass == 0: + self.doNoXMLparam() + else: + self.makeXML() + if self.args.script_path: + stname = os.path.join(self.tooloutdir, self.sfile) + if not os.path.exists(stname): + shutil.copyfile(self.sfile, stname) + xreal = "%s.xml" % self.tool_name + xout = os.path.join(self.tooloutdir, xreal) + shutil.copyfile(xreal, xout) + xout = os.path.join(self.repdir, xreal) + shutil.copyfile(xreal, xout) + for p in self.infiles: + pth = p["name"] + dest = os.path.join(self.testdir, "%s_sample" % p["infilename"]) + shutil.copyfile(pth, dest) + dest = os.path.join( + self.repdir, "%s_sample.%s" % (p["infilename"], p["format"]) + ) + shutil.copyfile(pth, dest) + dest = os.path.join(self.local_tools, self.tool_name) + shutil.copytree(self.tooloutdir,dest, dirs_exist_ok=True) + + def makeToolTar(self, report_fail=False): + """move outputs into test-data and prepare the tarball""" + excludeme = "_planemo_test_report.html" + + def exclude_function(tarinfo): + filename = tarinfo.name + return None if filename.endswith(excludeme) else tarinfo + + for p in self.outfiles: + oname = p["name"] + tdest = os.path.join(self.testdir, "%s_sample" % oname) + src = os.path.join(self.testdir, oname) + if not os.path.isfile(tdest): + if os.path.isfile(src): + shutil.copyfile(src, tdest) + dest = os.path.join(self.repdir, "%s.sample.%s" % (oname,p['format'])) + shutil.copyfile(src, dest) + else: + if report_fail: + print( + "###Tool may have failed - output file %s not found in testdir after planemo run %s." + % (tdest, self.testdir) + ) + tf = tarfile.open(self.newtarpath, "w:gz") + tf.add( + name=self.tooloutdir, + arcname=self.tool_name, + filter=exclude_function, + ) + shutil.copy(self.newtarpath, os.path.join(self.tooloutdir, f"{self.tool_name}_untested_toolshed.gz")) + tf.close() + + + def planemo_test_update(self): + """planemo is a requirement so is available for testing + """ + xreal = "%s.xml" % self.tool_name + tool_test_path = os.path.join( + self.repdir, f"{self.tool_name}_planemo_test_report.html" + ) + if os.path.exists(self.tlog): + tout = open(self.tlog, "a") + else: + tout = open(self.tlog, "w") + cll = [ + "planemo", + "test", + "--conda_auto_init", + "--biocontainers", + "--test_data", + os.path.abspath(self.testdir), + "--test_output", + os.path.abspath(tool_test_path), + "--galaxy_root", + self.args.galaxy_root, + "--update_test_data", + os.path.abspath(xreal), + ] + p = subprocess.run( + cll, + shell=False, + cwd=self.tooloutdir, + stderr=tout, + stdout=tout, + ) + tout.close() + return p.returncode + + + def update_toolconf(self ): + + def sortchildrenby(parent, attr): + parent[:] = sorted(parent, key=lambda child: child.get(attr)) + + tcpath = os.path.join(self.args.galaxy_root,'config/local_tool_conf.xml') + xmlfile = os.path.join(self.local_tools, self.tool_name, '%s.xml' % self.tool_name) + parser = ET.XMLParser(remove_blank_text=True) + tree = ET.parse(tcpath, parser) + root = tree.getroot() + hasTF = False + e = root.findall("section") + if len(e) > 0: + hasTF = True + TFsection = e[0] + if not hasTF: + TFsection = ET.Element("section", {"id":"localtools", "name":"Local Tools"}) + root.insert(0, TFsection) # at the top! + our_tools = TFsection.findall("tool") + conf_tools = [x.attrib["file"] for x in our_tools] + if xmlfile not in conf_tools: # new + ET.SubElement(TFsection, "tool", {"file": xmlfile}) + sortchildrenby(TFsection,"file") + tree.write(tcpath, pretty_print=True) + + + + + + + def shedLoad(self): + """ + use bioblend to create new repository + or update existing + + """ + if os.path.exists(self.tlog): + sto = open(self.tlog, "a") + else: + sto = open(self.tlog, "w") + + ts = toolshed.ToolShedInstance( + url=self.args.toolshed_url, + key=self.args.toolshed_api_key, + verify=False, + ) + repos = ts.repositories.get_repositories() + rnames = [x.get("name", "?") for x in repos] + rids = [x.get("id", "?") for x in repos] + tfcat = "ToolFactory generated tools" + if self.tool_name not in rnames: + tscat = ts.categories.get_categories() + cnames = [x.get("name", "?").strip() for x in tscat] + cids = [x.get("id", "?") for x in tscat] + catID = None + if tfcat.strip() in cnames: + ci = cnames.index(tfcat) + catID = cids[ci] + res = ts.repositories.create_repository( + name=self.args.tool_name, + synopsis="Synopsis:%s" % self.args.tool_desc, + description=self.args.tool_desc, + type="unrestricted", + remote_repository_url=self.args.toolshed_url, + homepage_url=None, + category_ids=catID, + ) + tid = res.get("id", None) + sto.write(f"#create_repository {self.args.tool_name} tid={tid} res={res}\n") + else: + i = rnames.index(self.tool_name) + tid = rids[i] + try: + res = ts.repositories.update_repository( + id=tid, tar_ball_path=self.newtarpath, commit_message=None + ) + sto.write(f"#update res id {id} ={res}\n") + except ConnectionError: + sto.write( + "####### Is the toolshed running and the API key correct? Bioblend shed upload failed\n" + ) + sto.close() + + def eph_galaxy_load(self): + """ + use ephemeris to load the new tool from the local toolshed after planemo uploads it + """ + if os.path.exists(self.tlog): + tout = open(self.tlog, "a") + else: + tout = open(self.tlog, "w") + cll = [ + "shed-tools", + "install", + "-g", + self.args.galaxy_url, + "--latest", + "-a", + self.args.galaxy_api_key, + "--name", + self.tool_name, + "--owner", + "fubar", + "--toolshed", + self.args.toolshed_url, + "--section_label", + "ToolFactory", + ] + tout.write("running\n%s\n" % " ".join(cll)) + subp = subprocess.run( + cll, + env=self.ourenv, + cwd=self.ourcwd, + shell=False, + stderr=tout, + stdout=tout, + ) + tout.write( + "installed %s - got retcode %d\n" % (self.tool_name, subp.returncode) + ) + tout.close() + return subp.returncode + + def planemo_biodocker_test(self): + """planemo currently leaks dependencies if used in the same container and gets unhappy after a + first successful run. https://github.com/galaxyproject/planemo/issues/1078#issuecomment-731476930 + + Docker biocontainer has planemo with caches filled to save repeated downloads + + + """ + + def prun(container, tout, cl, user="biodocker"): + rlog = container.exec_run(cl, user=user) + slogl = str(rlog).split("\\n") + slog = "\n".join(slogl) + tout.write(f"## got rlog {slog} from {cl}\n") + + if os.path.exists(self.tlog): + tout = open(self.tlog, "a") + else: + tout = open(self.tlog, "w") + planemoimage = "quay.io/fubar2/planemo-biocontainer" + xreal = "%s.xml" % self.tool_name + repname = f"{self.tool_name}_planemo_test_report.html" + ptestrep_path = os.path.join(self.repdir, repname) + client = docker.from_env() + tvol = client.volumes.create() + tvolname = tvol.name + destdir = "/toolfactory/ptest" + imrep = os.path.join(destdir, repname) + # need to keep the container running so keep it open with sleep + # will stop and destroy it when we are done + container = client.containers.run( + planemoimage, + "sleep 120m", + detach=True, + user="biodocker", + volumes={f"{tvolname}": {"bind": "/toolfactory", "mode": "rw"}}, + ) + cl = f"mkdir -p {destdir}" + prun(container, tout, cl, user="root") + # that's how hard it is to get root on a biodocker container :( + cl = f"rm -rf {destdir}/*" + prun(container, tout, cl, user="root") + ptestpath = os.path.join(destdir, "tfout", xreal) + self.copy_to_container(self.tooloutdir, destdir, container) + cl = "chown -R biodocker /toolfactory" + prun(container, tout, cl, user="root") + _ = container.exec_run(f"ls -la {destdir}") + ptestcl = f"planemo test --test_output {imrep} --update_test_data --no_cleanup --test_data {destdir}/tfout/test-data --galaxy_root /home/biodocker/galaxy-central {ptestpath}" + try: + _ = container.exec_run(ptestcl) + # fails because test outputs missing but updates the test-data directory + except Exception: + e = sys.exc_info()[0] + tout.write(f"#### error: {e} from {ptestcl}\n") + cl = f"planemo test --test_output {imrep} --no_cleanup --test_data {destdir}/tfout/test-data --galaxy_root /home/biodocker/galaxy-central {ptestpath}" + try: + prun(container, tout, cl) + except Exception: + e = sys.exc_info()[0] + tout.write(f"#### error: {e} from {ptestcl}\n") + testouts = tempfile.mkdtemp(suffix=None, prefix="tftemp", dir=".") + self.copy_from_container(destdir, testouts, container) + src = os.path.join(testouts, "ptest") + if os.path.isdir(src): + shutil.copytree(src, ".", dirs_exist_ok=True) + src = repname + if os.path.isfile(repname): + shutil.copyfile(src, ptestrep_path) + else: + tout.write(f"No output from run to shutil.copytree in {src}\n") + tout.close() + container.stop() + container.remove() + tvol.remove() + shutil.rmtree(testouts) # leave for debugging + + + # def run(self): + # """ + # scripts must be small enough not to fill the pipe! + # """ + # if self.treatbashSpecial and self.opts.interpreter in ['bash','sh']: + # retval = self.runBash() + # else: + # if self.opts.output_dir: + # ste = open(self.elog,'w') + # sto = open(self.tlog,'w') + # sto.write('## Toolfactory generated command line = %s\n' % ' '.join(self.cl)) + # sto.flush() + # p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=ste,stdin=subprocess.PIPE,cwd=self.opts.output_dir) + # else: + # p = subprocess.Popen(self.cl,shell=False,stdin=subprocess.PIPE) + # p.stdin.write(self.script) + # p.stdin.close() + # retval = p.wait() + # if self.opts.output_dir: + # sto.close() + # ste.close() + # err = open(self.elog,'r').read() + # if retval <> 0 and err: # problem + # print >> sys.stderr, '## error code %d returned with:\n%s' % (retval,err) + # if self.opts.make_HTML: + # self.makeHtml() + # return retval + + # def runBash(self): + # """ + # cannot use - for bash so use self.sfile + # """ + # if self.opts.output_dir: + # s = '## Toolfactory generated command line = %s\n' % ' '.join(self.cl) + # sto = open(self.tlog,'w') + # sto.write(s) + # sto.flush() + # p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,cwd=self.opts.output_dir) + # else: + # p = subprocess.Popen(self.cl,shell=False) + # retval = p.wait() + # if self.opts.output_dir: + # sto.close() + # if self.opts.make_HTML: + # self.makeHtml() + # return retval + + # def make_conda_env(self, dep_list): + # """ +# (venv) galaxy@ross-newgrt:/evol/galaxy$ mulled-hash bioblend=0.17.0,galaxyxml=0.4.14 +# mulled-v2-37438395e15c3d0bed4e02d66d5b05ca3d18b389:1d0b008b65909163243b3fdddd9aa20605f8a005 + +# conda create -n myenv python=3.9 scipy=0.17.3 astroid babel + + + # """ + # dep_list.sort() + # self.env_name = '-'.join(dep_list) + # for e in self.xmlcl + + + # for e in self.xclsuffix: + # # xappendme = ["999", p["infilename"], "< $%s" % p["infilename"]] + # else: + # xappendme = [p["CL"], "$%s" % p["infilename"], ""] + # xclsuffix.append(xappendme) + # if os.path.exists(self.tlog): + # tout = open(self.tlog, "a") + # else: + # tout = open(self.tlog, "w") + # cli = ["conda", "create", "-n", self.env_name, ' '.join(dep_list)] + # p = subprocess.run( + # cll, + # shell=False, + # cwd=self.tooloutdir, + # stderr=tout, + # stdout=tout, + # ) + # cli = ["conda", "activate", self.env_name, " && "] + # cli.append(run_cmd) + # tout.close() + +def main(): + """ + This is a Galaxy wrapper. + It expects to be called by a special purpose tool.xml + + """ + parser = argparse.ArgumentParser() + a = parser.add_argument + a("--script_path", default=None) + a("--history_test", default=None) + a("--cl_user_suffix", default=None) + a("--sysexe", default=None) + a("--packages", default=None) + a("--tool_name", default="newtool") + a("--tool_dir", default=None) + a("--input_files", default=[], action="append") + a("--output_files", default=[], action="append") + a("--user_email", default="Unknown") + a("--bad_user", default=None) + a("--help_text", default=None) + a("--tool_desc", default=None) + a("--tool_version", default="0.01") + a("--citations", default=None) + a("--command_override", default=None) + a("--test_override", default=None) + a("--additional_parameters", action="append", default=[]) + a("--selecttext_parameters", action="append", default=[]) + a("--edit_additional_parameters", action="store_true", default=False) + a("--parampass", default="positional") + a("--tfout", default="./tfout") + a("--galaxy_root", default="/galaxy-central") + a("--galaxy_venv", default="/galaxy_venv") + a("--collection", action="append", default=[]) + a("--include_tests", default=False, action="store_true") + a("--install_flag", action = "store_true", default=False) + a("--admin_only", default=True, action="store_true") + a("--untested_tool_out", default=None) + a("--local_tools", default="tools") # relative to $__root_dir__ + a("--tool_conf_path", default="config/tool_conf.xml") # relative to $__root_dir__ + args = parser.parse_args() + if args.admin_only: + assert not args.bad_user, ( + 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy \ +admin adds %s to "admin_users" in the galaxy.yml Galaxy configuration file' + % (args.bad_user, args.bad_user) + ) + assert args.tool_name, "## This ToolFactory cannot build a tool without a tool name. Please supply one." + tf = Tool_Factory(args) + tf.writeShedyml() + tf.makeTool() + tf.planemo_test_update() + tf.makeToolTar() + tf.update_toolconf() + + +if __name__ == "__main__": + main() diff -r 2beaae16651e -r 0183cad9d13b pyrev_pos_test/test-data/pyrev_positionalparse_output_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyrev_pos_test/test-data/pyrev_positionalparse_output_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1210 @@ +yrotcafloot/2rabuf/moc.buhtig//:sptth ees # +# +2102 yaM )moc pots liamg ta surazal pots ssor( surazal ssor thgirypoc # +# +devreser sthgir lla # +LPGL eht rednu desneciL # +ta emoclew sexif gub dna tnemevorpmi rof snoitseggus # +yrotcafloot/2rabuf/moc.buhtig//:sptth # +# +llatsni/tset dna etareneg - sloot owt otni derotcafeR :2202 hcram # +noitpoda reniatnocoib dna tnempoleved lairotut NTG fo trap sa # +stuptuo tset eht setaerc ,evihcra detset-non a no omenalp snur retset ehT # +.tset htiw loot reporp wen a snruter dna # + + + +esrapgra tropmi +ypoc tropmi +ltncf tropmi +nosj tropmi +so tropmi +er tropmi +xelhs tropmi +lituhs tropmi +ssecorpbus tropmi +sys tropmi +elifrat tropmi +elifpmet tropmi +emit tropmi + +yxalag tropmi dnelboib morf + +txg sa loot.lmxyxalag tropmi +ptxg sa sretemarap.loot.lmxyxalag tropmi + +TE sa eerte.lmxl tropmi + +lmay tropmi + +"2202 hcraM 4.2V" = noisrevym +eurT = esobrev +eurT = gubed +"yrotcafloot/2rabuf/moc.buhtig//:sptth" = LRUyrotcaFloot +"~~~EM~~~EVOMER~~~" = EXEEKAF +neve exe eht gnidneperp lmxyxalag xif ot pmub noisrev/RP a litnu siht deen # +.edirrevo htiw # + + +:)(wonemit fed +"""gnirts a sa emit tnerruc nruter""" +)))(emit.emit(emitlacol.emit ,"S%:M%:H% Y%/m%/d%"(emitfrts.emit nruter + + +}"#\\" :"#" ,"$\\" :"$"{ = elbat_epacse_hateehc + + +:)txet(epacse_hateehc fed +""".txet nihtiw seititne ecudorP""" +)]txet ni c rof )c ,c(teg.elbat_epacse_hateehc[(nioj."" nruter + + +:)txet_snoitatic(snoitatic_esrap fed +"""""" +])(pirts.c fi )"**YRTNE**"(tilps.txet_snoitatic ni c rof c[ = snoitatic +][ = selput_noitatic +:snoitatic ni noitatic rof +:)"iod"(htiwstrats.noitatic fi +)))(pirts.]: )"iod"(nel[noitatic ,"iod"((dneppa.selput_noitatic +:esle +)))(pirts.]: )"xetbib"(nel[noitatic ,"xetbib"((dneppa.selput_noitatic +selput_noitatic nruter + + +:yrotcaF_looT ssalc +tpircs yrartibra na rof repparW""" +lmxyxalag sesu + +""" + +aqon # :)enoN=sgra ,fles(__tini__ fed +""" +ereh loot eht gninnur rof lc enil dnammoc eraperp +noitareneg loot lmxyxalag rof dedeen stnemele eraperp dna +""" +)'sloot_lacol',toor_yxalag.sgra(nioj.htap.so = sloot_lacol.fles +)(dwcteg.so = dwcruo.fles +][ = snoitcelloc.fles +:0 > )noitcelloc.sgra(nel fi +:yrt +[ = snoitcelloc.fles +1 > ))(pirts.x(nel fi noitcelloc.sgra ni x rof )x(sdaol.nosj +] +:noitpecxE tpecxe +(tnirp +"yranoitcid a eb dluohs - demroflam si })noitcelloc.sgra(rts{ retemarap snoitcelloc--"f +) +:yrt +[ = selifni.fles +1 > ))(pirts.x(nel fi selif_tupni.sgra ni x rof )x(sdaol.nosj +] +:noitpecxE tpecxe +(tnirp +"yranoitcid a eb dluohs - demroflam si })selif_tupni.sgra(rts{ retemarap selif_tupni--"f +) +:yrt +[ = seliftuo.fles +1 > ))(pirts.x(nel fi selif_tuptuo.sgra ni x rof )x(sdaol.nosj +] +:noitpecxE tpecxe +(tnirp +"yranoitcid a eb dluohs - demroflam si }selif_tuptuo.sgra{ retemarap selif_tuptuo--"f +) +'tros emos fo tuptuo na tuohtiw liaf lliw rennur boj yxalaG ehT .deificeps snoitcelloc tuptuo ro seliftuo oN' ,0 > ))snoitcelloc.fles(nel + )seliftuo.fles(nel( tressa +:yrt +[ = rapdda.fles +1 > ))(pirts.x(nel fi sretemarap_lanoitidda.sgra ni x rof )x(sdaol.nosj +] +:noitpecxE tpecxe +(tnirp +"yranoitcid a eb dluohs - demroflam si }sretemarap_lanoitidda.sgra{ sretemarap_lanoitidda--"f +) +:yrt +[ = raples.fles +1 > ))(pirts.x(nel fi sretemarap_txettceles.sgra ni x rof )x(sdaol.nosj +] +:noitpecxE tpecxe +(tnirp +"yranoitcid a eb dluohs - demroflam si }sretemarap_txettceles.sgra{ sretemarap_txettceles--"f +) +sgra = sgra.fles +)(rappunaelc.fles +enoN = tceriderlcxtsal.fles +][ = lclmx.fles +"lanoitisop" == ssapmarap.sgra.fles = lanoitisop_si.fles +:exesys.sgra.fles fi +:exesys.sgra.fles ni " " fi +)exesys.sgra.fles(tilps.xelhs = emetucexe.fles +:esle +[ = emetucexe.fles +,exesys.sgra.fles +] +:esle +:segakcap.sgra.fles fi +[ = emetucexe.fles +,)(pirts.]0[)":"(tilps.]0[)","(tilps.segakcap.sgra.fles +] +:esle +enoN = emetucexe.fles +dneppa.lclmx.fles = LCXa +[ ni ssapmarap.sgra tressa +,"0" +,"esrapgra" +,"lanoitisop" +'"esrapgra" ro "lanoitisop","0" eb tsum ssapmarap.sgra' ,] +)eman_loot.sgra ,"" ,"+]_9-0Z-Az-a^["(bus.er = eman_loot.fles +eman_loot.fles = di_loot.fles +(looT.txg = lootwen.fles +,eman_loot.fles +,di_loot.fles +,noisrev_loot.sgra.fles +,csed_loot.sgra.fles +,EXEEKAF +) +"tuoft/." = ridtuoloot.fles +"negloot/." = ridper.fles +)eman_loot.fles % "zg.dehsloot_detset_ton_s%" ,ridtuoloot.fles(nioj.htap.so # tuo_loot_detsetnu.sgra = htapratwen.fles +)"atad-tset" ,ridtuoloot.fles(nioj.htap.so = ridtset.fles +:)ridtuoloot.fles(stsixe.htap.so ton fi +)ridtuoloot.fles(ridkm.so +:)ridtset.fles(stsixe.htap.so ton fi +)ridtset.fles(ridkm.so +:)ridper.fles(stsixe.htap.so ton fi +)ridper.fles(ridkm.so +)eman_loot.fles % 'txt.gol_nur_FT_s%',ridper.fles(nioj.htap.so = golt.fles +)(stupnI.ptxg = stupnit.fles +)(stuptuO.ptxg = stuptuot.fles +][ = maraptset.fles +:htap_tpircs.sgra.fles fi +)(tpircSperp.fles +:edirrevo_dnammoc.sgra.fles fi +)(senildaer.)"r" ,edirrevo_dnammoc.sgra.fles(nepo = socs +]socs ni x rof )(pirtsr.x[ = edirrevo_dnammoc.fles +:esle +enoN = edirrevo_dnammoc.fles +:edirrevo_tset.sgra.fles fi +)(senildaer.)"r" ,edirrevo_tset.sgra.fles(nepo = sots +]sots ni x rof )(pirtsr.x[ = edirrevo_tset.fles +:esle +enoN = edirrevo_tset.fles +:htap_tpircs.sgra.fles fi +:emetucexe.fles ni xe rof +)xe(LCXa +)"emnur$"(LCXa +:esle +:emetucexe.fles ni xe rof +)xe(LCXa + +:"0" == ssapmarap.sgra.fles fi +)(elpmislc.fles +:esle +:"lanoitisop" == ssapmarap.sgra.fles fi +)(soplcperp.fles +)(lanoitisoplc.fles +:esle +)(pgraperp.fles +)(esrapgralc.fles + +:)fles(elpmislc fed +"""o/i rof > dna < sesu - staeper ro sretemarap on""" +dneppa.lclmx.fles = LCXa +:0 > )selifni.fles(nel fi +)"<"(LCXa +)]"emanelifni"[]0[selifni.fles % "s%$"(LCXa +:0 > )seliftuo.fles(nel fi +)">"(LCXa +)]"eman"[]0[seliftuo.fles % "s%$"(LCXa +dne LC YID # :xiffus_resu_lc.sgra.fles fi +)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc +:plc ni c rof +)c(LCXa + +:)fles(pgraperp fed +][ = xiffuslcx +:)selifni.fles(etaremune ni p ,i rof +]"emanelifni"[p = man +:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi +[ = emdneppax +,man +,man +,man % "s%$ <" +] +:esle +"1" == ]"taeper"[p = per +"" = revo +:per fi +'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo +]revo ,]"LC"[p % "s%$" ,]"LC"[p[ = emdneppax +)emdneppax(dneppa.xiffuslcx +:)seliftuo.fles(etaremune ni p ,i rof +:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi +]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles +:esle +)]"" ,]"eman"[p % "s%$" ,]"eman"[p[(dneppa.xiffuslcx +:rapdda.fles ni p rof +]"eman"[p = man +"1" == ]"taeper"[p = per +:per fi +'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo +:esle +]"edirrevo"[p = revo +)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +:raples.fles ni p rof +)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +xiffuslcx = xiffuslcx.fles + +:)fles(soplcperp fed +][ = xiffuslcx +:)selifni.fles(etaremune ni p ,i rof +:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi +[ = emdneppax +,"999" +,]"emanelifni"[p +,]"emanelifni"[p % "s%$ <" +] +:esle +]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax +)emdneppax(dneppa.xiffuslcx +:)seliftuo.fles(etaremune ni p ,i rof +:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi +]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles +:esle +)]"" ,]"eman"[p % "s%$" ,]"LC"[p[(dneppa.xiffuslcx +:rapdda.fles ni p rof +]"eman"[p = man +esnes ON ekam staeper # "1" == ]"taeper"[p = per +:per fi +(tnirp +"!senil dnammoc retemarap lanoitisop ni dettimrep ton - derongi }man{ rof staepeR .gninraw ###"f +) +]"edirrevo"[p = revo +)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +:raples.fles ni p rof +)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +)(tros.xiffuslcx +xiffuslcx = xiffuslcx.fles + +:)fles(tpircSperp fed +)(senildaer.)"r" ,htap_tpircs.sgra.fles(nepo = xr +]xr ni x rof )(pirtsr.x[ = xr +]"" > )(pirts.x fi xr ni x rof )(pirts.x[ = kcehcxr +"nur tonnaC .ytpme si tpircs deilppuS" ,0 > )kcehcxr(nel tressa +)xr(nioj."n\" = tpircs.fles +(pmetskm.elifpmet = elifs.fles ,eldnahf +)]0[emetucexe.fles( % "s%_"=xiffus ,eman_loot.fles=xiferp +) +)"w" ,elifs.fles(nepo = tpircst +)tpircs.fles(etirw.tpircst +)(esolc.tpircst +]"" > )(pirts.x fi xr ni x rof "}x{ "f[ = tpircSdecaps.fles +)"war#" ,0(tresni.xr +)"war dne#"(dneppa.xr +xr = tpircSdepacse.fles +)]0[emetucexe.fles ,eman_loot.fles( % "s%.s%" = tra +)"bw" ,tra(nepo = tcafitra +))"8ftu" ,tpircs.fles(setyb(etirw.tcafitra +)(esolc.tcafitra + +:)fles(rappunaelc fed +"""lanidro ciremun rieht yb detacilpmoc era sretemarap lanoitisop """ +:"lanoitisop" == ssapmarap.sgra.fles fi +:)selifni.fles(etaremune ni p ,i rof +( tressa +"NIDTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p +( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,) +,]"LC"[p +,]"lebal"[p +) +:)seliftuo.fles(etaremune ni p ,i rof +( tressa +"TUODTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p +( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,) +,]"LC"[p +,]"eman"[p +) +:)rapdda.fles(etaremune ni p ,i rof +[p tressa +"LC" +( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)(tigidsi.] +,]"LC"[p +,]"eman"[p +) +:)selifni.fles(etaremune ni p ,i rof +)p(ypoc.ypoc = pfni +]"LC"[pfni = ]"LCgiro"[pfni +:]"0" ,"lanoitisop"[ ni ssapmarap.sgra.fles fi +)"_" ," "(ecalper.]"lebal"[pfni = ]"emanelifni"[pfni +:esle +]"LC"[pfni = ]"emanelifni"[pfni +pfni = ]i[selifni.fles +:)seliftuo.fles(etaremune ni p ,i rof +)p(ypoc.ypoc = pftuo +ypoc peek # ]"LC"[pftuo = ]"LCgiro"[pftuo +pftuo = ]i[seliftuo.fles +:)rapdda.fles(etaremune ni p ,i rof +)p(ypoc.ypoc = pdda +]"LC"[pdda = ]"LCgiro"[pdda +pdda = ]i[rapdda.fles + +:)fles(lanoitisoplc fed +smarap neht redro ni stupni # +dneppa.lclmx.fles = LCXa +:xiffuslcx.fles ni )edirrevok ,v ,k( rof +)v(LCXa +:tceriderlcxtsal.fles fi +:tceriderlcxtsal.fles ni lc rof +)lc(LCXa +dne LC YID # :xiffus_resu_lc.sgra.fles fi +)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc +:plc ni c rof +)c(LCXa + +:)fles(esrapgralc fed +"""elyts esrapgra""" +dneppa.lclmx.fles = LCXa +mrof deman esrapgra ni smarap neht stupni # + +:xiffuslcx.fles ni )edirrevok ,v ,k( rof +:"" > edirrevok fi +edirrevok = k +)k(LCXa +:esle +:1 == ))(pirts.k(nel fi +k % "s%-" = k +:esle +k % "s%--" = k +)k(LCXa +)v(LCXa +:tceriderlcxtsal.fles fi +:tceriderlcxtsal.fles ni lc rof +)lc(LCXa +dne LC YID # :xiffus_resu_lc.sgra.fles fi +)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc +:plc ni c rof +)c(LCXa + +:)emanwen ,fles(hsadNteg fed +:lanoitisop_si.fles fi +0 = hsadn +:esle +2 = hsadn +:2 < )emanwen(nel fi +1 = hsadn +hsadn nruter + +aqon # :)fles(marapLMXod fed +"""loot ot stnemele dedeen lla ddA""" +:seliftuo.fles ni p rof +]"eman"[p = emanwen +]"tamrof"[p = tmfwen +]"LC"[p = lcwen +]"tset"[p = tset +]"LCgiro"[p = lcdlo +)(pirts.tset = tset +)lcwen(hsadNteg.fles = hsadn +(ataDtuptuO.ptxg = mrapa +emanwen=lebal ,hsadn=sehsad_mun ,tmfwen=tamrof ,emanwen=eman +) +lanoitisop_si.fles = lanoitisop.mrapa +:lanoitisop_si.fles fi +:"TUODTS" == )(reppu.lcdlo fi +9999999 = lanoitisop.mrapa +emanwen % "s%$ >" = edirrevo_enil_dnammoc.mrapa +:esle +)lcdlo(tni = lanoitisop.mrapa +emanwen % "s%$" = edirrevo_enil_dnammoc.mrapa +)mrapa(dneppa.stuptuot.fles +enoN = dl +:"" > )(pirts.tset fi +:)"ffid"(htiwstrats.)(pirts.tset fi +"ffid" = c +0 = dl +:tigidsi.]1[)":"(tilps.tset fi +)]1[)":"(tilps.tset(tni = dl +(tuptuOtseT.ptxg = pt +,emanwen=eman +,emanwen % "elpmas_s%"=eulav +,c=erapmoc +,dl=ffid_senil +) +:)"ezis_mis"(htiwstrats.tset file +"ezis_mis" = c +)(pirts.]1[)":"(tilps.tset = nt +:"" > nt fi +:nt ni "." fi +enoN = atled +))nt(taolf ,0.1(nim = carf_atled +:esle +)nt(tni = atled +enoN = carf_atled +(tuptuOtseT.ptxg = pt +,emanwen=eman +,emanwen % "elpmas_s%"=eulav +,c=erapmoc +,atled=atled +,carf_atled=carf_atled +) +:esle +tset = c +(tuptuOtseT.ptxg = pt +,emanwen=eman +,emanwen % "elpmas_s%"=eulav +,c=erapmoc +) +)pt(dneppa.maraptset.fles +:selifni.fles ni p rof +]"emanelifni"[p = emanwen +]"tamrof"[p = tmfwen +)emanwen(hsadNteg.fles = hsadn +"1" == )"0" ,"taeper"(teg.p = sper +:0 > )]"lebal"[p(nel ton fi +]"LC"[p = bala +:esle +]"lebal"[p = bala +(maraPataD.ptxg = tupnina +,emanwen +,eslaF=lanoitpo +,bala=lebal +,]"pleh"[p=pleh +,tmfwen=tamrof +,eslaF=elpitlum +,hsadn=sehsad_mun +) +lanoitisop_si.fles = lanoitisop.tupnina +:lanoitisop_si.fles fi +:"NIDTS" == )(reppu.]"LCgiro"[p fi +8999999 = lanoitisop.tupnina +emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina +:esle +)]"LCgiro"[p(tni = lanoitisop.tupnina +emanwen % "s%$" = edirrevo_enil_dnammoc.tupnina +:sper fi +(taepeR.ptxg = eper +"dedeen sa }bala{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman +) +)tupnina(dneppa.eper +)eper(dneppa.stupnit.fles +)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt +)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = 2mrapt +)2mrapt(dneppa.mrapt +)mrapt(dneppa.maraptset.fles +:esle +)tupnina(dneppa.stupnit.fles +)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = mrapt +)mrapt(dneppa.maraptset.fles +:rapdda.fles ni p rof +]"eman"[p = emanwen +]"eulav"[p = lavwen +]"lebal"[p = lebalwen +]"pleh"[p = plehwen +]"epyt"[p = epytwen +]"LC"[p = lcwen +]"LCgiro"[p = lcdlo +"1" == ]"taeper"[p = sper +:0 > )lebalwen(nel ton fi +emanwen = lebalwen +)emanwen(hsadNteg.fles = hsadn +:"txet" == epytwen fi +(maraPtxeT.ptxg = mrapa +,emanwen +,lebalwen=lebal +,plehwen=pleh +,lavwen=eulav +,hsadn=sehsad_mun +) +:"regetni" == epytwen file +(maraPregetnI.ptxg = mrapa +,emanwen +,lebalwen=lebal +,plehwen=pleh +,lavwen=eulav +,hsadn=sehsad_mun +) +:"taolf" == epytwen file +(maraPtaolF.ptxg = mrapa +,emanwen +,lebalwen=lebal +,plehwen=pleh +,lavwen=eulav +,hsadn=sehsad_mun +) +:"naeloob" == epytwen file +(maraPnaelooB.ptxg = mrapa +,emanwen +,lebalwen=lebal +,plehwen=pleh +,lavwen=eulav +,hsadn=sehsad_mun +) +:esle +(rorrEeulaV esiar +\rof "s%" epyt retemarap desingocernU' +'LMXekam ni s% retemarap lanoitidda +)emanwen ,epytwen( % +) +lanoitisop_si.fles = lanoitisop.mrapa +:lanoitisop_si.fles fi +)lcdlo(tni = lanoitisop.mrapa +:sper fi +(taepeR.ptxg = eper +"dedeen sa }lebalwen{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman +) +)mrapa(dneppa.eper +)eper(dneppa.stupnit.fles +)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt +)lavwen=eulav ,emanwen(maraPtseT.ptxg = 2mrapt +)2mrapt(dneppa.mrapt +)mrapt(dneppa.maraptset.fles +:esle +)mrapa(dneppa.stupnit.fles +)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt +)mrapt(dneppa.maraptset.fles +:raples.fles ni p rof +]"eman"[p = emanwen +]"eulav"[p = lavwen +]"lebal"[p = lebalwen +]"pleh"[p = plehwen +]"epyt"[p = epytwen +]"LC"[p = lcwen +:0 > )lebalwen(nel ton fi +emanwen = lebalwen +)emanwen(hsadNteg.fles = hsadn +:"txettceles" == epytwen fi +]"stxet"[p = txetwen +(maraPtceleS.ptxg = mrapa +,emanwen +,lebalwen=lebal +,plehwen=pleh +,hsadn=sehsad_mun +) +:))lavwen(nel(egnar ni i rof +(noitpOtceleS.ptxg = tpona +,]i[lavwen=eulav +,]i[txetwen=txet +) +)tpona(dneppa.mrapa +lanoitisop_si.fles = lanoitisop.mrapa +:lanoitisop_si.fles fi +)lcwen(tni = lanoitisop.mrapa +)mrapa(dneppa.stupnit.fles +)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt +)mrapt(dneppa.maraptset.fles +:esle +(rorrEeulaV esiar +\rof "s%" epyt retemarap desingocernU' +'LMXekam ni s% retemarap txettceles +)emanwen ,epytwen( % +) +:snoitcelloc.fles ni p rof +]"dnik"[p = dnikwen +]"eman"[p = emanwen +]"lebal"[p = lebalwen +]"revocsid"[p = csidwen +)dnikwen=epyt ,lebalwen=lebal ,emanwen(noitcelloCtuptuO.ptxg = tcelloc +(stesataDrevocsiD.ptxg = csid +"eslaf"=elbisiv ,"}emanwen{"f=yrotcerid ,csidwen=nrettap +) +)csid(dneppa.tcelloc +)tcelloc(dneppa.stuptuot.fles +:yrt +.degrem RP litnu nekorb # )emanwen(noitcelloCtuptuOtseT.ptxg = mrapt +)mrapt(dneppa.maraptset.fles +:noitpecxE tpecxe +(tnirp +"!neht litnu neddir-revo eb tsum snoitcelloc rof stset - tey degrem RP eht evah ton seod noisrev lmxyxalaG :GNINRAW ####" +) + +:)fles(marapLMXoNod fed +"""tuodts ot nidts - egakcap elyts retlif""" +:0 > )selifni.fles(nel fi +]"lebal"[]0[selifni.fles = bala +:0 == )bala(nel fi +]"emanelifni"[]0[selifni.fles = bala +( = s1xam +"s% - deilppus selif tupni elpitlum tub 0 si ssapmarap fi tupni eno mumixaM" +)selifni.fles(rts % +) +s1xam ,1 == )selifni.fles(nel tressa +]"emanelifni"[]0[selifni.fles = emanwen +(maraPataD.ptxg = tupnina +,emanwen +,eslaF=lanoitpo +,bala=lebal +,]"pleh"[]0[selifni.fles=pleh +,]"tamrof"[]0[selifni.fles=tamrof +,eslaF=elpitlum +,0=sehsad_mun +) +emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina +eurT = lanoitisop.tupnina +)tupnina(dneppa.stupnit.fles +)emanwen % "elpmas_s%"=eulav ,emanwen=eman(maraPtseT.ptxg = pt +)pt(dneppa.maraptset.fles +:0 > )seliftuo.fles(nel fi +]"eman"[]0[seliftuo.fles = emanwen +]"tamrof"[]0[seliftuo.fles = tmfwen +)0=sehsad_mun ,tmfwen=tamrof ,emanwen(ataDtuptuO.ptxg = tuona +emanwen % "s%$ >" = edirrevo_enil_dnammoc.tuona +lanoitisop_si.fles = lanoitisop.tuona +)tuona(dneppa.stuptuot.fles +)emanwen % "elpmas_s%"=eulav ,emanwen=eman(tuptuOtseT.ptxg = pt +)pt(dneppa.maraptset.fles + +aqon # :)fles(LMXekam fed +""" +tpircs wen eht rof repparw loot lmx yxalaG a etaerC +lmthyxalag sesU +...redro tcerroc otni enil dnammoc eht teg ot woH .mmmH +""" +:edirrevo_dnammoc.fles fi +elif gifnoc # edirrevo_dnammoc.fles = edirrevo_dnammoc.lootwen.fles +:esle +lclmx.fles = edirrevo_dnammoc.lootwen.fles +)(snoitatiC.ptxg = etic +)"375stb/scitamrofnioib/3901.01"=eulav ,"iod"=epyt(noitatiC.ptxg = etica +)etica(dneppa.etic +etic = snoitatic.lootwen.fles +"" = txetrefas +:txet_pleh.sgra.fles fi +)(senildaer.)"r" ,txet_pleh.sgra.fles(nepo = txetpleh +)]txetpleh ni x rof )x(epacse_hateehc[(nioj."n\" = txetrefas +:0 == ))(pirts.txetrefas(nel fi +( = txetrefas +"n\esaelp txet pleh htiw dliuber ot )s%( rohtua loot eht ksA" +)liame_resu.sgra.fles( % +) +:htap_tpircs.sgra.fles fi +:0 > )txetrefas(nel fi +!dewolla noitisnart # "n\------n\n\" + txetrefas = txetrefas +]"" > )(pirts.x fi tpircSdecaps.fles ni x rof x[ = rcs +)"n\::tpircSn\n\" ,0(tresni.rcs +:003 > )rcs(nel fi +( = rcs +]001:[rcs +]"...... " ,"deteled ffuts - senil 003> "[ + +]:001-[rcs + +) +)"n\"(dneppa.rcs +)rcs(nioj."n\" + txetrefas = txetrefas +txetrefas = pleh.lootwen.fles +'"}noisrev_loot.sgra.fles{" ohce'f = dnammoc_noisrev.lootwen.fles +)(soidtS.ptxg = dts +)(oidtS.ptxg = 1dts +)1dts(dneppa.dts +dts = soidts.lootwen.fles +)(stnemeriuqeR.ptxg = stnemeriuqer +][ = vneadnoc.fles +:segakcap.sgra.fles fi +:yrt +:)","(tilps.segakcap.sgra.fles ni d rof +enoN = rev +enoN = gkcap +)":" ,"=="(ecalper.d = d +)":" ,"="(ecalper.d = d +:d ni ":" fi +)":"(tilps.d = rev ,gkcap +)(pirts.rev = rev +)(pirts.gkcap = gkcap +:esle +)(pirts.d = gkcap +enoN = rev +:"" == rev fi +enoN = rev +:gkcap fi +(dneppa.stnemeriuqer +)rev ,)(pirts.gkcap ,"egakcap"(tnemeriuqeR.ptxg +) +)d(dneppa.vneadnoc.fles +:noitpecxE tpecxe +(tnirp +,"= esrap tonnac - deilppus gnirts segakcap demroflam ###" +,segakcap.sgra.fles +) +)2(tixe.sys +stnemeriuqer = stnemeriuqer.lootwen.fles +:"0" == ssapmarap.sgra.fles fi +)(marapLMXoNod.fles +:esle +)(marapLMXod.fles +stuptuot.fles = stuptuo.lootwen.fles +stupnit.fles = stupni.lootwen.fles +:htap_tpircs.sgra.fles fi +)(selifgifnoC.ptxg = selifgifnoc +(dneppa.selifgifnoc +))tpircSdepacse.fles(nioj."n\"=txet ,"emnur"=eman(elifgifnoC.ptxg +) +selifgifnoc = selifgifnoc.lootwen.fles +)(stseT.ptxg = stset +)(tseT.ptxg = a_tset +:maraptset.fles ni pt rof +)pt(dneppa.a_tset +)a_tset(dneppa.stset +stset = stset.lootwen.fles +(tnemmoc_dda.lootwen.fles +".yrotcaF looT yxalaG eht gnisu s% ta s% yb detaerC" +))(wonemit ,liame_resu.sgra.fles( % +) +))LRUyrotcaFloot( % "s% :ta tig ni ecruoS"(tnemmoc_dda.lootwen.fles +)(tropxe.lootwen.fles = 0lmxe +detpecca RP litnu dnuora krow yraropmet # )"" ,EXEEKAF(ecalper.0lmxe = lmxe +( fi +edirrevo_tset.fles +stset rof stcejbo lmxl stcepxe ti sa lmxyxalag edisni siht od tonnac # :) +]0[)">stset<"(tilps.lmxe = 1trap +]1[)">stset/<"(tilps.lmxe = 2trap +)2trap ,)edirrevo_tset.fles(nioj."n\" ,1trap( % "s%n\s%n\s%" = dexif +dexif = lmxe +:fx sa )"w" ,eman_loot.fles % "lmx.s%"(nepo htiw +)lmxe(etirw.fx +)"n\"(etirw.fx +meti yrotsih yxalag # + +:)fles(lmydehSetirw fed +"""omenalp rof""" +]0[)"@"(tilps.liame_resu.sgra.fles = resuy +)"lmy.dehs." ,ridtuoloot.fles(nioj.htap.so = emanfy +)"w" ,emanfy(nepo = flmay +{ = tcido +,eman_loot.fles :"eman" +,resuy :"renwo" +,"detcirtsernu" :"epyt" +,csed_loot.sgra.fles :"noitpircsed" +,csed_loot.sgra.fles :"sisponys" +,"slooT detareneG FT" :"yrogetac" +} +)eurT=edocinu_wolla ,flmay ,tcido(pmud.lmay +)(esolc.flmay + +:)fles(looTekam fed +"""ecalp otni selpmas tupni dna slmx etirw""" +:0 == ssapmarap.sgra.fles fi +)(marapLMXoNod.fles +:esle +)(LMXekam.fles +:htap_tpircs.sgra.fles fi +)elifs.fles ,ridtuoloot.fles(nioj.htap.so = emants +:)emants(stsixe.htap.so ton fi +)emants ,elifs.fles(elifypoc.lituhs +eman_loot.fles % "lmx.s%" = laerx +)laerx ,ridtuoloot.fles(nioj.htap.so = tuox +)tuox ,laerx(elifypoc.lituhs +)laerx ,ridper.fles(nioj.htap.so = tuox +)tuox ,laerx(elifypoc.lituhs +:selifni.fles ni p rof +]"eman"[p = htp +)]"emanelifni"[p % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsed +)tsed ,htp(elifypoc.lituhs +(nioj.htap.so = tsed +)]"tamrof"[p ,]"emanelifni"[p( % "s%.elpmas_s%" ,ridper.fles +) +)tsed ,htp(elifypoc.lituhs +)eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = tsed +)eurT=ko_tsixe_srid ,tsed,ridtuoloot.fles(eertypoc.lituhs + +:)eslaF=liaf_troper ,fles(raTlooTekam fed +"""llabrat eht eraperp dna atad-tset otni stuptuo evom""" +"lmth.troper_tset_omenalp_" = emedulcxe + +:)ofnirat(noitcnuf_edulcxe fed +eman.ofnirat = emanelif +ofnirat esle )emedulcxe(htiwsdne.emanelif fi enoN nruter + +:seliftuo.fles ni p rof +]"eman"[p = emano +)emano % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsedt +)emano ,ridtset.fles(nioj.htap.so = crs +:)tsedt(elifsi.htap.so ton fi +:)crs(elifsi.htap.so fi +)tsedt ,crs(elifypoc.lituhs +))]'tamrof'[p,emano( % "s%.elpmas.s%" ,ridper.fles(nioj.htap.so = tsed +)tsed ,crs(elifypoc.lituhs +:esle +:liaf_troper fi +(tnirp +".s% nur omenalp retfa ridtset ni dnuof ton s% elif tuptuo - deliaf evah yam looT###" +)ridtset.fles ,tsedt( % +) +)"zg:w" ,htapratwen.fles(nepo.elifrat = ft +(dda.ft +,ridtuoloot.fles=eman +,eman_loot.fles=emancra +,noitcnuf_edulcxe=retlif +) +))"zg.dehsloot_detsetnu_}eman_loot.fles{"f ,ridtuoloot.fles(nioj.htap.so ,htapratwen.fles(ypoc.lituhs +)(esolc.ft + + +:)fles(etadpu_tset_omenalp fed +gnitset rof elbaliava si os tnemeriuqer a si omenalp""" +""" +eman_loot.fles % "lmx.s%" = laerx +(nioj.htap.so = htap_tset_loot +"lmth.troper_tset_omenalp_}eman_loot.fles{"f ,ridper.fles +) +:)golt.fles(stsixe.htap.so fi +)"a" ,golt.fles(nepo = tuot +:esle +)"w" ,golt.fles(nepo = tuot +[ = llc +,"omenalp" +,"tset" +,"tini_otua_adnoc--" +,"sreniatnocoib--" +,"atad_tset--" +,)ridtset.fles(htapsba.htap.so +,"tuptuo_tset--" +,)htap_tset_loot(htapsba.htap.so +,"toor_yxalag--" +,toor_yxalag.sgra.fles +,"atad_tset_etadpu--" +,)laerx(htapsba.htap.so +] +(nur.ssecorpbus = p +,llc +,eslaF=llehs +,ridtuoloot.fles=dwc +,tuot=rredts +,tuot=tuodts +) +)(esolc.tuot +edocnruter.p nruter + + +:) fles(fnocloot_etadpu fed + +:)rtta ,tnerap(ybnerdlihctros fed +))rtta(teg.dlihc :dlihc adbmal=yek ,tnerap(detros = ]:[tnerap + +)'lmx.fnoc_loot_lacol/gifnoc',toor_yxalag.sgra.fles(nioj.htap.so = htapct +)eman_loot.fles % 'lmx.s%' ,eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = eliflmx +)eurT=txet_knalb_evomer(resraPLMX.TE = resrap +)resrap ,htapct(esrap.TE = eert +)(toorteg.eert = toor +eslaF = FTsah +)"noitces"(lladnif.toor = e +:0 > )e(nel fi +eurT = FTsah +]0[e = noitcesFT +:FTsah ton fi +)}"slooT lacoL":"eman" ,"slootlacol":"di"{ ,"noitces"(tnemelE.TE = noitcesFT +!pot eht ta # )noitcesFT ,0(tresni.toor +)"loot"(lladnif.noitcesFT = sloot_ruo +]sloot_ruo ni x rof ]"elif"[birtta.x[ = sloot_fnoc +wen # :sloot_fnoc ni ton eliflmx fi +)}eliflmx :"elif"{ ,"loot" ,noitcesFT(tnemelEbuS.TE +)"elif",noitcesFT(ybnerdlihctros +)eurT=tnirp_ytterp ,htapct(etirw.eert + + + + + + +:)fles(daoLdehs fed +""" +yrotisoper wen etaerc ot dnelboib esu +gnitsixe etadpu ro + +""" +:)golt.fles(stsixe.htap.so fi +)"a" ,golt.fles(nepo = ots +:esle +)"w" ,golt.fles(nepo = ots + +(ecnatsnIdehSlooT.dehsloot = st +,lru_dehsloot.sgra.fles=lru +,yek_ipa_dehsloot.sgra.fles=yek +,eslaF=yfirev +) +)(seirotisoper_teg.seirotisoper.st = soper +]soper ni x rof )"?" ,"eman"(teg.x[ = semanr +]soper ni x rof )"?" ,"di"(teg.x[ = sdir +"sloot detareneg yrotcaFlooT" = tacft +:semanr ni ton eman_loot.fles fi +)(seirogetac_teg.seirogetac.st = tacst +]tacst ni x rof )(pirts.)"?" ,"eman"(teg.x[ = semanc +]tacst ni x rof )"?" ,"di"(teg.x[ = sdic +enoN = DItac +:semanc ni )(pirts.tacft fi +)tacft(xedni.semanc = ic +]ic[sdic = DItac +(yrotisoper_etaerc.seirotisoper.st = ser +,eman_loot.sgra.fles=eman +,csed_loot.sgra.fles % "s%:sisponyS"=sisponys +,csed_loot.sgra.fles=noitpircsed +,"detcirtsernu"=epyt +,lru_dehsloot.sgra.fles=lru_yrotisoper_etomer +,enoN=lru_egapemoh +,DItac=sdi_yrogetac +) +)enoN ,"di"(teg.ser = dit +)"n\}ser{=ser }dit{=dit }eman_loot.sgra.fles{ yrotisoper_etaerc#"f(etirw.ots +:esle +)eman_loot.fles(xedni.semanr = i +]i[sdir = dit +:yrt +(yrotisoper_etadpu.seirotisoper.st = ser +enoN=egassem_timmoc ,htapratwen.fles=htap_llab_rat ,dit=di +) +)"n\}ser{= }di{ di ser etadpu#"f(etirw.ots +:rorrEnoitcennoC tpecxe +(etirw.ots +"n\deliaf daolpu dehs dnelboiB ?tcerroc yek IPA eht dna gninnur dehsloot eht sI #######" +) +)(esolc.ots + +:)fles(daol_yxalag_hpe fed +""" +ti sdaolpu omenalp retfa dehsloot lacol eht morf loot wen eht daol ot siremehpe esu +""" +:)golt.fles(stsixe.htap.so fi +)"a" ,golt.fles(nepo = tuot +:esle +)"w" ,golt.fles(nepo = tuot +[ = llc +,"sloot-dehs" +,"llatsni" +,"g-" +,lru_yxalag.sgra.fles +,"tsetal--" +,"a-" +,yek_ipa_yxalag.sgra.fles +,"eman--" +,eman_loot.fles +,"renwo--" +,"rabuf" +,"dehsloot--" +,lru_dehsloot.sgra.fles +,"lebal_noitces--" +,"yrotcaFlooT" +] +))llc(nioj." " % "n\s%n\gninnur"(etirw.tuot +(nur.ssecorpbus = pbus +,llc +,vneruo.fles=vne +,dwcruo.fles=dwc +,eslaF=llehs +,tuot=rredts +,tuot=tuodts +) +(etirw.tuot +)edocnruter.pbus ,eman_loot.fles( % "n\d% edocter tog - s% dellatsni" +) +)(esolc.tuot +edocnruter.pbus nruter + +:)fles(tset_rekcodoib_omenalp fed +a retfa yppahnu steg dna reniatnoc emas eht ni desu fi seicnedneped skael yltnerruc omenalp""" +039674137-tnemmoceussi#8701/seussi/omenalp/tcejorpyxalag/moc.buhtig//:sptth .nur lufsseccus tsrif + +sdaolnwod detaeper evas ot dellif sehcac htiw omenalp sah reniatnocoib rekcoD + + +""" + +:)"rekcodoib"=resu ,lc ,tuot ,reniatnoc(nurp fed +)resu=resu ,lc(nur_cexe.reniatnoc = golr +)"n\\"(tilps.)golr(rts = lgols +)lgols(nioj."n\" = gols +)"n\}lc{ morf }gols{ golr tog ##"f(etirw.tuot + +:)golt.fles(stsixe.htap.so fi +)"a" ,golt.fles(nepo = tuot +:esle +)"w" ,golt.fles(nepo = tuot +"reniatnocoib-omenalp/2rabuf/oi.yauq" = egamiomenalp +eman_loot.fles % "lmx.s%" = laerx +"lmth.troper_tset_omenalp_}eman_loot.fles{"f = emanper +)emanper ,ridper.fles(nioj.htap.so = htap_pertsetp +)(vne_morf.rekcod = tneilc +)(etaerc.semulov.tneilc = lovt +eman.lovt = emanlovt +"tsetp/yrotcafloot/" = ridtsed +)emanper ,ridtsed(nioj.htap.so = permi +peels htiw nepo ti peek os gninnur reniatnoc eht peek ot deen # +enod era ew nehw ti yortsed dna pots lliw # +(nur.sreniatnoc.tneilc = reniatnoc +,egamiomenalp +,"m021 peels" +,eurT=hcated +,"rekcodoib"=resu +,}}"wr" :"edom" ,"yrotcafloot/" :"dnib"{ :"}emanlovt{"f{=semulov +) +"}ridtsed{ p- ridkm"f = lc +)"toor"=resu ,lc ,tuot ,reniatnoc(nurp +(: reniatnoc rekcodoib a no toor teg ot si ti drah woh s'taht # +"*/}ridtsed{ fr- mr"f = lc +)"toor"=resu ,lc ,tuot ,reniatnoc(nurp +)laerx ,"tuoft" ,ridtsed(nioj.htap.so = htaptsetp +)reniatnoc ,ridtsed ,ridtuoloot.fles(reniatnoc_ot_ypoc.fles +"yrotcafloot/ rekcodoib R- nwohc" = lc +)"toor"=resu ,lc ,tuot ,reniatnoc(nurp +)"}ridtsed{ al- sl"f(nur_cexe.reniatnoc = _ +"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- atad_tset_etadpu-- }permi{ tuptuo_tset-- tset omenalp"f = lctsetp +:yrt +)lctsetp(nur_cexe.reniatnoc = _ +yrotcerid atad-tset eht setadpu tub gnissim stuptuo tset esuaceb sliaf # +:noitpecxE tpecxe +]0[)(ofni_cxe.sys = e +)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot +"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- }permi{ tuptuo_tset-- tset omenalp"f = lc +:yrt +)lc ,tuot ,reniatnoc(nurp +:noitpecxE tpecxe +]0[)(ofni_cxe.sys = e +)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot +)"."=rid ,"pmetft"=xiferp ,enoN=xiffus(pmetdkm.elifpmet = stuotset +)reniatnoc ,stuotset ,ridtsed(reniatnoc_morf_ypoc.fles +)"tsetp" ,stuotset(nioj.htap.so = crs +:)crs(ridsi.htap.so fi +)eurT=ko_tsixe_srid ,"." ,crs(eertypoc.lituhs +emanper = crs +:)emanper(elifsi.htap.so fi +)htap_pertsetp ,crs(elifypoc.lituhs +:esle +)"n\}crs{ ni eertypoc.lituhs ot nur morf tuptuo oN"f(etirw.tuot +)(esolc.tuot +)(pots.reniatnoc +)(evomer.reniatnoc +)(evomer.lovt +gniggubed rof evael # )stuotset(eertmr.lituhs + + +:)fles(nur fed # +""" # +!epip eht llif ot ton hguone llams eb tsum stpircs # +""" # +:]'hs','hsab'[ ni reterpretni.stpo.fles dna laicepShsabtaert.fles fi # +)(hsaBnur.fles = lavter # +:esle # +:rid_tuptuo.stpo.fles fi # +)'w',gole.fles(nepo = ets # +)'w',golt.fles(nepo = ots # +))lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##'(etirw.ots # +)(hsulf.ots # +)rid_tuptuo.stpo.fles=dwc,EPIP.ssecorpbus=nidts,ets=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +:esle # +)EPIP.ssecorpbus=nidts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +)tpircs.fles(etirw.nidts.p # +)(esolc.nidts.p # +)(tiaw.p = lavter # +:rid_tuptuo.stpo.fles fi # +)(esolc.ots # +)(esolc.ets # +)(daer.)'r',gole.fles(nepo = rre # +melborp # :rre dna 0 >< lavter fi # +)rre,lavter( % 's%n\:htiw denruter d% edoc rorre ##' ,rredts.sys >> tnirp # +:LMTH_ekam.stpo.fles fi # +)(lmtHekam.fles # +lavter nruter # + +:)fles(hsaBnur fed # +""" # +elifs.fles esu os hsab rof - esu tonnac # +""" # +:rid_tuptuo.stpo.fles fi # +)lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##' = s # +)'w',golt.fles(nepo = ots # +)s(etirw.ots # +)(hsulf.ots # +)rid_tuptuo.stpo.fles=dwc,ots=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +:esle # +)eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +)(tiaw.p = lavter # +:rid_tuptuo.stpo.fles fi # +)(esolc.ots # +:LMTH_ekam.stpo.fles fi # +)(lmtHekam.fles # +lavter nruter # + +:)tsil_ped ,fles(vne_adnoc_ekam fed # +""" # +41.4.0=lmxyxalag,0.71.0=dnelboib hsah-dellum $yxalag/love/:trgwen-ssor@yxalag )vnev( # +500a8f50602aa9ddddf3b34236190956b800b0d1:983b81d3ac50b5d66d20e4deb0d3c51e59383473-2v-dellum # + +lebab diortsa 3.71.0=ypics 9.3=nohtyp vneym n- etaerc adnoc # + + +""" # +)(tros.tsil_ped # +)tsil_ped(nioj.'-' = eman_vne.fles # ++ lclmx.fles ni e rof # + +:xiffuslcx.fles ni e rof # +]]"emanelifni"[p % "s%$ <" ,]"emanelifni"[p ,"999"[ = emdneppax # # +:esle # +]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax # +)emdneppax(dneppa.xiffuslcx # +:)golt.fles(stsixe.htap.so fi # +)"a" ,golt.fles(nepo = tuot # +:esle # +)"w" ,golt.fles(nepo = tuot # +])tsil_ped(nioj.' ' ,eman_vne.fles ,"n-" ,"etaerc" ,"adnoc"[ = ilc # +(nur.ssecorpbus = p # +,llc # +,eslaF=llehs # +,ridtuoloot.fles=dwc # +,tuot=rredts # +,tuot=tuodts # +) # +]" && " ,eman_vne.fles ,"etavitca" ,"adnoc"[ = ilc # +)dmc_nur(dneppa.ilc # +)(esolc.tuot # + +:)(niam fed +""" +.repparw yxalaG a si sihT +lmx.loot esoprup laiceps a yb dellac eb ot stcepxe tI + +""" +)(resraPtnemugrA.esrapgra = resrap +tnemugra_dda.resrap = a +)enoN=tluafed ,"htap_tpircs--"(a +)enoN=tluafed ,"tset_yrotsih--"(a +)enoN=tluafed ,"xiffus_resu_lc--"(a +)enoN=tluafed ,"exesys--"(a +)enoN=tluafed ,"segakcap--"(a +)"lootwen"=tluafed ,"eman_loot--"(a +)enoN=tluafed ,"rid_loot--"(a +)"dneppa"=noitca ,][=tluafed ,"selif_tupni--"(a +)"dneppa"=noitca ,][=tluafed ,"selif_tuptuo--"(a +)"nwonknU"=tluafed ,"liame_resu--"(a +)enoN=tluafed ,"resu_dab--"(a +)enoN=tluafed ,"txet_pleh--"(a +)enoN=tluafed ,"csed_loot--"(a +)"10.0"=tluafed ,"noisrev_loot--"(a +)enoN=tluafed ,"snoitatic--"(a +)enoN=tluafed ,"edirrevo_dnammoc--"(a +)enoN=tluafed ,"edirrevo_tset--"(a +)][=tluafed ,"dneppa"=noitca ,"sretemarap_lanoitidda--"(a +)][=tluafed ,"dneppa"=noitca ,"sretemarap_txettceles--"(a +)eslaF=tluafed ,"eurt_erots"=noitca ,"sretemarap_lanoitidda_tide--"(a +)"lanoitisop"=tluafed ,"ssapmarap--"(a +)"tuoft/."=tluafed ,"tuoft--"(a +)"lartnec-yxalag/"=tluafed ,"toor_yxalag--"(a +)"vnev_yxalag/"=tluafed ,"vnev_yxalag--"(a +)][=tluafed ,"dneppa"=noitca ,"noitcelloc--"(a +)"eurt_erots"=noitca ,eslaF=tluafed ,"stset_edulcni--"(a +)eslaF=tluafed ,"eurt_erots" = noitca ,"galf_llatsni--"(a +)"eurt_erots"=noitca ,eurT=tluafed ,"ylno_nimda--"(a +)enoN=tluafed ,"tuo_loot_detsetnu--"(a +__rid_toor__$ ot evitaler # )"sloot"=tluafed ,"sloot_lacol--"(a +__rid_toor__$ ot evitaler # )"lmx.fnoc_loot/gifnoc"=tluafed ,"htap_fnoc_loot--"(a +)(sgra_esrap.resrap = sgra +:ylno_nimda.sgra fi +( ,resu_dab.sgra ton tressa +\ yxalaG litnu loot siht esu ot dezirohtua TON si s% :DESIROHTUANU' +'elif noitarugifnoc yxalaG lmy.yxalag eht ni "sresu_nimda" ot s% sdda nimda +)resu_dab.sgra ,resu_dab.sgra( % +) +".eno ylppus esaelP .eman loot a tuohtiw loot a dliub tonnac yrotcaFlooT sihT ##" ,eman_loot.sgra tressa +)sgra(yrotcaF_looT = ft +)(lmydehSetirw.ft +)(looTekam.ft +)(etadpu_tset_omenalp.ft +)(raTlooTekam.ft +)(fnocloot_etadpu.ft + + +:"__niam__" == __eman__ fi +)(niam diff -r 2beaae16651e -r 0183cad9d13b seqtk_telo/seqtk_telo.seqtk=1.4.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/seqtk_telo/seqtk_telo.seqtk=1.4.txt Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1 @@ +seqtk $infa > $out_bed 2> $out_count diff -r 2beaae16651e -r 0183cad9d13b seqtk_telo/seqtk_telo.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/seqtk_telo/seqtk_telo.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,32 @@ + + + + + + seqtk + + + + + $out_bed ]]> + + + + + + + + + + + + + + + 10.1093/bioinformatics/bts573 + + + diff -r 2beaae16651e -r 0183cad9d13b seqtk_telo/test-data/infa_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/seqtk_telo/test-data/infa_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,163 @@ +>test +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +GCACTCGCCGCGAGGGTTGCCGGGACGGGCCCAAGATGGCTGAGCGCCTT +GGTTCCGCTTCTGCCTGCCGCGCAGAGCCCCATTCATTGCCTTGCTGCTA +AGTGGCGCCGCGTAGTGCCAGTAGGCTCCAAGTCTTCAGGGTCTGTCCCA +TCGGGCAGGAAGCCGTCATGGCAACCCTGGAAAAGCTGATGAAGGCTTTC +GAGTCGCTCAAGTCGTTTCAGCAGCAACAGCAGCAGCAGCCACCGCCGCA +GGCGCCGCCGCCACCGCCGCCGCCGCCTCCGCCTCAACCCCCTCAGCCGC +CGCCTCAGGGGCAGCCGCCGCCGCCACCACCGCCGCTGCCAGGTCCGGCA +GAGGAACCGCTGCACCGACCGTGAGTCCGGGCGCCGCAGCTCCCGCCCGG +GCCCCGCGCCCCTGGCCTGCGTGCTGGGCATGGCCAACACTGTTCCCTGT +CCAGAGGGTCGCGGTACCTCCCTGAGGCCAGGCTTTCCCGGCCCGGGCCC +TCGTCTTGCGGGGTCTCTGGCCTCCCTCAGAGGAGACAGAGCCGGGTCAG +GCCAGCCAGGGACTCGCTGAGGGGCGTCACGACTCCAGTGCCTTCGCCGT +TCCCAGTTTGCGAAGTTAGGGAACGAACTTGTTTCTCTCTTCTGGAGAAA +CTGGGGCGGTGGCGCACATGACTGTTGTGAAGAGAACTTGGAGAGGCAGA +GATCTCTAGGGTTACCTCCTCATCAGGCCTAAGAGCTGGGAGTGCAGGAC +AGCGTGAGAGATGTGCGGGTAGTGGATGACATAATGCTTTTAGGAGGTCT +CGGCGGGAGTGCTGAGGGCGGGGGAGTGTGAACGCATCCAATGGGATATT +CTTTTTCCAAGTGACACTTGAAGCAGCCTGTGACTCGAGGCACTTCGTAC +TCTCCTGGCGTTTCATTTAGTTTGTGGTGTAGTGTAGTTAAACCAGGTTT +TAAGCATAGCCAGAGAGGTGTGCTTCTGTGTGTCTGCAGGCAGTTGGATG +AGTTGTATTTGTCAAGTACATGGTGAGTTACTTAGGTGTGATTATTAATA +AAAAACTATATGTGTGCATATATATGAAAGAGTCGACTTATACTTAACTG +CCTATCGATTTTTTGTTCTATATAAAACGGATACATTGGTGGTGCTCAGT +TTTCACCGGGGAATGAATTTTACTAGTGTTGCAGACAGGCTTGTTTTAGA +ACATAGGCCACTCTGACTCTGACTTTGTGCCAGTAAAAGTTCCTGTTTAG +TTCTTTGCTGACATCTTATAGATCTTTGGAAGCTAGCTGCTTGTGACTGG +AGAGAATATTGAAACAGAAGAGAGACCATGAGTCACAGTGCTCTAAGAGA +AAAGAGACGCTCAAAACATTTCCTGGAAATCCATGCTGAGTGTTGAGCCC +TGTGCTCTCTTGCAGCTCAGTCCTTTCTCTCAACTCTGGGCATTTTATTT +CTAATCTGGATTTGTATAATTAATAAGGAGAACTTTTGGGAACAACCTAC +TAAAGAATGTCATCATTAAAACTCACTTAGAAAATAAGTGTTCTGGTGAT +ATCATTGAGCTATGTTCCCAGTCCTGAGAGTTTGTTTTTTTTTTTTTTTT +TAAATAAAGATTTGGGGAGAAAAGGTGGCTTACTTGATAGAACAAAATAT +AGGAATAAAATTTCCTTCTATAAGGTGAAAAGTGTGAATAGAAAACTTCT +TATCCTCTAGATAAGTAGTTTCTTTTTGCTTTTGAGAGTCTCACTATGTA +ACTCTTGACCTGAACTCAGAGAGATCCATCCTCCTGCCTCTGCCTCCTCT +CTCTGGGATTAAAGGCATGTGGCACCATGCTGGGCTGTCCAAGTATGCCA +CAGACCCTCTAGGTCCCTGGTCTTCGAGGAACGGGATTTCTTAGGCAGAT +GGGTAAGGAGTCGGATGAAAATGACAATCAGCCACACACAAGAGAGGTGT +TGAATCTGAATGTAATGTTCTGGTTGAGCTTCAGACTTATATAACAACGA +ATTATCAGAGGATACAAATCACAAAAAGACAAGATACACTGAAATTCACC +AGTTACAGCAGAAAGGAATTTGCAGGGACTAATTAAATGTTTACATTAGG +GATAACAAGCCCTGCCTAGGATCAGCCTAATGCCAGGCAAGAATTTCACA +CTTTAAGGTTAAAAGCATCAGGGGGTTGTTAACTCTTGACAGGCCTTAAG +AGTAATGTGCTATCACTGAGCTCTAAATTCTTAGGTCTAGTAAAACTTAT +CCTGTCTGGAGAGTTCCCCCTTATCAGGGTAGTATATCAACTTATACTTG +ACATGGAATGAAGCCTGTAGTAAAACATTTCTATCTCAGTGAGACTTTTA +GTCTCTATCTGTAAACAGCTGAGTAAAATGGCAAGTGCTTAATTGTTTAC +TGAATGGGTTAAGCTCCTTGCTGCTATCTGGAATCTAAGAACACTGGGGA +AAGGCTTTAGCTATGTTAGAATACAATATTAAAAGGCATTTACTATAAGG +TGATGCTTAATAGAGTGCACGTGAATCTATACACTAGATTAATGTGGTGG +AAATTTGAATATAATGGGTTAGGGAAAGAGATGCCATAACTCTGGGAGGA +AAATTTCCCTGGACTCTTATCCTCGTGAAACAGCTTCCAGGCTTTTCGCC +TGACAAACCGATCCAAACTGGAGAGTTGGCTTTCGCCAGAATATCCAGGA +GGAGAGTCCTAGAAATTCATTTCTCATGAGCAGCTTTTTGGCATTTTTGC +CTCACAAGCTGACTCCACCAGAGTACCCTGACACAAGTATTGTCTAGTTA +TTTTGATTATTACCATGACTCTGCCTCTGGGTGAGAGGAATTGTGGAAGT +TTACATATTCCCCATATCTTCTATAAACCTCTGTGTGTGTGTGTGTGTGT +GTGTGTGTGTGTGTGTGTGTGTGTATGAGGGAGAGAGAGGGAGAGAGAGA +GAGGGAGGGAGGAAGAGAGAGAGAGAGATTGTTCTGTGCCTGCTTCGAAC +ACAAATTAGTTTGCAAAAGTAATTCATTAACATGATACAGTCCCAAAGAT +AAAAATGGTTAAATAATGAAAACATCTCCCTCCCCATTTTCCTAACTTTG +TACCCAGGAGCAAGCTCTGTTACACTTCATTTGTCCTTCCAGATAAAATT +TGGGCATATGTTAGGACAGAATTTTAAATTATTTACAAACAAAAGTATTT +TGGAACAAAAGCTTTTAAAAGCTTTTATTTTAATAAAATAACTTGTTACT +ACACTGTATATAACTAACTAACATTTTCCAAAATTAGCTCCATTAGCATC +TATCTCATATTTCTATGTACTTTGCTGTTGAAAAACCAAGTGTTCATTAA +TAATAAGTAACAAACTCACTGCTTGGAAGCTTTGATTTTTGGCATTTTGT +CCACTTGACTCAGTTAAAAGTCCTTTTTTTCGAAATGAGAACAGCCAAAA +CAGTTTTAGAATGAGTCTGTTCTGCTTTTGTGACTCTCATTGTGTTCTGT +AGAACCAGTGTCACAGCCATATGTGGGCCTCTGTTGAAGTAGCTGAGAAC +TTGTTCTCTGCTCTGCTAGCTGCTGTCGATCTGATAGGCCTTGAACAGTT +GACATTCACCCTTAATAGTCCTCATTAGTCTTCCTGAGCATAGTCATTCA +TTTATCAATATTTGCTGATCATCTCCTATGTGCCTAGCATTGTTCTAGTT +GCAGGTTTTAGCAGGGAACAAAGTCATGTCTCATGAAGCTAAAATTCTTG +GGAGAGACATAGACAGTAAGCAGAATAGTTTGTTCATAGTGAGTGATGAG +GCGCATGCAGTAAAGTAGGGAAGGGGATTAGGAAATGCCAGGGCTTGACA +TGTTTTAGACAGGGTGTTTAAATAATATCTGCTTAGTTGAAGGCTTATTT +TTGAATAAATATCTGAAGAGTCAGAAATCTACCAGGAGGGTGTATGGAAG +AGGAGTATTCCTGCAAGGGGAAGTTGTCAAAGGCTTTCCTGTGTGGGGAT +TAGTGATGTCATGTTTTTGCTGGATGAAATGAGTGACGGTAAGAGTTGTA +GTGGGGGTGAAGCAAAGGGTTGAGGGAGGCTTCATTGGTGTTATCAGTTA +CTGCATTTATCTCCAAATAGAGAACGTAGCAATGAAAGCTACAGAGAACG +GGAAAGGTGAGGATTTATTCTAAGACAAAATAAGTGTAGGAAGTTTAACA +ATTAGATCAGGAGCACAGACTCCAAGTCTAAGTCTTCATTCTTGCACATT +TTTTAAAAATTTTGTTATGTGTTCTGGATACTATTTCCTTATGAGATATA +AGTTTAAAAGCCTTTCTGTGGATTGCCTTGCCTTTGTTGTTGTTGTTTGT +TTTGTTTTGTTTTGTTGAGACAGGTCTCTCTATGTAGCCTTGACTGTCCT +GAAAATCACTCTGTAGACCAGGCTGGCCTGGAACTCAGAGATCTGCCTGC +TTCTGCTTTTCAAGTGCTGATATTAAATGTATGTGCCACCACTGCCAGGC +TAAGATTGTTCTTTCAATTTCTTTTTTTGTTTTCTTTTGAGATCAAAGTT +TGCTATGTACTTTTGGCTGGCCTGGTATATTGTGTAGTCTAAGTTGGCTT +CAAATCTTCATGGCACAGATTCCCAAGTACTGGGACCATAGGTATGGCCC +ATCACAGTGGGGGGTTGGGGGGGCCAGTACATCTATCTCTTGAATGGTGT +GGAGTGTATATATGTGTTAGGGGTTTGCAGAGGCCAAAAGAATATTGAGT +GTCTTCCTCTATTGCTCGCCACTTCTCTGAATAAACCTAAAGTTACCAAT +GGATTTCTAGTAAGCTGACTGACCAGCAAATATTGGGGATCTGTCTGTCC +CTGTTCACCATAGTGAGGTTACAGACGTGAATAACCACACCCAGTTTTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA +CCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAA diff -r 2beaae16651e -r 0183cad9d13b seqtk_telo/test-data/out_bed_sample diff -r 2beaae16651e -r 0183cad9d13b tacrev/tacrev.bash.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tacrev/tacrev.bash.txt Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,3 @@ +#raw +tac | rev +#end raw diff -r 2beaae16651e -r 0183cad9d13b tacrev/tacrev.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tacrev/tacrev.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,37 @@ + + + + + + + +$tacrev_reversed_output]]> + + + + + + + + + + + + + + + + + 10.1093/bioinformatics/bts573 + + + diff -r 2beaae16651e -r 0183cad9d13b tacrev/tacrev_reversed_output_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tacrev/tacrev_reversed_output_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1210 @@ +)(niam +:"__niam__" == __eman__ fi + + +)(fnocloot_etadpu.ft +)(raTlooTekam.ft +)(etadpu_tset_omenalp.ft +)(looTekam.ft +)(lmydehSetirw.ft +)sgra(yrotcaF_looT = ft +".eno ylppus esaelP .eman loot a tuohtiw loot a dliub tonnac yrotcaFlooT sihT ##" ,eman_loot.sgra tressa +) +)resu_dab.sgra ,resu_dab.sgra( % +'elif noitarugifnoc yxalaG lmy.yxalag eht ni "sresu_nimda" ot s% sdda nimda +\ yxalaG litnu loot siht esu ot dezirohtua TON si s% :DESIROHTUANU' +( ,resu_dab.sgra ton tressa +:ylno_nimda.sgra fi +)(sgra_esrap.resrap = sgra +__rid_toor__$ ot evitaler # )"lmx.fnoc_loot/gifnoc"=tluafed ,"htap_fnoc_loot--"(a +__rid_toor__$ ot evitaler # )"sloot"=tluafed ,"sloot_lacol--"(a +)enoN=tluafed ,"tuo_loot_detsetnu--"(a +)"eurt_erots"=noitca ,eurT=tluafed ,"ylno_nimda--"(a +)eslaF=tluafed ,"eurt_erots" = noitca ,"galf_llatsni--"(a +)"eurt_erots"=noitca ,eslaF=tluafed ,"stset_edulcni--"(a +)][=tluafed ,"dneppa"=noitca ,"noitcelloc--"(a +)"vnev_yxalag/"=tluafed ,"vnev_yxalag--"(a +)"lartnec-yxalag/"=tluafed ,"toor_yxalag--"(a +)"tuoft/."=tluafed ,"tuoft--"(a +)"lanoitisop"=tluafed ,"ssapmarap--"(a +)eslaF=tluafed ,"eurt_erots"=noitca ,"sretemarap_lanoitidda_tide--"(a +)][=tluafed ,"dneppa"=noitca ,"sretemarap_txettceles--"(a +)][=tluafed ,"dneppa"=noitca ,"sretemarap_lanoitidda--"(a +)enoN=tluafed ,"edirrevo_tset--"(a +)enoN=tluafed ,"edirrevo_dnammoc--"(a +)enoN=tluafed ,"snoitatic--"(a +)"10.0"=tluafed ,"noisrev_loot--"(a +)enoN=tluafed ,"csed_loot--"(a +)enoN=tluafed ,"txet_pleh--"(a +)enoN=tluafed ,"resu_dab--"(a +)"nwonknU"=tluafed ,"liame_resu--"(a +)"dneppa"=noitca ,][=tluafed ,"selif_tuptuo--"(a +)"dneppa"=noitca ,][=tluafed ,"selif_tupni--"(a +)enoN=tluafed ,"rid_loot--"(a +)"lootwen"=tluafed ,"eman_loot--"(a +)enoN=tluafed ,"segakcap--"(a +)enoN=tluafed ,"exesys--"(a +)enoN=tluafed ,"xiffus_resu_lc--"(a +)enoN=tluafed ,"tset_yrotsih--"(a +)enoN=tluafed ,"htap_tpircs--"(a +tnemugra_dda.resrap = a +)(resraPtnemugrA.esrapgra = resrap +""" + +lmx.loot esoprup laiceps a yb dellac eb ot stcepxe tI +.repparw yxalaG a si sihT +""" +:)(niam fed + +)(esolc.tuot # +)dmc_nur(dneppa.ilc # +]" && " ,eman_vne.fles ,"etavitca" ,"adnoc"[ = ilc # +) # +,tuot=tuodts # +,tuot=rredts # +,ridtuoloot.fles=dwc # +,eslaF=llehs # +,llc # +(nur.ssecorpbus = p # +])tsil_ped(nioj.' ' ,eman_vne.fles ,"n-" ,"etaerc" ,"adnoc"[ = ilc # +)"w" ,golt.fles(nepo = tuot # +:esle # +)"a" ,golt.fles(nepo = tuot # +:)golt.fles(stsixe.htap.so fi # +)emdneppax(dneppa.xiffuslcx # +]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax # +:esle # +]]"emanelifni"[p % "s%$ <" ,]"emanelifni"[p ,"999"[ = emdneppax # # +:xiffuslcx.fles ni e rof # + ++ lclmx.fles ni e rof # +)tsil_ped(nioj.'-' = eman_vne.fles # +)(tros.tsil_ped # +""" # + + +lebab diortsa 3.71.0=ypics 9.3=nohtyp vneym n- etaerc adnoc # + +500a8f50602aa9ddddf3b34236190956b800b0d1:983b81d3ac50b5d66d20e4deb0d3c51e59383473-2v-dellum # +41.4.0=lmxyxalag,0.71.0=dnelboib hsah-dellum $yxalag/love/:trgwen-ssor@yxalag )vnev( # +""" # +:)tsil_ped ,fles(vne_adnoc_ekam fed # + +lavter nruter # +)(lmtHekam.fles # +:LMTH_ekam.stpo.fles fi # +)(esolc.ots # +:rid_tuptuo.stpo.fles fi # +)(tiaw.p = lavter # +)eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +:esle # +)rid_tuptuo.stpo.fles=dwc,ots=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +)(hsulf.ots # +)s(etirw.ots # +)'w',golt.fles(nepo = ots # +)lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##' = s # +:rid_tuptuo.stpo.fles fi # +""" # +elifs.fles esu os hsab rof - esu tonnac # +""" # +:)fles(hsaBnur fed # + +lavter nruter # +)(lmtHekam.fles # +:LMTH_ekam.stpo.fles fi # +)rre,lavter( % 's%n\:htiw denruter d% edoc rorre ##' ,rredts.sys >> tnirp # +melborp # :rre dna 0 >< lavter fi # +)(daer.)'r',gole.fles(nepo = rre # +)(esolc.ets # +)(esolc.ots # +:rid_tuptuo.stpo.fles fi # +)(tiaw.p = lavter # +)(esolc.nidts.p # +)tpircs.fles(etirw.nidts.p # +)EPIP.ssecorpbus=nidts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +:esle # +)rid_tuptuo.stpo.fles=dwc,EPIP.ssecorpbus=nidts,ets=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +)(hsulf.ots # +))lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##'(etirw.ots # +)'w',golt.fles(nepo = ots # +)'w',gole.fles(nepo = ets # +:rid_tuptuo.stpo.fles fi # +:esle # +)(hsaBnur.fles = lavter # +:]'hs','hsab'[ ni reterpretni.stpo.fles dna laicepShsabtaert.fles fi # +""" # +!epip eht llif ot ton hguone llams eb tsum stpircs # +""" # +:)fles(nur fed # + + +gniggubed rof evael # )stuotset(eertmr.lituhs +)(evomer.lovt +)(evomer.reniatnoc +)(pots.reniatnoc +)(esolc.tuot +)"n\}crs{ ni eertypoc.lituhs ot nur morf tuptuo oN"f(etirw.tuot +:esle +)htap_pertsetp ,crs(elifypoc.lituhs +:)emanper(elifsi.htap.so fi +emanper = crs +)eurT=ko_tsixe_srid ,"." ,crs(eertypoc.lituhs +:)crs(ridsi.htap.so fi +)"tsetp" ,stuotset(nioj.htap.so = crs +)reniatnoc ,stuotset ,ridtsed(reniatnoc_morf_ypoc.fles +)"."=rid ,"pmetft"=xiferp ,enoN=xiffus(pmetdkm.elifpmet = stuotset +)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot +]0[)(ofni_cxe.sys = e +:noitpecxE tpecxe +)lc ,tuot ,reniatnoc(nurp +:yrt +"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- }permi{ tuptuo_tset-- tset omenalp"f = lc +)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot +]0[)(ofni_cxe.sys = e +:noitpecxE tpecxe +yrotcerid atad-tset eht setadpu tub gnissim stuptuo tset esuaceb sliaf # +)lctsetp(nur_cexe.reniatnoc = _ +:yrt +"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- atad_tset_etadpu-- }permi{ tuptuo_tset-- tset omenalp"f = lctsetp +)"}ridtsed{ al- sl"f(nur_cexe.reniatnoc = _ +)"toor"=resu ,lc ,tuot ,reniatnoc(nurp +"yrotcafloot/ rekcodoib R- nwohc" = lc +)reniatnoc ,ridtsed ,ridtuoloot.fles(reniatnoc_ot_ypoc.fles +)laerx ,"tuoft" ,ridtsed(nioj.htap.so = htaptsetp +)"toor"=resu ,lc ,tuot ,reniatnoc(nurp +"*/}ridtsed{ fr- mr"f = lc +(: reniatnoc rekcodoib a no toor teg ot si ti drah woh s'taht # +)"toor"=resu ,lc ,tuot ,reniatnoc(nurp +"}ridtsed{ p- ridkm"f = lc +) +,}}"wr" :"edom" ,"yrotcafloot/" :"dnib"{ :"}emanlovt{"f{=semulov +,"rekcodoib"=resu +,eurT=hcated +,"m021 peels" +,egamiomenalp +(nur.sreniatnoc.tneilc = reniatnoc +enod era ew nehw ti yortsed dna pots lliw # +peels htiw nepo ti peek os gninnur reniatnoc eht peek ot deen # +)emanper ,ridtsed(nioj.htap.so = permi +"tsetp/yrotcafloot/" = ridtsed +eman.lovt = emanlovt +)(etaerc.semulov.tneilc = lovt +)(vne_morf.rekcod = tneilc +)emanper ,ridper.fles(nioj.htap.so = htap_pertsetp +"lmth.troper_tset_omenalp_}eman_loot.fles{"f = emanper +eman_loot.fles % "lmx.s%" = laerx +"reniatnocoib-omenalp/2rabuf/oi.yauq" = egamiomenalp +)"w" ,golt.fles(nepo = tuot +:esle +)"a" ,golt.fles(nepo = tuot +:)golt.fles(stsixe.htap.so fi + +)"n\}lc{ morf }gols{ golr tog ##"f(etirw.tuot +)lgols(nioj."n\" = gols +)"n\\"(tilps.)golr(rts = lgols +)resu=resu ,lc(nur_cexe.reniatnoc = golr +:)"rekcodoib"=resu ,lc ,tuot ,reniatnoc(nurp fed + +""" + + +sdaolnwod detaeper evas ot dellif sehcac htiw omenalp sah reniatnocoib rekcoD + +039674137-tnemmoceussi#8701/seussi/omenalp/tcejorpyxalag/moc.buhtig//:sptth .nur lufsseccus tsrif +a retfa yppahnu steg dna reniatnoc emas eht ni desu fi seicnedneped skael yltnerruc omenalp""" +:)fles(tset_rekcodoib_omenalp fed + +edocnruter.pbus nruter +)(esolc.tuot +) +)edocnruter.pbus ,eman_loot.fles( % "n\d% edocter tog - s% dellatsni" +(etirw.tuot +) +,tuot=tuodts +,tuot=rredts +,eslaF=llehs +,dwcruo.fles=dwc +,vneruo.fles=vne +,llc +(nur.ssecorpbus = pbus +))llc(nioj." " % "n\s%n\gninnur"(etirw.tuot +] +,"yrotcaFlooT" +,"lebal_noitces--" +,lru_dehsloot.sgra.fles +,"dehsloot--" +,"rabuf" +,"renwo--" +,eman_loot.fles +,"eman--" +,yek_ipa_yxalag.sgra.fles +,"a-" +,"tsetal--" +,lru_yxalag.sgra.fles +,"g-" +,"llatsni" +,"sloot-dehs" +[ = llc +)"w" ,golt.fles(nepo = tuot +:esle +)"a" ,golt.fles(nepo = tuot +:)golt.fles(stsixe.htap.so fi +""" +ti sdaolpu omenalp retfa dehsloot lacol eht morf loot wen eht daol ot siremehpe esu +""" +:)fles(daol_yxalag_hpe fed + +)(esolc.ots +) +"n\deliaf daolpu dehs dnelboiB ?tcerroc yek IPA eht dna gninnur dehsloot eht sI #######" +(etirw.ots +:rorrEnoitcennoC tpecxe +)"n\}ser{= }di{ di ser etadpu#"f(etirw.ots +) +enoN=egassem_timmoc ,htapratwen.fles=htap_llab_rat ,dit=di +(yrotisoper_etadpu.seirotisoper.st = ser +:yrt +]i[sdir = dit +)eman_loot.fles(xedni.semanr = i +:esle +)"n\}ser{=ser }dit{=dit }eman_loot.sgra.fles{ yrotisoper_etaerc#"f(etirw.ots +)enoN ,"di"(teg.ser = dit +) +,DItac=sdi_yrogetac +,enoN=lru_egapemoh +,lru_dehsloot.sgra.fles=lru_yrotisoper_etomer +,"detcirtsernu"=epyt +,csed_loot.sgra.fles=noitpircsed +,csed_loot.sgra.fles % "s%:sisponyS"=sisponys +,eman_loot.sgra.fles=eman +(yrotisoper_etaerc.seirotisoper.st = ser +]ic[sdic = DItac +)tacft(xedni.semanc = ic +:semanc ni )(pirts.tacft fi +enoN = DItac +]tacst ni x rof )"?" ,"di"(teg.x[ = sdic +]tacst ni x rof )(pirts.)"?" ,"eman"(teg.x[ = semanc +)(seirogetac_teg.seirogetac.st = tacst +:semanr ni ton eman_loot.fles fi +"sloot detareneg yrotcaFlooT" = tacft +]soper ni x rof )"?" ,"di"(teg.x[ = sdir +]soper ni x rof )"?" ,"eman"(teg.x[ = semanr +)(seirotisoper_teg.seirotisoper.st = soper +) +,eslaF=yfirev +,yek_ipa_dehsloot.sgra.fles=yek +,lru_dehsloot.sgra.fles=lru +(ecnatsnIdehSlooT.dehsloot = st + +)"w" ,golt.fles(nepo = ots +:esle +)"a" ,golt.fles(nepo = ots +:)golt.fles(stsixe.htap.so fi +""" + +gnitsixe etadpu ro +yrotisoper wen etaerc ot dnelboib esu +""" +:)fles(daoLdehs fed + + + + + + +)eurT=tnirp_ytterp ,htapct(etirw.eert +)"elif",noitcesFT(ybnerdlihctros +)}eliflmx :"elif"{ ,"loot" ,noitcesFT(tnemelEbuS.TE +wen # :sloot_fnoc ni ton eliflmx fi +]sloot_ruo ni x rof ]"elif"[birtta.x[ = sloot_fnoc +)"loot"(lladnif.noitcesFT = sloot_ruo +!pot eht ta # )noitcesFT ,0(tresni.toor +)}"slooT lacoL":"eman" ,"slootlacol":"di"{ ,"noitces"(tnemelE.TE = noitcesFT +:FTsah ton fi +]0[e = noitcesFT +eurT = FTsah +:0 > )e(nel fi +)"noitces"(lladnif.toor = e +eslaF = FTsah +)(toorteg.eert = toor +)resrap ,htapct(esrap.TE = eert +)eurT=txet_knalb_evomer(resraPLMX.TE = resrap +)eman_loot.fles % 'lmx.s%' ,eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = eliflmx +)'lmx.fnoc_loot_lacol/gifnoc',toor_yxalag.sgra.fles(nioj.htap.so = htapct + +))rtta(teg.dlihc :dlihc adbmal=yek ,tnerap(detros = ]:[tnerap +:)rtta ,tnerap(ybnerdlihctros fed + +:) fles(fnocloot_etadpu fed + + +edocnruter.p nruter +)(esolc.tuot +) +,tuot=tuodts +,tuot=rredts +,ridtuoloot.fles=dwc +,eslaF=llehs +,llc +(nur.ssecorpbus = p +] +,)laerx(htapsba.htap.so +,"atad_tset_etadpu--" +,toor_yxalag.sgra.fles +,"toor_yxalag--" +,)htap_tset_loot(htapsba.htap.so +,"tuptuo_tset--" +,)ridtset.fles(htapsba.htap.so +,"atad_tset--" +,"sreniatnocoib--" +,"tini_otua_adnoc--" +,"tset" +,"omenalp" +[ = llc +)"w" ,golt.fles(nepo = tuot +:esle +)"a" ,golt.fles(nepo = tuot +:)golt.fles(stsixe.htap.so fi +) +"lmth.troper_tset_omenalp_}eman_loot.fles{"f ,ridper.fles +(nioj.htap.so = htap_tset_loot +eman_loot.fles % "lmx.s%" = laerx +""" +gnitset rof elbaliava si os tnemeriuqer a si omenalp""" +:)fles(etadpu_tset_omenalp fed + + +)(esolc.ft +))"zg.dehsloot_detsetnu_}eman_loot.fles{"f ,ridtuoloot.fles(nioj.htap.so ,htapratwen.fles(ypoc.lituhs +) +,noitcnuf_edulcxe=retlif +,eman_loot.fles=emancra +,ridtuoloot.fles=eman +(dda.ft +)"zg:w" ,htapratwen.fles(nepo.elifrat = ft +) +)ridtset.fles ,tsedt( % +".s% nur omenalp retfa ridtset ni dnuof ton s% elif tuptuo - deliaf evah yam looT###" +(tnirp +:liaf_troper fi +:esle +)tsed ,crs(elifypoc.lituhs +))]'tamrof'[p,emano( % "s%.elpmas.s%" ,ridper.fles(nioj.htap.so = tsed +)tsedt ,crs(elifypoc.lituhs +:)crs(elifsi.htap.so fi +:)tsedt(elifsi.htap.so ton fi +)emano ,ridtset.fles(nioj.htap.so = crs +)emano % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsedt +]"eman"[p = emano +:seliftuo.fles ni p rof + +ofnirat esle )emedulcxe(htiwsdne.emanelif fi enoN nruter +eman.ofnirat = emanelif +:)ofnirat(noitcnuf_edulcxe fed + +"lmth.troper_tset_omenalp_" = emedulcxe +"""llabrat eht eraperp dna atad-tset otni stuptuo evom""" +:)eslaF=liaf_troper ,fles(raTlooTekam fed + +)eurT=ko_tsixe_srid ,tsed,ridtuoloot.fles(eertypoc.lituhs +)eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = tsed +)tsed ,htp(elifypoc.lituhs +) +)]"tamrof"[p ,]"emanelifni"[p( % "s%.elpmas_s%" ,ridper.fles +(nioj.htap.so = tsed +)tsed ,htp(elifypoc.lituhs +)]"emanelifni"[p % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsed +]"eman"[p = htp +:selifni.fles ni p rof +)tuox ,laerx(elifypoc.lituhs +)laerx ,ridper.fles(nioj.htap.so = tuox +)tuox ,laerx(elifypoc.lituhs +)laerx ,ridtuoloot.fles(nioj.htap.so = tuox +eman_loot.fles % "lmx.s%" = laerx +)emants ,elifs.fles(elifypoc.lituhs +:)emants(stsixe.htap.so ton fi +)elifs.fles ,ridtuoloot.fles(nioj.htap.so = emants +:htap_tpircs.sgra.fles fi +)(LMXekam.fles +:esle +)(marapLMXoNod.fles +:0 == ssapmarap.sgra.fles fi +"""ecalp otni selpmas tupni dna slmx etirw""" +:)fles(looTekam fed + +)(esolc.flmay +)eurT=edocinu_wolla ,flmay ,tcido(pmud.lmay +} +,"slooT detareneG FT" :"yrogetac" +,csed_loot.sgra.fles :"sisponys" +,csed_loot.sgra.fles :"noitpircsed" +,"detcirtsernu" :"epyt" +,resuy :"renwo" +,eman_loot.fles :"eman" +{ = tcido +)"w" ,emanfy(nepo = flmay +)"lmy.dehs." ,ridtuoloot.fles(nioj.htap.so = emanfy +]0[)"@"(tilps.liame_resu.sgra.fles = resuy +"""omenalp rof""" +:)fles(lmydehSetirw fed + +meti yrotsih yxalag # +)"n\"(etirw.fx +)lmxe(etirw.fx +:fx sa )"w" ,eman_loot.fles % "lmx.s%"(nepo htiw +dexif = lmxe +)2trap ,)edirrevo_tset.fles(nioj."n\" ,1trap( % "s%n\s%n\s%" = dexif +]1[)">stset/<"(tilps.lmxe = 2trap +]0[)">stset<"(tilps.lmxe = 1trap +stset rof stcejbo lmxl stcepxe ti sa lmxyxalag edisni siht od tonnac # :) +edirrevo_tset.fles +( fi +detpecca RP litnu dnuora krow yraropmet # )"" ,EXEEKAF(ecalper.0lmxe = lmxe +)(tropxe.lootwen.fles = 0lmxe +))LRUyrotcaFloot( % "s% :ta tig ni ecruoS"(tnemmoc_dda.lootwen.fles +) +))(wonemit ,liame_resu.sgra.fles( % +".yrotcaF looT yxalaG eht gnisu s% ta s% yb detaerC" +(tnemmoc_dda.lootwen.fles +stset = stset.lootwen.fles +)a_tset(dneppa.stset +)pt(dneppa.a_tset +:maraptset.fles ni pt rof +)(tseT.ptxg = a_tset +)(stseT.ptxg = stset +selifgifnoc = selifgifnoc.lootwen.fles +) +))tpircSdepacse.fles(nioj."n\"=txet ,"emnur"=eman(elifgifnoC.ptxg +(dneppa.selifgifnoc +)(selifgifnoC.ptxg = selifgifnoc +:htap_tpircs.sgra.fles fi +stupnit.fles = stupni.lootwen.fles +stuptuot.fles = stuptuo.lootwen.fles +)(marapLMXod.fles +:esle +)(marapLMXoNod.fles +:"0" == ssapmarap.sgra.fles fi +stnemeriuqer = stnemeriuqer.lootwen.fles +)2(tixe.sys +) +,segakcap.sgra.fles +,"= esrap tonnac - deilppus gnirts segakcap demroflam ###" +(tnirp +:noitpecxE tpecxe +)d(dneppa.vneadnoc.fles +) +)rev ,)(pirts.gkcap ,"egakcap"(tnemeriuqeR.ptxg +(dneppa.stnemeriuqer +:gkcap fi +enoN = rev +:"" == rev fi +enoN = rev +)(pirts.d = gkcap +:esle +)(pirts.gkcap = gkcap +)(pirts.rev = rev +)":"(tilps.d = rev ,gkcap +:d ni ":" fi +)":" ,"="(ecalper.d = d +)":" ,"=="(ecalper.d = d +enoN = gkcap +enoN = rev +:)","(tilps.segakcap.sgra.fles ni d rof +:yrt +:segakcap.sgra.fles fi +][ = vneadnoc.fles +)(stnemeriuqeR.ptxg = stnemeriuqer +dts = soidts.lootwen.fles +)1dts(dneppa.dts +)(oidtS.ptxg = 1dts +)(soidtS.ptxg = dts +'"}noisrev_loot.sgra.fles{" ohce'f = dnammoc_noisrev.lootwen.fles +txetrefas = pleh.lootwen.fles +)rcs(nioj."n\" + txetrefas = txetrefas +)"n\"(dneppa.rcs +) +]:001-[rcs + +]"...... " ,"deteled ffuts - senil 003> "[ + +]001:[rcs +( = rcs +:003 > )rcs(nel fi +)"n\::tpircSn\n\" ,0(tresni.rcs +]"" > )(pirts.x fi tpircSdecaps.fles ni x rof x[ = rcs +!dewolla noitisnart # "n\------n\n\" + txetrefas = txetrefas +:0 > )txetrefas(nel fi +:htap_tpircs.sgra.fles fi +) +)liame_resu.sgra.fles( % +"n\esaelp txet pleh htiw dliuber ot )s%( rohtua loot eht ksA" +( = txetrefas +:0 == ))(pirts.txetrefas(nel fi +)]txetpleh ni x rof )x(epacse_hateehc[(nioj."n\" = txetrefas +)(senildaer.)"r" ,txet_pleh.sgra.fles(nepo = txetpleh +:txet_pleh.sgra.fles fi +"" = txetrefas +etic = snoitatic.lootwen.fles +)etica(dneppa.etic +)"375stb/scitamrofnioib/3901.01"=eulav ,"iod"=epyt(noitatiC.ptxg = etica +)(snoitatiC.ptxg = etic +lclmx.fles = edirrevo_dnammoc.lootwen.fles +:esle +elif gifnoc # edirrevo_dnammoc.fles = edirrevo_dnammoc.lootwen.fles +:edirrevo_dnammoc.fles fi +""" +...redro tcerroc otni enil dnammoc eht teg ot woH .mmmH +lmthyxalag sesU +tpircs wen eht rof repparw loot lmx yxalaG a etaerC +""" +aqon # :)fles(LMXekam fed + +)pt(dneppa.maraptset.fles +)emanwen % "elpmas_s%"=eulav ,emanwen=eman(tuptuOtseT.ptxg = pt +)tuona(dneppa.stuptuot.fles +lanoitisop_si.fles = lanoitisop.tuona +emanwen % "s%$ >" = edirrevo_enil_dnammoc.tuona +)0=sehsad_mun ,tmfwen=tamrof ,emanwen(ataDtuptuO.ptxg = tuona +]"tamrof"[]0[seliftuo.fles = tmfwen +]"eman"[]0[seliftuo.fles = emanwen +:0 > )seliftuo.fles(nel fi +)pt(dneppa.maraptset.fles +)emanwen % "elpmas_s%"=eulav ,emanwen=eman(maraPtseT.ptxg = pt +)tupnina(dneppa.stupnit.fles +eurT = lanoitisop.tupnina +emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina +) +,0=sehsad_mun +,eslaF=elpitlum +,]"tamrof"[]0[selifni.fles=tamrof +,]"pleh"[]0[selifni.fles=pleh +,bala=lebal +,eslaF=lanoitpo +,emanwen +(maraPataD.ptxg = tupnina +]"emanelifni"[]0[selifni.fles = emanwen +s1xam ,1 == )selifni.fles(nel tressa +) +)selifni.fles(rts % +"s% - deilppus selif tupni elpitlum tub 0 si ssapmarap fi tupni eno mumixaM" +( = s1xam +]"emanelifni"[]0[selifni.fles = bala +:0 == )bala(nel fi +]"lebal"[]0[selifni.fles = bala +:0 > )selifni.fles(nel fi +"""tuodts ot nidts - egakcap elyts retlif""" +:)fles(marapLMXoNod fed + +) +"!neht litnu neddir-revo eb tsum snoitcelloc rof stset - tey degrem RP eht evah ton seod noisrev lmxyxalaG :GNINRAW ####" +(tnirp +:noitpecxE tpecxe +)mrapt(dneppa.maraptset.fles +.degrem RP litnu nekorb # )emanwen(noitcelloCtuptuOtseT.ptxg = mrapt +:yrt +)tcelloc(dneppa.stuptuot.fles +)csid(dneppa.tcelloc +) +"eslaf"=elbisiv ,"}emanwen{"f=yrotcerid ,csidwen=nrettap +(stesataDrevocsiD.ptxg = csid +)dnikwen=epyt ,lebalwen=lebal ,emanwen(noitcelloCtuptuO.ptxg = tcelloc +]"revocsid"[p = csidwen +]"lebal"[p = lebalwen +]"eman"[p = emanwen +]"dnik"[p = dnikwen +:snoitcelloc.fles ni p rof +) +)emanwen ,epytwen( % +'LMXekam ni s% retemarap txettceles +\rof "s%" epyt retemarap desingocernU' +(rorrEeulaV esiar +:esle +)mrapt(dneppa.maraptset.fles +)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt +)mrapa(dneppa.stupnit.fles +)lcwen(tni = lanoitisop.mrapa +:lanoitisop_si.fles fi +lanoitisop_si.fles = lanoitisop.mrapa +)tpona(dneppa.mrapa +) +,]i[txetwen=txet +,]i[lavwen=eulav +(noitpOtceleS.ptxg = tpona +:))lavwen(nel(egnar ni i rof +) +,hsadn=sehsad_mun +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPtceleS.ptxg = mrapa +]"stxet"[p = txetwen +:"txettceles" == epytwen fi +)emanwen(hsadNteg.fles = hsadn +emanwen = lebalwen +:0 > )lebalwen(nel ton fi +]"LC"[p = lcwen +]"epyt"[p = epytwen +]"pleh"[p = plehwen +]"lebal"[p = lebalwen +]"eulav"[p = lavwen +]"eman"[p = emanwen +:raples.fles ni p rof +)mrapt(dneppa.maraptset.fles +)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt +)mrapa(dneppa.stupnit.fles +:esle +)mrapt(dneppa.maraptset.fles +)2mrapt(dneppa.mrapt +)lavwen=eulav ,emanwen(maraPtseT.ptxg = 2mrapt +)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt +)eper(dneppa.stupnit.fles +)mrapa(dneppa.eper +) +"dedeen sa }lebalwen{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman +(taepeR.ptxg = eper +:sper fi +)lcdlo(tni = lanoitisop.mrapa +:lanoitisop_si.fles fi +lanoitisop_si.fles = lanoitisop.mrapa +) +)emanwen ,epytwen( % +'LMXekam ni s% retemarap lanoitidda +\rof "s%" epyt retemarap desingocernU' +(rorrEeulaV esiar +:esle +) +,hsadn=sehsad_mun +,lavwen=eulav +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPnaelooB.ptxg = mrapa +:"naeloob" == epytwen file +) +,hsadn=sehsad_mun +,lavwen=eulav +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPtaolF.ptxg = mrapa +:"taolf" == epytwen file +) +,hsadn=sehsad_mun +,lavwen=eulav +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPregetnI.ptxg = mrapa +:"regetni" == epytwen file +) +,hsadn=sehsad_mun +,lavwen=eulav +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPtxeT.ptxg = mrapa +:"txet" == epytwen fi +)emanwen(hsadNteg.fles = hsadn +emanwen = lebalwen +:0 > )lebalwen(nel ton fi +"1" == ]"taeper"[p = sper +]"LCgiro"[p = lcdlo +]"LC"[p = lcwen +]"epyt"[p = epytwen +]"pleh"[p = plehwen +]"lebal"[p = lebalwen +]"eulav"[p = lavwen +]"eman"[p = emanwen +:rapdda.fles ni p rof +)mrapt(dneppa.maraptset.fles +)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = mrapt +)tupnina(dneppa.stupnit.fles +:esle +)mrapt(dneppa.maraptset.fles +)2mrapt(dneppa.mrapt +)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = 2mrapt +)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt +)eper(dneppa.stupnit.fles +)tupnina(dneppa.eper +) +"dedeen sa }bala{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman +(taepeR.ptxg = eper +:sper fi +emanwen % "s%$" = edirrevo_enil_dnammoc.tupnina +)]"LCgiro"[p(tni = lanoitisop.tupnina +:esle +emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina +8999999 = lanoitisop.tupnina +:"NIDTS" == )(reppu.]"LCgiro"[p fi +:lanoitisop_si.fles fi +lanoitisop_si.fles = lanoitisop.tupnina +) +,hsadn=sehsad_mun +,eslaF=elpitlum +,tmfwen=tamrof +,]"pleh"[p=pleh +,bala=lebal +,eslaF=lanoitpo +,emanwen +(maraPataD.ptxg = tupnina +]"lebal"[p = bala +:esle +]"LC"[p = bala +:0 > )]"lebal"[p(nel ton fi +"1" == )"0" ,"taeper"(teg.p = sper +)emanwen(hsadNteg.fles = hsadn +]"tamrof"[p = tmfwen +]"emanelifni"[p = emanwen +:selifni.fles ni p rof +)pt(dneppa.maraptset.fles +) +,c=erapmoc +,emanwen % "elpmas_s%"=eulav +,emanwen=eman +(tuptuOtseT.ptxg = pt +tset = c +:esle +) +,carf_atled=carf_atled +,atled=atled +,c=erapmoc +,emanwen % "elpmas_s%"=eulav +,emanwen=eman +(tuptuOtseT.ptxg = pt +enoN = carf_atled +)nt(tni = atled +:esle +))nt(taolf ,0.1(nim = carf_atled +enoN = atled +:nt ni "." fi +:"" > nt fi +)(pirts.]1[)":"(tilps.tset = nt +"ezis_mis" = c +:)"ezis_mis"(htiwstrats.tset file +) +,dl=ffid_senil +,c=erapmoc +,emanwen % "elpmas_s%"=eulav +,emanwen=eman +(tuptuOtseT.ptxg = pt +)]1[)":"(tilps.tset(tni = dl +:tigidsi.]1[)":"(tilps.tset fi +0 = dl +"ffid" = c +:)"ffid"(htiwstrats.)(pirts.tset fi +:"" > )(pirts.tset fi +enoN = dl +)mrapa(dneppa.stuptuot.fles +emanwen % "s%$" = edirrevo_enil_dnammoc.mrapa +)lcdlo(tni = lanoitisop.mrapa +:esle +emanwen % "s%$ >" = edirrevo_enil_dnammoc.mrapa +9999999 = lanoitisop.mrapa +:"TUODTS" == )(reppu.lcdlo fi +:lanoitisop_si.fles fi +lanoitisop_si.fles = lanoitisop.mrapa +) +emanwen=lebal ,hsadn=sehsad_mun ,tmfwen=tamrof ,emanwen=eman +(ataDtuptuO.ptxg = mrapa +)lcwen(hsadNteg.fles = hsadn +)(pirts.tset = tset +]"LCgiro"[p = lcdlo +]"tset"[p = tset +]"LC"[p = lcwen +]"tamrof"[p = tmfwen +]"eman"[p = emanwen +:seliftuo.fles ni p rof +"""loot ot stnemele dedeen lla ddA""" +aqon # :)fles(marapLMXod fed + +hsadn nruter +1 = hsadn +:2 < )emanwen(nel fi +2 = hsadn +:esle +0 = hsadn +:lanoitisop_si.fles fi +:)emanwen ,fles(hsadNteg fed + +)c(LCXa +:plc ni c rof +)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc +dne LC YID # :xiffus_resu_lc.sgra.fles fi +)lc(LCXa +:tceriderlcxtsal.fles ni lc rof +:tceriderlcxtsal.fles fi +)v(LCXa +)k(LCXa +k % "s%--" = k +:esle +k % "s%-" = k +:1 == ))(pirts.k(nel fi +:esle +)k(LCXa +edirrevok = k +:"" > edirrevok fi +:xiffuslcx.fles ni )edirrevok ,v ,k( rof + +mrof deman esrapgra ni smarap neht stupni # +dneppa.lclmx.fles = LCXa +"""elyts esrapgra""" +:)fles(esrapgralc fed + +)c(LCXa +:plc ni c rof +)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc +dne LC YID # :xiffus_resu_lc.sgra.fles fi +)lc(LCXa +:tceriderlcxtsal.fles ni lc rof +:tceriderlcxtsal.fles fi +)v(LCXa +:xiffuslcx.fles ni )edirrevok ,v ,k( rof +dneppa.lclmx.fles = LCXa +smarap neht redro ni stupni # +:)fles(lanoitisoplc fed + +pdda = ]i[rapdda.fles +]"LC"[pdda = ]"LCgiro"[pdda +)p(ypoc.ypoc = pdda +:)rapdda.fles(etaremune ni p ,i rof +pftuo = ]i[seliftuo.fles +ypoc peek # ]"LC"[pftuo = ]"LCgiro"[pftuo +)p(ypoc.ypoc = pftuo +:)seliftuo.fles(etaremune ni p ,i rof +pfni = ]i[selifni.fles +]"LC"[pfni = ]"emanelifni"[pfni +:esle +)"_" ," "(ecalper.]"lebal"[pfni = ]"emanelifni"[pfni +:]"0" ,"lanoitisop"[ ni ssapmarap.sgra.fles fi +]"LC"[pfni = ]"LCgiro"[pfni +)p(ypoc.ypoc = pfni +:)selifni.fles(etaremune ni p ,i rof +) +,]"eman"[p +,]"LC"[p +( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)(tigidsi.] +"LC" +[p tressa +:)rapdda.fles(etaremune ni p ,i rof +) +,]"eman"[p +,]"LC"[p +( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,) +"TUODTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p +( tressa +:)seliftuo.fles(etaremune ni p ,i rof +) +,]"lebal"[p +,]"LC"[p +( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,) +"NIDTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p +( tressa +:)selifni.fles(etaremune ni p ,i rof +:"lanoitisop" == ssapmarap.sgra.fles fi +"""lanidro ciremun rieht yb detacilpmoc era sretemarap lanoitisop """ +:)fles(rappunaelc fed + +)(esolc.tcafitra +))"8ftu" ,tpircs.fles(setyb(etirw.tcafitra +)"bw" ,tra(nepo = tcafitra +)]0[emetucexe.fles ,eman_loot.fles( % "s%.s%" = tra +xr = tpircSdepacse.fles +)"war dne#"(dneppa.xr +)"war#" ,0(tresni.xr +]"" > )(pirts.x fi xr ni x rof "}x{ "f[ = tpircSdecaps.fles +)(esolc.tpircst +)tpircs.fles(etirw.tpircst +)"w" ,elifs.fles(nepo = tpircst +) +)]0[emetucexe.fles( % "s%_"=xiffus ,eman_loot.fles=xiferp +(pmetskm.elifpmet = elifs.fles ,eldnahf +)xr(nioj."n\" = tpircs.fles +"nur tonnaC .ytpme si tpircs deilppuS" ,0 > )kcehcxr(nel tressa +]"" > )(pirts.x fi xr ni x rof )(pirts.x[ = kcehcxr +]xr ni x rof )(pirtsr.x[ = xr +)(senildaer.)"r" ,htap_tpircs.sgra.fles(nepo = xr +:)fles(tpircSperp fed + +xiffuslcx = xiffuslcx.fles +)(tros.xiffuslcx +)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +:raples.fles ni p rof +)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +]"edirrevo"[p = revo +) +"!senil dnammoc retemarap lanoitisop ni dettimrep ton - derongi }man{ rof staepeR .gninraw ###"f +(tnirp +:per fi +esnes ON ekam staeper # "1" == ]"taeper"[p = per +]"eman"[p = man +:rapdda.fles ni p rof +)]"" ,]"eman"[p % "s%$" ,]"LC"[p[(dneppa.xiffuslcx +:esle +]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles +:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi +:)seliftuo.fles(etaremune ni p ,i rof +)emdneppax(dneppa.xiffuslcx +]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax +:esle +] +,]"emanelifni"[p % "s%$ <" +,]"emanelifni"[p +,"999" +[ = emdneppax +:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi +:)selifni.fles(etaremune ni p ,i rof +][ = xiffuslcx +:)fles(soplcperp fed + +xiffuslcx = xiffuslcx.fles +)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +:raples.fles ni p rof +)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +]"edirrevo"[p = revo +:esle +'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo +:per fi +"1" == ]"taeper"[p = per +]"eman"[p = man +:rapdda.fles ni p rof +)]"" ,]"eman"[p % "s%$" ,]"eman"[p[(dneppa.xiffuslcx +:esle +]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles +:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi +:)seliftuo.fles(etaremune ni p ,i rof +)emdneppax(dneppa.xiffuslcx +]revo ,]"LC"[p % "s%$" ,]"LC"[p[ = emdneppax +'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo +:per fi +"" = revo +"1" == ]"taeper"[p = per +:esle +] +,man % "s%$ <" +,man +,man +[ = emdneppax +:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi +]"emanelifni"[p = man +:)selifni.fles(etaremune ni p ,i rof +][ = xiffuslcx +:)fles(pgraperp fed + +)c(LCXa +:plc ni c rof +)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc +dne LC YID # :xiffus_resu_lc.sgra.fles fi +)]"eman"[]0[seliftuo.fles % "s%$"(LCXa +)">"(LCXa +:0 > )seliftuo.fles(nel fi +)]"emanelifni"[]0[selifni.fles % "s%$"(LCXa +)"<"(LCXa +:0 > )selifni.fles(nel fi +dneppa.lclmx.fles = LCXa +"""o/i rof > dna < sesu - staeper ro sretemarap on""" +:)fles(elpmislc fed + +)(esrapgralc.fles +)(pgraperp.fles +:esle +)(lanoitisoplc.fles +)(soplcperp.fles +:"lanoitisop" == ssapmarap.sgra.fles fi +:esle +)(elpmislc.fles +:"0" == ssapmarap.sgra.fles fi + +)xe(LCXa +:emetucexe.fles ni xe rof +:esle +)"emnur$"(LCXa +)xe(LCXa +:emetucexe.fles ni xe rof +:htap_tpircs.sgra.fles fi +enoN = edirrevo_tset.fles +:esle +]sots ni x rof )(pirtsr.x[ = edirrevo_tset.fles +)(senildaer.)"r" ,edirrevo_tset.sgra.fles(nepo = sots +:edirrevo_tset.sgra.fles fi +enoN = edirrevo_dnammoc.fles +:esle +]socs ni x rof )(pirtsr.x[ = edirrevo_dnammoc.fles +)(senildaer.)"r" ,edirrevo_dnammoc.sgra.fles(nepo = socs +:edirrevo_dnammoc.sgra.fles fi +)(tpircSperp.fles +:htap_tpircs.sgra.fles fi +][ = maraptset.fles +)(stuptuO.ptxg = stuptuot.fles +)(stupnI.ptxg = stupnit.fles +)eman_loot.fles % 'txt.gol_nur_FT_s%',ridper.fles(nioj.htap.so = golt.fles +)ridper.fles(ridkm.so +:)ridper.fles(stsixe.htap.so ton fi +)ridtset.fles(ridkm.so +:)ridtset.fles(stsixe.htap.so ton fi +)ridtuoloot.fles(ridkm.so +:)ridtuoloot.fles(stsixe.htap.so ton fi +)"atad-tset" ,ridtuoloot.fles(nioj.htap.so = ridtset.fles +)eman_loot.fles % "zg.dehsloot_detset_ton_s%" ,ridtuoloot.fles(nioj.htap.so # tuo_loot_detsetnu.sgra = htapratwen.fles +"negloot/." = ridper.fles +"tuoft/." = ridtuoloot.fles +) +,EXEEKAF +,csed_loot.sgra.fles +,noisrev_loot.sgra.fles +,di_loot.fles +,eman_loot.fles +(looT.txg = lootwen.fles +eman_loot.fles = di_loot.fles +)eman_loot.sgra ,"" ,"+]_9-0Z-Az-a^["(bus.er = eman_loot.fles +'"esrapgra" ro "lanoitisop","0" eb tsum ssapmarap.sgra' ,] +,"lanoitisop" +,"esrapgra" +,"0" +[ ni ssapmarap.sgra tressa +dneppa.lclmx.fles = LCXa +enoN = emetucexe.fles +:esle +] +,)(pirts.]0[)":"(tilps.]0[)","(tilps.segakcap.sgra.fles +[ = emetucexe.fles +:segakcap.sgra.fles fi +:esle +] +,exesys.sgra.fles +[ = emetucexe.fles +:esle +)exesys.sgra.fles(tilps.xelhs = emetucexe.fles +:exesys.sgra.fles ni " " fi +:exesys.sgra.fles fi +"lanoitisop" == ssapmarap.sgra.fles = lanoitisop_si.fles +][ = lclmx.fles +enoN = tceriderlcxtsal.fles +)(rappunaelc.fles +sgra = sgra.fles +) +"yranoitcid a eb dluohs - demroflam si }sretemarap_txettceles.sgra{ sretemarap_txettceles--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi sretemarap_txettceles.sgra ni x rof )x(sdaol.nosj +[ = raples.fles +:yrt +) +"yranoitcid a eb dluohs - demroflam si }sretemarap_lanoitidda.sgra{ sretemarap_lanoitidda--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi sretemarap_lanoitidda.sgra ni x rof )x(sdaol.nosj +[ = rapdda.fles +:yrt +'tros emos fo tuptuo na tuohtiw liaf lliw rennur boj yxalaG ehT .deificeps snoitcelloc tuptuo ro seliftuo oN' ,0 > ))snoitcelloc.fles(nel + )seliftuo.fles(nel( tressa +) +"yranoitcid a eb dluohs - demroflam si }selif_tuptuo.sgra{ retemarap selif_tuptuo--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi selif_tuptuo.sgra ni x rof )x(sdaol.nosj +[ = seliftuo.fles +:yrt +) +"yranoitcid a eb dluohs - demroflam si })selif_tupni.sgra(rts{ retemarap selif_tupni--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi selif_tupni.sgra ni x rof )x(sdaol.nosj +[ = selifni.fles +:yrt +) +"yranoitcid a eb dluohs - demroflam si })noitcelloc.sgra(rts{ retemarap snoitcelloc--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi noitcelloc.sgra ni x rof )x(sdaol.nosj +[ = snoitcelloc.fles +:yrt +:0 > )noitcelloc.sgra(nel fi +][ = snoitcelloc.fles +)(dwcteg.so = dwcruo.fles +)'sloot_lacol',toor_yxalag.sgra(nioj.htap.so = sloot_lacol.fles +""" +noitareneg loot lmxyxalag rof dedeen stnemele eraperp dna +ereh loot eht gninnur rof lc enil dnammoc eraperp +""" +aqon # :)enoN=sgra ,fles(__tini__ fed + +""" + +lmxyxalag sesu +tpircs yrartibra na rof repparW""" +:yrotcaF_looT ssalc + + +selput_noitatic nruter +)))(pirts.]: )"xetbib"(nel[noitatic ,"xetbib"((dneppa.selput_noitatic +:esle +)))(pirts.]: )"iod"(nel[noitatic ,"iod"((dneppa.selput_noitatic +:)"iod"(htiwstrats.noitatic fi +:snoitatic ni noitatic rof +][ = selput_noitatic +])(pirts.c fi )"**YRTNE**"(tilps.txet_snoitatic ni c rof c[ = snoitatic +"""""" +:)txet_snoitatic(snoitatic_esrap fed + + +)]txet ni c rof )c ,c(teg.elbat_epacse_hateehc[(nioj."" nruter +""".txet nihtiw seititne ecudorP""" +:)txet(epacse_hateehc fed + + +}"#\\" :"#" ,"$\\" :"$"{ = elbat_epacse_hateehc + + +)))(emit.emit(emitlacol.emit ,"S%:M%:H% Y%/m%/d%"(emitfrts.emit nruter +"""gnirts a sa emit tnerruc nruter""" +:)(wonemit fed + + +.edirrevo htiw # +neve exe eht gnidneperp lmxyxalag xif ot pmub noisrev/RP a litnu siht deen # +"~~~EM~~~EVOMER~~~" = EXEEKAF +"yrotcafloot/2rabuf/moc.buhtig//:sptth" = LRUyrotcaFloot +eurT = gubed +eurT = esobrev +"2202 hcraM 4.2V" = noisrevym + +lmay tropmi + +TE sa eerte.lmxl tropmi + +ptxg sa sretemarap.loot.lmxyxalag tropmi +txg sa loot.lmxyxalag tropmi + +yxalag tropmi dnelboib morf + +emit tropmi +elifpmet tropmi +elifrat tropmi +sys tropmi +ssecorpbus tropmi +lituhs tropmi +xelhs tropmi +er tropmi +so tropmi +nosj tropmi +ltncf tropmi +ypoc tropmi +esrapgra tropmi + + + +.tset htiw loot reporp wen a snruter dna # +stuptuo tset eht setaerc ,evihcra detset-non a no omenalp snur retset ehT # +noitpoda reniatnocoib dna tnempoleved lairotut NTG fo trap sa # +llatsni/tset dna etareneg - sloot owt otni derotcafeR :2202 hcram # +# +yrotcafloot/2rabuf/moc.buhtig//:sptth # +ta emoclew sexif gub dna tnemevorpmi rof snoitseggus # +LPGL eht rednu desneciL # +devreser sthgir lla # +# +2102 yaM )moc pots liamg ta surazal pots ssor( surazal ssor thgirypoc # +# +yrotcafloot/2rabuf/moc.buhtig//:sptth ees # diff -r 2beaae16651e -r 0183cad9d13b tacrev/test-data/Input_text_file_to_be_reversed_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tacrev/test-data/Input_text_file_to_be_reversed_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1210 @@ +# see https://github.com/fubar2/toolfactory +# +# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012 +# +# all rights reserved +# Licensed under the LGPL +# suggestions for improvement and bug fixes welcome at +# https://github.com/fubar2/toolfactory +# +# march 2022: Refactored into two tools - generate and test/install +# as part of GTN tutorial development and biocontainer adoption +# The tester runs planemo on a non-tested archive, creates the test outputs +# and returns a new proper tool with test. + + + +import argparse +import copy +import fcntl +import json +import os +import re +import shlex +import shutil +import subprocess +import sys +import tarfile +import tempfile +import time + +from bioblend import galaxy + +import galaxyxml.tool as gxt +import galaxyxml.tool.parameters as gxtp + +import lxml.etree as ET + +import yaml + +myversion = "V2.4 March 2022" +verbose = True +debug = True +toolFactoryURL = "https://github.com/fubar2/toolfactory" +FAKEEXE = "~~~REMOVE~~~ME~~~" +# need this until a PR/version bump to fix galaxyxml prepending the exe even +# with override. + + +def timenow(): + """return current time as a string""" + return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) + + +cheetah_escape_table = {"$": "\\$", "#": "\\#"} + + +def cheetah_escape(text): + """Produce entities within text.""" + return "".join([cheetah_escape_table.get(c, c) for c in text]) + + +def parse_citations(citations_text): + """""" + citations = [c for c in citations_text.split("**ENTRY**") if c.strip()] + citation_tuples = [] + for citation in citations: + if citation.startswith("doi"): + citation_tuples.append(("doi", citation[len("doi") :].strip())) + else: + citation_tuples.append(("bibtex", citation[len("bibtex") :].strip())) + return citation_tuples + + +class Tool_Factory: + """Wrapper for an arbitrary script + uses galaxyxml + + """ + + def __init__(self, args=None): # noqa + """ + prepare command line cl for running the tool here + and prepare elements needed for galaxyxml tool generation + """ + self.local_tools = os.path.join(args.galaxy_root,'local_tools') + self.ourcwd = os.getcwd() + self.collections = [] + if len(args.collection) > 0: + try: + self.collections = [ + json.loads(x) for x in args.collection if len(x.strip()) > 1 + ] + except Exception: + print( + f"--collections parameter {str(args.collection)} is malformed - should be a dictionary" + ) + try: + self.infiles = [ + json.loads(x) for x in args.input_files if len(x.strip()) > 1 + ] + except Exception: + print( + f"--input_files parameter {str(args.input_files)} is malformed - should be a dictionary" + ) + try: + self.outfiles = [ + json.loads(x) for x in args.output_files if len(x.strip()) > 1 + ] + except Exception: + print( + f"--output_files parameter {args.output_files} is malformed - should be a dictionary" + ) + assert (len(self.outfiles) + len(self.collections)) > 0, 'No outfiles or output collections specified. The Galaxy job runner will fail without an output of some sort' + try: + self.addpar = [ + json.loads(x) for x in args.additional_parameters if len(x.strip()) > 1 + ] + except Exception: + print( + f"--additional_parameters {args.additional_parameters} is malformed - should be a dictionary" + ) + try: + self.selpar = [ + json.loads(x) for x in args.selecttext_parameters if len(x.strip()) > 1 + ] + except Exception: + print( + f"--selecttext_parameters {args.selecttext_parameters} is malformed - should be a dictionary" + ) + self.args = args + self.cleanuppar() + self.lastxclredirect = None + self.xmlcl = [] + self.is_positional = self.args.parampass == "positional" + if self.args.sysexe: + if " " in self.args.sysexe: + self.executeme = shlex.split(self.args.sysexe) + else: + self.executeme = [ + self.args.sysexe, + ] + else: + if self.args.packages: + self.executeme = [ + self.args.packages.split(",")[0].split(":")[0].strip(), + ] + else: + self.executeme = None + aXCL = self.xmlcl.append + assert args.parampass in [ + "0", + "argparse", + "positional", + ], 'args.parampass must be "0","positional" or "argparse"' + self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name) + self.tool_id = self.tool_name + self.newtool = gxt.Tool( + self.tool_name, + self.tool_id, + self.args.tool_version, + self.args.tool_desc, + FAKEEXE, + ) + self.tooloutdir = "./tfout" + self.repdir = "./toolgen" + self.newtarpath = args.untested_tool_out # os.path.join(self.tooloutdir, "%s_not_tested_toolshed.gz" % self.tool_name) + self.testdir = os.path.join(self.tooloutdir, "test-data") + if not os.path.exists(self.tooloutdir): + os.mkdir(self.tooloutdir) + if not os.path.exists(self.testdir): + os.mkdir(self.testdir) + if not os.path.exists(self.repdir): + os.mkdir(self.repdir) + self.tlog = os.path.join(self.repdir,'%s_TF_run_log.txt' % self.tool_name) + self.tinputs = gxtp.Inputs() + self.toutputs = gxtp.Outputs() + self.testparam = [] + if self.args.script_path: + self.prepScript() + if self.args.command_override: + scos = open(self.args.command_override, "r").readlines() + self.command_override = [x.rstrip() for x in scos] + else: + self.command_override = None + if self.args.test_override: + stos = open(self.args.test_override, "r").readlines() + self.test_override = [x.rstrip() for x in stos] + else: + self.test_override = None + if self.args.script_path: + for ex in self.executeme: + aXCL(ex) + aXCL("$runme") + else: + for ex in self.executeme: + aXCL(ex) + + if self.args.parampass == "0": + self.clsimple() + else: + if self.args.parampass == "positional": + self.prepclpos() + self.clpositional() + else: + self.prepargp() + self.clargparse() + + def clsimple(self): + """no parameters or repeats - uses < and > for i/o""" + aXCL = self.xmlcl.append + if len(self.infiles) > 0: + aXCL("<") + aXCL("$%s" % self.infiles[0]["infilename"]) + if len(self.outfiles) > 0: + aXCL(">") + aXCL("$%s" % self.outfiles[0]["name"]) + if self.args.cl_user_suffix: # DIY CL end + clp = shlex.split(self.args.cl_user_suffix) + for c in clp: + aXCL(c) + + def prepargp(self): + xclsuffix = [] + for i, p in enumerate(self.infiles): + nam = p["infilename"] + if p["origCL"].strip().upper() == "STDIN": + xappendme = [ + nam, + nam, + "< $%s" % nam, + ] + else: + rep = p["repeat"] == "1" + over = "" + if rep: + over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for' + xappendme = [p["CL"], "$%s" % p["CL"], over] + xclsuffix.append(xappendme) + for i, p in enumerate(self.outfiles): + if p["origCL"].strip().upper() == "STDOUT": + self.lastxclredirect = [">", "$%s" % p["name"]] + else: + xclsuffix.append([p["name"], "$%s" % p["name"], ""]) + for p in self.addpar: + nam = p["name"] + rep = p["repeat"] == "1" + if rep: + over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for' + else: + over = p["override"] + xclsuffix.append([p["CL"], '"$%s"' % nam, over]) + for p in self.selpar: + xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]]) + self.xclsuffix = xclsuffix + + def prepclpos(self): + xclsuffix = [] + for i, p in enumerate(self.infiles): + if p["origCL"].strip().upper() == "STDIN": + xappendme = [ + "999", + p["infilename"], + "< $%s" % p["infilename"], + ] + else: + xappendme = [p["CL"], "$%s" % p["infilename"], ""] + xclsuffix.append(xappendme) + for i, p in enumerate(self.outfiles): + if p["origCL"].strip().upper() == "STDOUT": + self.lastxclredirect = [">", "$%s" % p["name"]] + else: + xclsuffix.append([p["CL"], "$%s" % p["name"], ""]) + for p in self.addpar: + nam = p["name"] + rep = p["repeat"] == "1" # repeats make NO sense + if rep: + print( + f"### warning. Repeats for {nam} ignored - not permitted in positional parameter command lines!" + ) + over = p["override"] + xclsuffix.append([p["CL"], '"$%s"' % nam, over]) + for p in self.selpar: + xclsuffix.append([p["CL"], '"$%s"' % p["name"], p["override"]]) + xclsuffix.sort() + self.xclsuffix = xclsuffix + + def prepScript(self): + rx = open(self.args.script_path, "r").readlines() + rx = [x.rstrip() for x in rx] + rxcheck = [x.strip() for x in rx if x.strip() > ""] + assert len(rxcheck) > 0, "Supplied script is empty. Cannot run" + self.script = "\n".join(rx) + fhandle, self.sfile = tempfile.mkstemp( + prefix=self.tool_name, suffix="_%s" % (self.executeme[0]) + ) + tscript = open(self.sfile, "w") + tscript.write(self.script) + tscript.close() + self.spacedScript = [f" {x}" for x in rx if x.strip() > ""] + rx.insert(0, "#raw") + rx.append("#end raw") + self.escapedScript = rx + art = "%s.%s" % (self.tool_name, self.executeme[0]) + artifact = open(art, "wb") + artifact.write(bytes(self.script, "utf8")) + artifact.close() + + def cleanuppar(self): + """ positional parameters are complicated by their numeric ordinal""" + if self.args.parampass == "positional": + for i, p in enumerate(self.infiles): + assert ( + p["CL"].isdigit() or p["CL"].strip().upper() == "STDIN" + ), "Positional parameters must be ordinal integers - got %s for %s" % ( + p["CL"], + p["label"], + ) + for i, p in enumerate(self.outfiles): + assert ( + p["CL"].isdigit() or p["CL"].strip().upper() == "STDOUT" + ), "Positional parameters must be ordinal integers - got %s for %s" % ( + p["CL"], + p["name"], + ) + for i, p in enumerate(self.addpar): + assert p[ + "CL" + ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % ( + p["CL"], + p["name"], + ) + for i, p in enumerate(self.infiles): + infp = copy.copy(p) + infp["origCL"] = infp["CL"] + if self.args.parampass in ["positional", "0"]: + infp["infilename"] = infp["label"].replace(" ", "_") + else: + infp["infilename"] = infp["CL"] + self.infiles[i] = infp + for i, p in enumerate(self.outfiles): + outfp = copy.copy(p) + outfp["origCL"] = outfp["CL"] # keep copy + self.outfiles[i] = outfp + for i, p in enumerate(self.addpar): + addp = copy.copy(p) + addp["origCL"] = addp["CL"] + self.addpar[i] = addp + + def clpositional(self): + # inputs in order then params + aXCL = self.xmlcl.append + for (k, v, koverride) in self.xclsuffix: + aXCL(v) + if self.lastxclredirect: + for cl in self.lastxclredirect: + aXCL(cl) + if self.args.cl_user_suffix: # DIY CL end + clp = shlex.split(self.args.cl_user_suffix) + for c in clp: + aXCL(c) + + def clargparse(self): + """argparse style""" + aXCL = self.xmlcl.append + # inputs then params in argparse named form + + for (k, v, koverride) in self.xclsuffix: + if koverride > "": + k = koverride + aXCL(k) + else: + if len(k.strip()) == 1: + k = "-%s" % k + else: + k = "--%s" % k + aXCL(k) + aXCL(v) + if self.lastxclredirect: + for cl in self.lastxclredirect: + aXCL(cl) + if self.args.cl_user_suffix: # DIY CL end + clp = shlex.split(self.args.cl_user_suffix) + for c in clp: + aXCL(c) + + def getNdash(self, newname): + if self.is_positional: + ndash = 0 + else: + ndash = 2 + if len(newname) < 2: + ndash = 1 + return ndash + + def doXMLparam(self): # noqa + """Add all needed elements to tool""" + for p in self.outfiles: + newname = p["name"] + newfmt = p["format"] + newcl = p["CL"] + test = p["test"] + oldcl = p["origCL"] + test = test.strip() + ndash = self.getNdash(newcl) + aparm = gxtp.OutputData( + name=newname, format=newfmt, num_dashes=ndash, label=newname + ) + aparm.positional = self.is_positional + if self.is_positional: + if oldcl.upper() == "STDOUT": + aparm.positional = 9999999 + aparm.command_line_override = "> $%s" % newname + else: + aparm.positional = int(oldcl) + aparm.command_line_override = "$%s" % newname + self.toutputs.append(aparm) + ld = None + if test.strip() > "": + if test.strip().startswith("diff"): + c = "diff" + ld = 0 + if test.split(":")[1].isdigit: + ld = int(test.split(":")[1]) + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + lines_diff=ld, + ) + elif test.startswith("sim_size"): + c = "sim_size" + tn = test.split(":")[1].strip() + if tn > "": + if "." in tn: + delta = None + delta_frac = min(1.0, float(tn)) + else: + delta = int(tn) + delta_frac = None + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + delta=delta, + delta_frac=delta_frac, + ) + else: + c = test + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + ) + self.testparam.append(tp) + for p in self.infiles: + newname = p["infilename"] + newfmt = p["format"] + ndash = self.getNdash(newname) + reps = p.get("repeat", "0") == "1" + if not len(p["label"]) > 0: + alab = p["CL"] + else: + alab = p["label"] + aninput = gxtp.DataParam( + newname, + optional=False, + label=alab, + help=p["help"], + format=newfmt, + multiple=False, + num_dashes=ndash, + ) + aninput.positional = self.is_positional + if self.is_positional: + if p["origCL"].upper() == "STDIN": + aninput.positional = 9999998 + aninput.command_line_override = "< $%s" % newname + else: + aninput.positional = int(p["origCL"]) + aninput.command_line_override = "$%s" % newname + if reps: + repe = gxtp.Repeat( + name=f"R_{newname}", title=f"Add as many {alab} as needed" + ) + repe.append(aninput) + self.tinputs.append(repe) + tparm = gxtp.TestRepeat(name=f"R_{newname}") + tparm2 = gxtp.TestParam(newname, value="%s_sample" % newname) + tparm.append(tparm2) + self.testparam.append(tparm) + else: + self.tinputs.append(aninput) + tparm = gxtp.TestParam(newname, value="%s_sample" % newname) + self.testparam.append(tparm) + for p in self.addpar: + newname = p["name"] + newval = p["value"] + newlabel = p["label"] + newhelp = p["help"] + newtype = p["type"] + newcl = p["CL"] + oldcl = p["origCL"] + reps = p["repeat"] == "1" + if not len(newlabel) > 0: + newlabel = newname + ndash = self.getNdash(newname) + if newtype == "text": + aparm = gxtp.TextParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "integer": + aparm = gxtp.IntegerParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "float": + aparm = gxtp.FloatParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "boolean": + aparm = gxtp.BooleanParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + else: + raise ValueError( + 'Unrecognised parameter type "%s" for\ + additional parameter %s in makeXML' + % (newtype, newname) + ) + aparm.positional = self.is_positional + if self.is_positional: + aparm.positional = int(oldcl) + if reps: + repe = gxtp.Repeat( + name=f"R_{newname}", title=f"Add as many {newlabel} as needed" + ) + repe.append(aparm) + self.tinputs.append(repe) + tparm = gxtp.TestRepeat(name=f"R_{newname}") + tparm2 = gxtp.TestParam(newname, value=newval) + tparm.append(tparm2) + self.testparam.append(tparm) + else: + self.tinputs.append(aparm) + tparm = gxtp.TestParam(newname, value=newval) + self.testparam.append(tparm) + for p in self.selpar: + newname = p["name"] + newval = p["value"] + newlabel = p["label"] + newhelp = p["help"] + newtype = p["type"] + newcl = p["CL"] + if not len(newlabel) > 0: + newlabel = newname + ndash = self.getNdash(newname) + if newtype == "selecttext": + newtext = p["texts"] + aparm = gxtp.SelectParam( + newname, + label=newlabel, + help=newhelp, + num_dashes=ndash, + ) + for i in range(len(newval)): + anopt = gxtp.SelectOption( + value=newval[i], + text=newtext[i], + ) + aparm.append(anopt) + aparm.positional = self.is_positional + if self.is_positional: + aparm.positional = int(newcl) + self.tinputs.append(aparm) + tparm = gxtp.TestParam(newname, value=newval) + self.testparam.append(tparm) + else: + raise ValueError( + 'Unrecognised parameter type "%s" for\ + selecttext parameter %s in makeXML' + % (newtype, newname) + ) + for p in self.collections: + newkind = p["kind"] + newname = p["name"] + newlabel = p["label"] + newdisc = p["discover"] + collect = gxtp.OutputCollection(newname, label=newlabel, type=newkind) + disc = gxtp.DiscoverDatasets( + pattern=newdisc, directory=f"{newname}", visible="false" + ) + collect.append(disc) + self.toutputs.append(collect) + try: + tparm = gxtp.TestOutputCollection(newname) # broken until PR merged. + self.testparam.append(tparm) + except Exception: + print( + "#### WARNING: Galaxyxml version does not have the PR merged yet - tests for collections must be over-ridden until then!" + ) + + def doNoXMLparam(self): + """filter style package - stdin to stdout""" + if len(self.infiles) > 0: + alab = self.infiles[0]["label"] + if len(alab) == 0: + alab = self.infiles[0]["infilename"] + max1s = ( + "Maximum one input if parampass is 0 but multiple input files supplied - %s" + % str(self.infiles) + ) + assert len(self.infiles) == 1, max1s + newname = self.infiles[0]["infilename"] + aninput = gxtp.DataParam( + newname, + optional=False, + label=alab, + help=self.infiles[0]["help"], + format=self.infiles[0]["format"], + multiple=False, + num_dashes=0, + ) + aninput.command_line_override = "< $%s" % newname + aninput.positional = True + self.tinputs.append(aninput) + tp = gxtp.TestParam(name=newname, value="%s_sample" % newname) + self.testparam.append(tp) + if len(self.outfiles) > 0: + newname = self.outfiles[0]["name"] + newfmt = self.outfiles[0]["format"] + anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0) + anout.command_line_override = "> $%s" % newname + anout.positional = self.is_positional + self.toutputs.append(anout) + tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname) + self.testparam.append(tp) + + def makeXML(self): # noqa + """ + Create a Galaxy xml tool wrapper for the new script + Uses galaxyhtml + Hmmm. How to get the command line into correct order... + """ + if self.command_override: + self.newtool.command_override = self.command_override # config file + else: + self.newtool.command_override = self.xmlcl + cite = gxtp.Citations() + acite = gxtp.Citation(type="doi", value="10.1093/bioinformatics/bts573") + cite.append(acite) + self.newtool.citations = cite + safertext = "" + if self.args.help_text: + helptext = open(self.args.help_text, "r").readlines() + safertext = "\n".join([cheetah_escape(x) for x in helptext]) + if len(safertext.strip()) == 0: + safertext = ( + "Ask the tool author (%s) to rebuild with help text please\n" + % (self.args.user_email) + ) + if self.args.script_path: + if len(safertext) > 0: + safertext = safertext + "\n\n------\n" # transition allowed! + scr = [x for x in self.spacedScript if x.strip() > ""] + scr.insert(0, "\n\nScript::\n") + if len(scr) > 300: + scr = ( + scr[:100] + + [" >300 lines - stuff deleted", " ......"] + + scr[-100:] + ) + scr.append("\n") + safertext = safertext + "\n".join(scr) + self.newtool.help = safertext + self.newtool.version_command = f'echo "{self.args.tool_version}"' + std = gxtp.Stdios() + std1 = gxtp.Stdio() + std.append(std1) + self.newtool.stdios = std + requirements = gxtp.Requirements() + self.condaenv = [] + if self.args.packages: + try: + for d in self.args.packages.split(","): + ver = None + packg = None + d = d.replace("==", ":") + d = d.replace("=", ":") + if ":" in d: + packg, ver = d.split(":") + ver = ver.strip() + packg = packg.strip() + else: + packg = d.strip() + ver = None + if ver == "": + ver = None + if packg: + requirements.append( + gxtp.Requirement("package", packg.strip(), ver) + ) + self.condaenv.append(d) + except Exception: + print( + "### malformed packages string supplied - cannot parse =", + self.args.packages, + ) + sys.exit(2) + self.newtool.requirements = requirements + if self.args.parampass == "0": + self.doNoXMLparam() + else: + self.doXMLparam() + self.newtool.outputs = self.toutputs + self.newtool.inputs = self.tinputs + if self.args.script_path: + configfiles = gxtp.Configfiles() + configfiles.append( + gxtp.Configfile(name="runme", text="\n".join(self.escapedScript)) + ) + self.newtool.configfiles = configfiles + tests = gxtp.Tests() + test_a = gxtp.Test() + for tp in self.testparam: + test_a.append(tp) + tests.append(test_a) + self.newtool.tests = tests + self.newtool.add_comment( + "Created by %s at %s using the Galaxy Tool Factory." + % (self.args.user_email, timenow()) + ) + self.newtool.add_comment("Source in git at: %s" % (toolFactoryURL)) + exml0 = self.newtool.export() + exml = exml0.replace(FAKEEXE, "") # temporary work around until PR accepted + if ( + self.test_override + ): # cannot do this inside galaxyxml as it expects lxml objects for tests + part1 = exml.split("")[0] + part2 = exml.split("")[1] + fixed = "%s\n%s\n%s" % (part1, "\n".join(self.test_override), part2) + exml = fixed + with open("%s.xml" % self.tool_name, "w") as xf: + xf.write(exml) + xf.write("\n") + # galaxy history item + + def writeShedyml(self): + """for planemo""" + yuser = self.args.user_email.split("@")[0] + yfname = os.path.join(self.tooloutdir, ".shed.yml") + yamlf = open(yfname, "w") + odict = { + "name": self.tool_name, + "owner": yuser, + "type": "unrestricted", + "description": self.args.tool_desc, + "synopsis": self.args.tool_desc, + "category": "TF Generated Tools", + } + yaml.dump(odict, yamlf, allow_unicode=True) + yamlf.close() + + def makeTool(self): + """write xmls and input samples into place""" + if self.args.parampass == 0: + self.doNoXMLparam() + else: + self.makeXML() + if self.args.script_path: + stname = os.path.join(self.tooloutdir, self.sfile) + if not os.path.exists(stname): + shutil.copyfile(self.sfile, stname) + xreal = "%s.xml" % self.tool_name + xout = os.path.join(self.tooloutdir, xreal) + shutil.copyfile(xreal, xout) + xout = os.path.join(self.repdir, xreal) + shutil.copyfile(xreal, xout) + for p in self.infiles: + pth = p["name"] + dest = os.path.join(self.testdir, "%s_sample" % p["infilename"]) + shutil.copyfile(pth, dest) + dest = os.path.join( + self.repdir, "%s_sample.%s" % (p["infilename"], p["format"]) + ) + shutil.copyfile(pth, dest) + dest = os.path.join(self.local_tools, self.tool_name) + shutil.copytree(self.tooloutdir,dest, dirs_exist_ok=True) + + def makeToolTar(self, report_fail=False): + """move outputs into test-data and prepare the tarball""" + excludeme = "_planemo_test_report.html" + + def exclude_function(tarinfo): + filename = tarinfo.name + return None if filename.endswith(excludeme) else tarinfo + + for p in self.outfiles: + oname = p["name"] + tdest = os.path.join(self.testdir, "%s_sample" % oname) + src = os.path.join(self.testdir, oname) + if not os.path.isfile(tdest): + if os.path.isfile(src): + shutil.copyfile(src, tdest) + dest = os.path.join(self.repdir, "%s.sample.%s" % (oname,p['format'])) + shutil.copyfile(src, dest) + else: + if report_fail: + print( + "###Tool may have failed - output file %s not found in testdir after planemo run %s." + % (tdest, self.testdir) + ) + tf = tarfile.open(self.newtarpath, "w:gz") + tf.add( + name=self.tooloutdir, + arcname=self.tool_name, + filter=exclude_function, + ) + shutil.copy(self.newtarpath, os.path.join(self.tooloutdir, f"{self.tool_name}_untested_toolshed.gz")) + tf.close() + + + def planemo_test_update(self): + """planemo is a requirement so is available for testing + """ + xreal = "%s.xml" % self.tool_name + tool_test_path = os.path.join( + self.repdir, f"{self.tool_name}_planemo_test_report.html" + ) + if os.path.exists(self.tlog): + tout = open(self.tlog, "a") + else: + tout = open(self.tlog, "w") + cll = [ + "planemo", + "test", + "--conda_auto_init", + "--biocontainers", + "--test_data", + os.path.abspath(self.testdir), + "--test_output", + os.path.abspath(tool_test_path), + "--galaxy_root", + self.args.galaxy_root, + "--update_test_data", + os.path.abspath(xreal), + ] + p = subprocess.run( + cll, + shell=False, + cwd=self.tooloutdir, + stderr=tout, + stdout=tout, + ) + tout.close() + return p.returncode + + + def update_toolconf(self ): + + def sortchildrenby(parent, attr): + parent[:] = sorted(parent, key=lambda child: child.get(attr)) + + tcpath = os.path.join(self.args.galaxy_root,'config/local_tool_conf.xml') + xmlfile = os.path.join(self.local_tools, self.tool_name, '%s.xml' % self.tool_name) + parser = ET.XMLParser(remove_blank_text=True) + tree = ET.parse(tcpath, parser) + root = tree.getroot() + hasTF = False + e = root.findall("section") + if len(e) > 0: + hasTF = True + TFsection = e[0] + if not hasTF: + TFsection = ET.Element("section", {"id":"localtools", "name":"Local Tools"}) + root.insert(0, TFsection) # at the top! + our_tools = TFsection.findall("tool") + conf_tools = [x.attrib["file"] for x in our_tools] + if xmlfile not in conf_tools: # new + ET.SubElement(TFsection, "tool", {"file": xmlfile}) + sortchildrenby(TFsection,"file") + tree.write(tcpath, pretty_print=True) + + + + + + + def shedLoad(self): + """ + use bioblend to create new repository + or update existing + + """ + if os.path.exists(self.tlog): + sto = open(self.tlog, "a") + else: + sto = open(self.tlog, "w") + + ts = toolshed.ToolShedInstance( + url=self.args.toolshed_url, + key=self.args.toolshed_api_key, + verify=False, + ) + repos = ts.repositories.get_repositories() + rnames = [x.get("name", "?") for x in repos] + rids = [x.get("id", "?") for x in repos] + tfcat = "ToolFactory generated tools" + if self.tool_name not in rnames: + tscat = ts.categories.get_categories() + cnames = [x.get("name", "?").strip() for x in tscat] + cids = [x.get("id", "?") for x in tscat] + catID = None + if tfcat.strip() in cnames: + ci = cnames.index(tfcat) + catID = cids[ci] + res = ts.repositories.create_repository( + name=self.args.tool_name, + synopsis="Synopsis:%s" % self.args.tool_desc, + description=self.args.tool_desc, + type="unrestricted", + remote_repository_url=self.args.toolshed_url, + homepage_url=None, + category_ids=catID, + ) + tid = res.get("id", None) + sto.write(f"#create_repository {self.args.tool_name} tid={tid} res={res}\n") + else: + i = rnames.index(self.tool_name) + tid = rids[i] + try: + res = ts.repositories.update_repository( + id=tid, tar_ball_path=self.newtarpath, commit_message=None + ) + sto.write(f"#update res id {id} ={res}\n") + except ConnectionError: + sto.write( + "####### Is the toolshed running and the API key correct? Bioblend shed upload failed\n" + ) + sto.close() + + def eph_galaxy_load(self): + """ + use ephemeris to load the new tool from the local toolshed after planemo uploads it + """ + if os.path.exists(self.tlog): + tout = open(self.tlog, "a") + else: + tout = open(self.tlog, "w") + cll = [ + "shed-tools", + "install", + "-g", + self.args.galaxy_url, + "--latest", + "-a", + self.args.galaxy_api_key, + "--name", + self.tool_name, + "--owner", + "fubar", + "--toolshed", + self.args.toolshed_url, + "--section_label", + "ToolFactory", + ] + tout.write("running\n%s\n" % " ".join(cll)) + subp = subprocess.run( + cll, + env=self.ourenv, + cwd=self.ourcwd, + shell=False, + stderr=tout, + stdout=tout, + ) + tout.write( + "installed %s - got retcode %d\n" % (self.tool_name, subp.returncode) + ) + tout.close() + return subp.returncode + + def planemo_biodocker_test(self): + """planemo currently leaks dependencies if used in the same container and gets unhappy after a + first successful run. https://github.com/galaxyproject/planemo/issues/1078#issuecomment-731476930 + + Docker biocontainer has planemo with caches filled to save repeated downloads + + + """ + + def prun(container, tout, cl, user="biodocker"): + rlog = container.exec_run(cl, user=user) + slogl = str(rlog).split("\\n") + slog = "\n".join(slogl) + tout.write(f"## got rlog {slog} from {cl}\n") + + if os.path.exists(self.tlog): + tout = open(self.tlog, "a") + else: + tout = open(self.tlog, "w") + planemoimage = "quay.io/fubar2/planemo-biocontainer" + xreal = "%s.xml" % self.tool_name + repname = f"{self.tool_name}_planemo_test_report.html" + ptestrep_path = os.path.join(self.repdir, repname) + client = docker.from_env() + tvol = client.volumes.create() + tvolname = tvol.name + destdir = "/toolfactory/ptest" + imrep = os.path.join(destdir, repname) + # need to keep the container running so keep it open with sleep + # will stop and destroy it when we are done + container = client.containers.run( + planemoimage, + "sleep 120m", + detach=True, + user="biodocker", + volumes={f"{tvolname}": {"bind": "/toolfactory", "mode": "rw"}}, + ) + cl = f"mkdir -p {destdir}" + prun(container, tout, cl, user="root") + # that's how hard it is to get root on a biodocker container :( + cl = f"rm -rf {destdir}/*" + prun(container, tout, cl, user="root") + ptestpath = os.path.join(destdir, "tfout", xreal) + self.copy_to_container(self.tooloutdir, destdir, container) + cl = "chown -R biodocker /toolfactory" + prun(container, tout, cl, user="root") + _ = container.exec_run(f"ls -la {destdir}") + ptestcl = f"planemo test --test_output {imrep} --update_test_data --no_cleanup --test_data {destdir}/tfout/test-data --galaxy_root /home/biodocker/galaxy-central {ptestpath}" + try: + _ = container.exec_run(ptestcl) + # fails because test outputs missing but updates the test-data directory + except Exception: + e = sys.exc_info()[0] + tout.write(f"#### error: {e} from {ptestcl}\n") + cl = f"planemo test --test_output {imrep} --no_cleanup --test_data {destdir}/tfout/test-data --galaxy_root /home/biodocker/galaxy-central {ptestpath}" + try: + prun(container, tout, cl) + except Exception: + e = sys.exc_info()[0] + tout.write(f"#### error: {e} from {ptestcl}\n") + testouts = tempfile.mkdtemp(suffix=None, prefix="tftemp", dir=".") + self.copy_from_container(destdir, testouts, container) + src = os.path.join(testouts, "ptest") + if os.path.isdir(src): + shutil.copytree(src, ".", dirs_exist_ok=True) + src = repname + if os.path.isfile(repname): + shutil.copyfile(src, ptestrep_path) + else: + tout.write(f"No output from run to shutil.copytree in {src}\n") + tout.close() + container.stop() + container.remove() + tvol.remove() + shutil.rmtree(testouts) # leave for debugging + + + # def run(self): + # """ + # scripts must be small enough not to fill the pipe! + # """ + # if self.treatbashSpecial and self.opts.interpreter in ['bash','sh']: + # retval = self.runBash() + # else: + # if self.opts.output_dir: + # ste = open(self.elog,'w') + # sto = open(self.tlog,'w') + # sto.write('## Toolfactory generated command line = %s\n' % ' '.join(self.cl)) + # sto.flush() + # p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=ste,stdin=subprocess.PIPE,cwd=self.opts.output_dir) + # else: + # p = subprocess.Popen(self.cl,shell=False,stdin=subprocess.PIPE) + # p.stdin.write(self.script) + # p.stdin.close() + # retval = p.wait() + # if self.opts.output_dir: + # sto.close() + # ste.close() + # err = open(self.elog,'r').read() + # if retval <> 0 and err: # problem + # print >> sys.stderr, '## error code %d returned with:\n%s' % (retval,err) + # if self.opts.make_HTML: + # self.makeHtml() + # return retval + + # def runBash(self): + # """ + # cannot use - for bash so use self.sfile + # """ + # if self.opts.output_dir: + # s = '## Toolfactory generated command line = %s\n' % ' '.join(self.cl) + # sto = open(self.tlog,'w') + # sto.write(s) + # sto.flush() + # p = subprocess.Popen(self.cl,shell=False,stdout=sto,stderr=sto,cwd=self.opts.output_dir) + # else: + # p = subprocess.Popen(self.cl,shell=False) + # retval = p.wait() + # if self.opts.output_dir: + # sto.close() + # if self.opts.make_HTML: + # self.makeHtml() + # return retval + + # def make_conda_env(self, dep_list): + # """ +# (venv) galaxy@ross-newgrt:/evol/galaxy$ mulled-hash bioblend=0.17.0,galaxyxml=0.4.14 +# mulled-v2-37438395e15c3d0bed4e02d66d5b05ca3d18b389:1d0b008b65909163243b3fdddd9aa20605f8a005 + +# conda create -n myenv python=3.9 scipy=0.17.3 astroid babel + + + # """ + # dep_list.sort() + # self.env_name = '-'.join(dep_list) + # for e in self.xmlcl + + + # for e in self.xclsuffix: + # # xappendme = ["999", p["infilename"], "< $%s" % p["infilename"]] + # else: + # xappendme = [p["CL"], "$%s" % p["infilename"], ""] + # xclsuffix.append(xappendme) + # if os.path.exists(self.tlog): + # tout = open(self.tlog, "a") + # else: + # tout = open(self.tlog, "w") + # cli = ["conda", "create", "-n", self.env_name, ' '.join(dep_list)] + # p = subprocess.run( + # cll, + # shell=False, + # cwd=self.tooloutdir, + # stderr=tout, + # stdout=tout, + # ) + # cli = ["conda", "activate", self.env_name, " && "] + # cli.append(run_cmd) + # tout.close() + +def main(): + """ + This is a Galaxy wrapper. + It expects to be called by a special purpose tool.xml + + """ + parser = argparse.ArgumentParser() + a = parser.add_argument + a("--script_path", default=None) + a("--history_test", default=None) + a("--cl_user_suffix", default=None) + a("--sysexe", default=None) + a("--packages", default=None) + a("--tool_name", default="newtool") + a("--tool_dir", default=None) + a("--input_files", default=[], action="append") + a("--output_files", default=[], action="append") + a("--user_email", default="Unknown") + a("--bad_user", default=None) + a("--help_text", default=None) + a("--tool_desc", default=None) + a("--tool_version", default="0.01") + a("--citations", default=None) + a("--command_override", default=None) + a("--test_override", default=None) + a("--additional_parameters", action="append", default=[]) + a("--selecttext_parameters", action="append", default=[]) + a("--edit_additional_parameters", action="store_true", default=False) + a("--parampass", default="positional") + a("--tfout", default="./tfout") + a("--galaxy_root", default="/galaxy-central") + a("--galaxy_venv", default="/galaxy_venv") + a("--collection", action="append", default=[]) + a("--include_tests", default=False, action="store_true") + a("--install_flag", action = "store_true", default=False) + a("--admin_only", default=True, action="store_true") + a("--untested_tool_out", default=None) + a("--local_tools", default="tools") # relative to $__root_dir__ + a("--tool_conf_path", default="config/tool_conf.xml") # relative to $__root_dir__ + args = parser.parse_args() + if args.admin_only: + assert not args.bad_user, ( + 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy \ +admin adds %s to "admin_users" in the galaxy.yml Galaxy configuration file' + % (args.bad_user, args.bad_user) + ) + assert args.tool_name, "## This ToolFactory cannot build a tool without a tool name. Please supply one." + tf = Tool_Factory(args) + tf.writeShedyml() + tf.makeTool() + tf.planemo_test_update() + tf.makeToolTar() + tf.update_toolconf() + + +if __name__ == "__main__": + main() diff -r 2beaae16651e -r 0183cad9d13b tacrev/test-data/tacrev_reversed_output_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tacrev/test-data/tacrev_reversed_output_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1210 @@ +)(niam +:"__niam__" == __eman__ fi + + +)(fnocloot_etadpu.ft +)(raTlooTekam.ft +)(etadpu_tset_omenalp.ft +)(looTekam.ft +)(lmydehSetirw.ft +)sgra(yrotcaF_looT = ft +".eno ylppus esaelP .eman loot a tuohtiw loot a dliub tonnac yrotcaFlooT sihT ##" ,eman_loot.sgra tressa +) +)resu_dab.sgra ,resu_dab.sgra( % +'elif noitarugifnoc yxalaG lmy.yxalag eht ni "sresu_nimda" ot s% sdda nimda +\ yxalaG litnu loot siht esu ot dezirohtua TON si s% :DESIROHTUANU' +( ,resu_dab.sgra ton tressa +:ylno_nimda.sgra fi +)(sgra_esrap.resrap = sgra +__rid_toor__$ ot evitaler # )"lmx.fnoc_loot/gifnoc"=tluafed ,"htap_fnoc_loot--"(a +__rid_toor__$ ot evitaler # )"sloot"=tluafed ,"sloot_lacol--"(a +)enoN=tluafed ,"tuo_loot_detsetnu--"(a +)"eurt_erots"=noitca ,eurT=tluafed ,"ylno_nimda--"(a +)eslaF=tluafed ,"eurt_erots" = noitca ,"galf_llatsni--"(a +)"eurt_erots"=noitca ,eslaF=tluafed ,"stset_edulcni--"(a +)][=tluafed ,"dneppa"=noitca ,"noitcelloc--"(a +)"vnev_yxalag/"=tluafed ,"vnev_yxalag--"(a +)"lartnec-yxalag/"=tluafed ,"toor_yxalag--"(a +)"tuoft/."=tluafed ,"tuoft--"(a +)"lanoitisop"=tluafed ,"ssapmarap--"(a +)eslaF=tluafed ,"eurt_erots"=noitca ,"sretemarap_lanoitidda_tide--"(a +)][=tluafed ,"dneppa"=noitca ,"sretemarap_txettceles--"(a +)][=tluafed ,"dneppa"=noitca ,"sretemarap_lanoitidda--"(a +)enoN=tluafed ,"edirrevo_tset--"(a +)enoN=tluafed ,"edirrevo_dnammoc--"(a +)enoN=tluafed ,"snoitatic--"(a +)"10.0"=tluafed ,"noisrev_loot--"(a +)enoN=tluafed ,"csed_loot--"(a +)enoN=tluafed ,"txet_pleh--"(a +)enoN=tluafed ,"resu_dab--"(a +)"nwonknU"=tluafed ,"liame_resu--"(a +)"dneppa"=noitca ,][=tluafed ,"selif_tuptuo--"(a +)"dneppa"=noitca ,][=tluafed ,"selif_tupni--"(a +)enoN=tluafed ,"rid_loot--"(a +)"lootwen"=tluafed ,"eman_loot--"(a +)enoN=tluafed ,"segakcap--"(a +)enoN=tluafed ,"exesys--"(a +)enoN=tluafed ,"xiffus_resu_lc--"(a +)enoN=tluafed ,"tset_yrotsih--"(a +)enoN=tluafed ,"htap_tpircs--"(a +tnemugra_dda.resrap = a +)(resraPtnemugrA.esrapgra = resrap +""" + +lmx.loot esoprup laiceps a yb dellac eb ot stcepxe tI +.repparw yxalaG a si sihT +""" +:)(niam fed + +)(esolc.tuot # +)dmc_nur(dneppa.ilc # +]" && " ,eman_vne.fles ,"etavitca" ,"adnoc"[ = ilc # +) # +,tuot=tuodts # +,tuot=rredts # +,ridtuoloot.fles=dwc # +,eslaF=llehs # +,llc # +(nur.ssecorpbus = p # +])tsil_ped(nioj.' ' ,eman_vne.fles ,"n-" ,"etaerc" ,"adnoc"[ = ilc # +)"w" ,golt.fles(nepo = tuot # +:esle # +)"a" ,golt.fles(nepo = tuot # +:)golt.fles(stsixe.htap.so fi # +)emdneppax(dneppa.xiffuslcx # +]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax # +:esle # +]]"emanelifni"[p % "s%$ <" ,]"emanelifni"[p ,"999"[ = emdneppax # # +:xiffuslcx.fles ni e rof # + ++ lclmx.fles ni e rof # +)tsil_ped(nioj.'-' = eman_vne.fles # +)(tros.tsil_ped # +""" # + + +lebab diortsa 3.71.0=ypics 9.3=nohtyp vneym n- etaerc adnoc # + +500a8f50602aa9ddddf3b34236190956b800b0d1:983b81d3ac50b5d66d20e4deb0d3c51e59383473-2v-dellum # +41.4.0=lmxyxalag,0.71.0=dnelboib hsah-dellum $yxalag/love/:trgwen-ssor@yxalag )vnev( # +""" # +:)tsil_ped ,fles(vne_adnoc_ekam fed # + +lavter nruter # +)(lmtHekam.fles # +:LMTH_ekam.stpo.fles fi # +)(esolc.ots # +:rid_tuptuo.stpo.fles fi # +)(tiaw.p = lavter # +)eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +:esle # +)rid_tuptuo.stpo.fles=dwc,ots=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +)(hsulf.ots # +)s(etirw.ots # +)'w',golt.fles(nepo = ots # +)lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##' = s # +:rid_tuptuo.stpo.fles fi # +""" # +elifs.fles esu os hsab rof - esu tonnac # +""" # +:)fles(hsaBnur fed # + +lavter nruter # +)(lmtHekam.fles # +:LMTH_ekam.stpo.fles fi # +)rre,lavter( % 's%n\:htiw denruter d% edoc rorre ##' ,rredts.sys >> tnirp # +melborp # :rre dna 0 >< lavter fi # +)(daer.)'r',gole.fles(nepo = rre # +)(esolc.ets # +)(esolc.ots # +:rid_tuptuo.stpo.fles fi # +)(tiaw.p = lavter # +)(esolc.nidts.p # +)tpircs.fles(etirw.nidts.p # +)EPIP.ssecorpbus=nidts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +:esle # +)rid_tuptuo.stpo.fles=dwc,EPIP.ssecorpbus=nidts,ets=rredts,ots=tuodts,eslaF=llehs,lc.fles(nepoP.ssecorpbus = p # +)(hsulf.ots # +))lc.fles(nioj.' ' % 'n\s% = enil dnammoc detareneg yrotcaflooT ##'(etirw.ots # +)'w',golt.fles(nepo = ots # +)'w',gole.fles(nepo = ets # +:rid_tuptuo.stpo.fles fi # +:esle # +)(hsaBnur.fles = lavter # +:]'hs','hsab'[ ni reterpretni.stpo.fles dna laicepShsabtaert.fles fi # +""" # +!epip eht llif ot ton hguone llams eb tsum stpircs # +""" # +:)fles(nur fed # + + +gniggubed rof evael # )stuotset(eertmr.lituhs +)(evomer.lovt +)(evomer.reniatnoc +)(pots.reniatnoc +)(esolc.tuot +)"n\}crs{ ni eertypoc.lituhs ot nur morf tuptuo oN"f(etirw.tuot +:esle +)htap_pertsetp ,crs(elifypoc.lituhs +:)emanper(elifsi.htap.so fi +emanper = crs +)eurT=ko_tsixe_srid ,"." ,crs(eertypoc.lituhs +:)crs(ridsi.htap.so fi +)"tsetp" ,stuotset(nioj.htap.so = crs +)reniatnoc ,stuotset ,ridtsed(reniatnoc_morf_ypoc.fles +)"."=rid ,"pmetft"=xiferp ,enoN=xiffus(pmetdkm.elifpmet = stuotset +)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot +]0[)(ofni_cxe.sys = e +:noitpecxE tpecxe +)lc ,tuot ,reniatnoc(nurp +:yrt +"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- }permi{ tuptuo_tset-- tset omenalp"f = lc +)"n\}lctsetp{ morf }e{ :rorre ####"f(etirw.tuot +]0[)(ofni_cxe.sys = e +:noitpecxE tpecxe +yrotcerid atad-tset eht setadpu tub gnissim stuptuo tset esuaceb sliaf # +)lctsetp(nur_cexe.reniatnoc = _ +:yrt +"}htaptsetp{ lartnec-yxalag/rekcodoib/emoh/ toor_yxalag-- atad-tset/tuoft/}ridtsed{ atad_tset-- punaelc_on-- atad_tset_etadpu-- }permi{ tuptuo_tset-- tset omenalp"f = lctsetp +)"}ridtsed{ al- sl"f(nur_cexe.reniatnoc = _ +)"toor"=resu ,lc ,tuot ,reniatnoc(nurp +"yrotcafloot/ rekcodoib R- nwohc" = lc +)reniatnoc ,ridtsed ,ridtuoloot.fles(reniatnoc_ot_ypoc.fles +)laerx ,"tuoft" ,ridtsed(nioj.htap.so = htaptsetp +)"toor"=resu ,lc ,tuot ,reniatnoc(nurp +"*/}ridtsed{ fr- mr"f = lc +(: reniatnoc rekcodoib a no toor teg ot si ti drah woh s'taht # +)"toor"=resu ,lc ,tuot ,reniatnoc(nurp +"}ridtsed{ p- ridkm"f = lc +) +,}}"wr" :"edom" ,"yrotcafloot/" :"dnib"{ :"}emanlovt{"f{=semulov +,"rekcodoib"=resu +,eurT=hcated +,"m021 peels" +,egamiomenalp +(nur.sreniatnoc.tneilc = reniatnoc +enod era ew nehw ti yortsed dna pots lliw # +peels htiw nepo ti peek os gninnur reniatnoc eht peek ot deen # +)emanper ,ridtsed(nioj.htap.so = permi +"tsetp/yrotcafloot/" = ridtsed +eman.lovt = emanlovt +)(etaerc.semulov.tneilc = lovt +)(vne_morf.rekcod = tneilc +)emanper ,ridper.fles(nioj.htap.so = htap_pertsetp +"lmth.troper_tset_omenalp_}eman_loot.fles{"f = emanper +eman_loot.fles % "lmx.s%" = laerx +"reniatnocoib-omenalp/2rabuf/oi.yauq" = egamiomenalp +)"w" ,golt.fles(nepo = tuot +:esle +)"a" ,golt.fles(nepo = tuot +:)golt.fles(stsixe.htap.so fi + +)"n\}lc{ morf }gols{ golr tog ##"f(etirw.tuot +)lgols(nioj."n\" = gols +)"n\\"(tilps.)golr(rts = lgols +)resu=resu ,lc(nur_cexe.reniatnoc = golr +:)"rekcodoib"=resu ,lc ,tuot ,reniatnoc(nurp fed + +""" + + +sdaolnwod detaeper evas ot dellif sehcac htiw omenalp sah reniatnocoib rekcoD + +039674137-tnemmoceussi#8701/seussi/omenalp/tcejorpyxalag/moc.buhtig//:sptth .nur lufsseccus tsrif +a retfa yppahnu steg dna reniatnoc emas eht ni desu fi seicnedneped skael yltnerruc omenalp""" +:)fles(tset_rekcodoib_omenalp fed + +edocnruter.pbus nruter +)(esolc.tuot +) +)edocnruter.pbus ,eman_loot.fles( % "n\d% edocter tog - s% dellatsni" +(etirw.tuot +) +,tuot=tuodts +,tuot=rredts +,eslaF=llehs +,dwcruo.fles=dwc +,vneruo.fles=vne +,llc +(nur.ssecorpbus = pbus +))llc(nioj." " % "n\s%n\gninnur"(etirw.tuot +] +,"yrotcaFlooT" +,"lebal_noitces--" +,lru_dehsloot.sgra.fles +,"dehsloot--" +,"rabuf" +,"renwo--" +,eman_loot.fles +,"eman--" +,yek_ipa_yxalag.sgra.fles +,"a-" +,"tsetal--" +,lru_yxalag.sgra.fles +,"g-" +,"llatsni" +,"sloot-dehs" +[ = llc +)"w" ,golt.fles(nepo = tuot +:esle +)"a" ,golt.fles(nepo = tuot +:)golt.fles(stsixe.htap.so fi +""" +ti sdaolpu omenalp retfa dehsloot lacol eht morf loot wen eht daol ot siremehpe esu +""" +:)fles(daol_yxalag_hpe fed + +)(esolc.ots +) +"n\deliaf daolpu dehs dnelboiB ?tcerroc yek IPA eht dna gninnur dehsloot eht sI #######" +(etirw.ots +:rorrEnoitcennoC tpecxe +)"n\}ser{= }di{ di ser etadpu#"f(etirw.ots +) +enoN=egassem_timmoc ,htapratwen.fles=htap_llab_rat ,dit=di +(yrotisoper_etadpu.seirotisoper.st = ser +:yrt +]i[sdir = dit +)eman_loot.fles(xedni.semanr = i +:esle +)"n\}ser{=ser }dit{=dit }eman_loot.sgra.fles{ yrotisoper_etaerc#"f(etirw.ots +)enoN ,"di"(teg.ser = dit +) +,DItac=sdi_yrogetac +,enoN=lru_egapemoh +,lru_dehsloot.sgra.fles=lru_yrotisoper_etomer +,"detcirtsernu"=epyt +,csed_loot.sgra.fles=noitpircsed +,csed_loot.sgra.fles % "s%:sisponyS"=sisponys +,eman_loot.sgra.fles=eman +(yrotisoper_etaerc.seirotisoper.st = ser +]ic[sdic = DItac +)tacft(xedni.semanc = ic +:semanc ni )(pirts.tacft fi +enoN = DItac +]tacst ni x rof )"?" ,"di"(teg.x[ = sdic +]tacst ni x rof )(pirts.)"?" ,"eman"(teg.x[ = semanc +)(seirogetac_teg.seirogetac.st = tacst +:semanr ni ton eman_loot.fles fi +"sloot detareneg yrotcaFlooT" = tacft +]soper ni x rof )"?" ,"di"(teg.x[ = sdir +]soper ni x rof )"?" ,"eman"(teg.x[ = semanr +)(seirotisoper_teg.seirotisoper.st = soper +) +,eslaF=yfirev +,yek_ipa_dehsloot.sgra.fles=yek +,lru_dehsloot.sgra.fles=lru +(ecnatsnIdehSlooT.dehsloot = st + +)"w" ,golt.fles(nepo = ots +:esle +)"a" ,golt.fles(nepo = ots +:)golt.fles(stsixe.htap.so fi +""" + +gnitsixe etadpu ro +yrotisoper wen etaerc ot dnelboib esu +""" +:)fles(daoLdehs fed + + + + + + +)eurT=tnirp_ytterp ,htapct(etirw.eert +)"elif",noitcesFT(ybnerdlihctros +)}eliflmx :"elif"{ ,"loot" ,noitcesFT(tnemelEbuS.TE +wen # :sloot_fnoc ni ton eliflmx fi +]sloot_ruo ni x rof ]"elif"[birtta.x[ = sloot_fnoc +)"loot"(lladnif.noitcesFT = sloot_ruo +!pot eht ta # )noitcesFT ,0(tresni.toor +)}"slooT lacoL":"eman" ,"slootlacol":"di"{ ,"noitces"(tnemelE.TE = noitcesFT +:FTsah ton fi +]0[e = noitcesFT +eurT = FTsah +:0 > )e(nel fi +)"noitces"(lladnif.toor = e +eslaF = FTsah +)(toorteg.eert = toor +)resrap ,htapct(esrap.TE = eert +)eurT=txet_knalb_evomer(resraPLMX.TE = resrap +)eman_loot.fles % 'lmx.s%' ,eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = eliflmx +)'lmx.fnoc_loot_lacol/gifnoc',toor_yxalag.sgra.fles(nioj.htap.so = htapct + +))rtta(teg.dlihc :dlihc adbmal=yek ,tnerap(detros = ]:[tnerap +:)rtta ,tnerap(ybnerdlihctros fed + +:) fles(fnocloot_etadpu fed + + +edocnruter.p nruter +)(esolc.tuot +) +,tuot=tuodts +,tuot=rredts +,ridtuoloot.fles=dwc +,eslaF=llehs +,llc +(nur.ssecorpbus = p +] +,)laerx(htapsba.htap.so +,"atad_tset_etadpu--" +,toor_yxalag.sgra.fles +,"toor_yxalag--" +,)htap_tset_loot(htapsba.htap.so +,"tuptuo_tset--" +,)ridtset.fles(htapsba.htap.so +,"atad_tset--" +,"sreniatnocoib--" +,"tini_otua_adnoc--" +,"tset" +,"omenalp" +[ = llc +)"w" ,golt.fles(nepo = tuot +:esle +)"a" ,golt.fles(nepo = tuot +:)golt.fles(stsixe.htap.so fi +) +"lmth.troper_tset_omenalp_}eman_loot.fles{"f ,ridper.fles +(nioj.htap.so = htap_tset_loot +eman_loot.fles % "lmx.s%" = laerx +""" +gnitset rof elbaliava si os tnemeriuqer a si omenalp""" +:)fles(etadpu_tset_omenalp fed + + +)(esolc.ft +))"zg.dehsloot_detsetnu_}eman_loot.fles{"f ,ridtuoloot.fles(nioj.htap.so ,htapratwen.fles(ypoc.lituhs +) +,noitcnuf_edulcxe=retlif +,eman_loot.fles=emancra +,ridtuoloot.fles=eman +(dda.ft +)"zg:w" ,htapratwen.fles(nepo.elifrat = ft +) +)ridtset.fles ,tsedt( % +".s% nur omenalp retfa ridtset ni dnuof ton s% elif tuptuo - deliaf evah yam looT###" +(tnirp +:liaf_troper fi +:esle +)tsed ,crs(elifypoc.lituhs +))]'tamrof'[p,emano( % "s%.elpmas.s%" ,ridper.fles(nioj.htap.so = tsed +)tsedt ,crs(elifypoc.lituhs +:)crs(elifsi.htap.so fi +:)tsedt(elifsi.htap.so ton fi +)emano ,ridtset.fles(nioj.htap.so = crs +)emano % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsedt +]"eman"[p = emano +:seliftuo.fles ni p rof + +ofnirat esle )emedulcxe(htiwsdne.emanelif fi enoN nruter +eman.ofnirat = emanelif +:)ofnirat(noitcnuf_edulcxe fed + +"lmth.troper_tset_omenalp_" = emedulcxe +"""llabrat eht eraperp dna atad-tset otni stuptuo evom""" +:)eslaF=liaf_troper ,fles(raTlooTekam fed + +)eurT=ko_tsixe_srid ,tsed,ridtuoloot.fles(eertypoc.lituhs +)eman_loot.fles ,sloot_lacol.fles(nioj.htap.so = tsed +)tsed ,htp(elifypoc.lituhs +) +)]"tamrof"[p ,]"emanelifni"[p( % "s%.elpmas_s%" ,ridper.fles +(nioj.htap.so = tsed +)tsed ,htp(elifypoc.lituhs +)]"emanelifni"[p % "elpmas_s%" ,ridtset.fles(nioj.htap.so = tsed +]"eman"[p = htp +:selifni.fles ni p rof +)tuox ,laerx(elifypoc.lituhs +)laerx ,ridper.fles(nioj.htap.so = tuox +)tuox ,laerx(elifypoc.lituhs +)laerx ,ridtuoloot.fles(nioj.htap.so = tuox +eman_loot.fles % "lmx.s%" = laerx +)emants ,elifs.fles(elifypoc.lituhs +:)emants(stsixe.htap.so ton fi +)elifs.fles ,ridtuoloot.fles(nioj.htap.so = emants +:htap_tpircs.sgra.fles fi +)(LMXekam.fles +:esle +)(marapLMXoNod.fles +:0 == ssapmarap.sgra.fles fi +"""ecalp otni selpmas tupni dna slmx etirw""" +:)fles(looTekam fed + +)(esolc.flmay +)eurT=edocinu_wolla ,flmay ,tcido(pmud.lmay +} +,"slooT detareneG FT" :"yrogetac" +,csed_loot.sgra.fles :"sisponys" +,csed_loot.sgra.fles :"noitpircsed" +,"detcirtsernu" :"epyt" +,resuy :"renwo" +,eman_loot.fles :"eman" +{ = tcido +)"w" ,emanfy(nepo = flmay +)"lmy.dehs." ,ridtuoloot.fles(nioj.htap.so = emanfy +]0[)"@"(tilps.liame_resu.sgra.fles = resuy +"""omenalp rof""" +:)fles(lmydehSetirw fed + +meti yrotsih yxalag # +)"n\"(etirw.fx +)lmxe(etirw.fx +:fx sa )"w" ,eman_loot.fles % "lmx.s%"(nepo htiw +dexif = lmxe +)2trap ,)edirrevo_tset.fles(nioj."n\" ,1trap( % "s%n\s%n\s%" = dexif +]1[)">stset/<"(tilps.lmxe = 2trap +]0[)">stset<"(tilps.lmxe = 1trap +stset rof stcejbo lmxl stcepxe ti sa lmxyxalag edisni siht od tonnac # :) +edirrevo_tset.fles +( fi +detpecca RP litnu dnuora krow yraropmet # )"" ,EXEEKAF(ecalper.0lmxe = lmxe +)(tropxe.lootwen.fles = 0lmxe +))LRUyrotcaFloot( % "s% :ta tig ni ecruoS"(tnemmoc_dda.lootwen.fles +) +))(wonemit ,liame_resu.sgra.fles( % +".yrotcaF looT yxalaG eht gnisu s% ta s% yb detaerC" +(tnemmoc_dda.lootwen.fles +stset = stset.lootwen.fles +)a_tset(dneppa.stset +)pt(dneppa.a_tset +:maraptset.fles ni pt rof +)(tseT.ptxg = a_tset +)(stseT.ptxg = stset +selifgifnoc = selifgifnoc.lootwen.fles +) +))tpircSdepacse.fles(nioj."n\"=txet ,"emnur"=eman(elifgifnoC.ptxg +(dneppa.selifgifnoc +)(selifgifnoC.ptxg = selifgifnoc +:htap_tpircs.sgra.fles fi +stupnit.fles = stupni.lootwen.fles +stuptuot.fles = stuptuo.lootwen.fles +)(marapLMXod.fles +:esle +)(marapLMXoNod.fles +:"0" == ssapmarap.sgra.fles fi +stnemeriuqer = stnemeriuqer.lootwen.fles +)2(tixe.sys +) +,segakcap.sgra.fles +,"= esrap tonnac - deilppus gnirts segakcap demroflam ###" +(tnirp +:noitpecxE tpecxe +)d(dneppa.vneadnoc.fles +) +)rev ,)(pirts.gkcap ,"egakcap"(tnemeriuqeR.ptxg +(dneppa.stnemeriuqer +:gkcap fi +enoN = rev +:"" == rev fi +enoN = rev +)(pirts.d = gkcap +:esle +)(pirts.gkcap = gkcap +)(pirts.rev = rev +)":"(tilps.d = rev ,gkcap +:d ni ":" fi +)":" ,"="(ecalper.d = d +)":" ,"=="(ecalper.d = d +enoN = gkcap +enoN = rev +:)","(tilps.segakcap.sgra.fles ni d rof +:yrt +:segakcap.sgra.fles fi +][ = vneadnoc.fles +)(stnemeriuqeR.ptxg = stnemeriuqer +dts = soidts.lootwen.fles +)1dts(dneppa.dts +)(oidtS.ptxg = 1dts +)(soidtS.ptxg = dts +'"}noisrev_loot.sgra.fles{" ohce'f = dnammoc_noisrev.lootwen.fles +txetrefas = pleh.lootwen.fles +)rcs(nioj."n\" + txetrefas = txetrefas +)"n\"(dneppa.rcs +) +]:001-[rcs + +]"...... " ,"deteled ffuts - senil 003> "[ + +]001:[rcs +( = rcs +:003 > )rcs(nel fi +)"n\::tpircSn\n\" ,0(tresni.rcs +]"" > )(pirts.x fi tpircSdecaps.fles ni x rof x[ = rcs +!dewolla noitisnart # "n\------n\n\" + txetrefas = txetrefas +:0 > )txetrefas(nel fi +:htap_tpircs.sgra.fles fi +) +)liame_resu.sgra.fles( % +"n\esaelp txet pleh htiw dliuber ot )s%( rohtua loot eht ksA" +( = txetrefas +:0 == ))(pirts.txetrefas(nel fi +)]txetpleh ni x rof )x(epacse_hateehc[(nioj."n\" = txetrefas +)(senildaer.)"r" ,txet_pleh.sgra.fles(nepo = txetpleh +:txet_pleh.sgra.fles fi +"" = txetrefas +etic = snoitatic.lootwen.fles +)etica(dneppa.etic +)"375stb/scitamrofnioib/3901.01"=eulav ,"iod"=epyt(noitatiC.ptxg = etica +)(snoitatiC.ptxg = etic +lclmx.fles = edirrevo_dnammoc.lootwen.fles +:esle +elif gifnoc # edirrevo_dnammoc.fles = edirrevo_dnammoc.lootwen.fles +:edirrevo_dnammoc.fles fi +""" +...redro tcerroc otni enil dnammoc eht teg ot woH .mmmH +lmthyxalag sesU +tpircs wen eht rof repparw loot lmx yxalaG a etaerC +""" +aqon # :)fles(LMXekam fed + +)pt(dneppa.maraptset.fles +)emanwen % "elpmas_s%"=eulav ,emanwen=eman(tuptuOtseT.ptxg = pt +)tuona(dneppa.stuptuot.fles +lanoitisop_si.fles = lanoitisop.tuona +emanwen % "s%$ >" = edirrevo_enil_dnammoc.tuona +)0=sehsad_mun ,tmfwen=tamrof ,emanwen(ataDtuptuO.ptxg = tuona +]"tamrof"[]0[seliftuo.fles = tmfwen +]"eman"[]0[seliftuo.fles = emanwen +:0 > )seliftuo.fles(nel fi +)pt(dneppa.maraptset.fles +)emanwen % "elpmas_s%"=eulav ,emanwen=eman(maraPtseT.ptxg = pt +)tupnina(dneppa.stupnit.fles +eurT = lanoitisop.tupnina +emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina +) +,0=sehsad_mun +,eslaF=elpitlum +,]"tamrof"[]0[selifni.fles=tamrof +,]"pleh"[]0[selifni.fles=pleh +,bala=lebal +,eslaF=lanoitpo +,emanwen +(maraPataD.ptxg = tupnina +]"emanelifni"[]0[selifni.fles = emanwen +s1xam ,1 == )selifni.fles(nel tressa +) +)selifni.fles(rts % +"s% - deilppus selif tupni elpitlum tub 0 si ssapmarap fi tupni eno mumixaM" +( = s1xam +]"emanelifni"[]0[selifni.fles = bala +:0 == )bala(nel fi +]"lebal"[]0[selifni.fles = bala +:0 > )selifni.fles(nel fi +"""tuodts ot nidts - egakcap elyts retlif""" +:)fles(marapLMXoNod fed + +) +"!neht litnu neddir-revo eb tsum snoitcelloc rof stset - tey degrem RP eht evah ton seod noisrev lmxyxalaG :GNINRAW ####" +(tnirp +:noitpecxE tpecxe +)mrapt(dneppa.maraptset.fles +.degrem RP litnu nekorb # )emanwen(noitcelloCtuptuOtseT.ptxg = mrapt +:yrt +)tcelloc(dneppa.stuptuot.fles +)csid(dneppa.tcelloc +) +"eslaf"=elbisiv ,"}emanwen{"f=yrotcerid ,csidwen=nrettap +(stesataDrevocsiD.ptxg = csid +)dnikwen=epyt ,lebalwen=lebal ,emanwen(noitcelloCtuptuO.ptxg = tcelloc +]"revocsid"[p = csidwen +]"lebal"[p = lebalwen +]"eman"[p = emanwen +]"dnik"[p = dnikwen +:snoitcelloc.fles ni p rof +) +)emanwen ,epytwen( % +'LMXekam ni s% retemarap txettceles +\rof "s%" epyt retemarap desingocernU' +(rorrEeulaV esiar +:esle +)mrapt(dneppa.maraptset.fles +)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt +)mrapa(dneppa.stupnit.fles +)lcwen(tni = lanoitisop.mrapa +:lanoitisop_si.fles fi +lanoitisop_si.fles = lanoitisop.mrapa +)tpona(dneppa.mrapa +) +,]i[txetwen=txet +,]i[lavwen=eulav +(noitpOtceleS.ptxg = tpona +:))lavwen(nel(egnar ni i rof +) +,hsadn=sehsad_mun +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPtceleS.ptxg = mrapa +]"stxet"[p = txetwen +:"txettceles" == epytwen fi +)emanwen(hsadNteg.fles = hsadn +emanwen = lebalwen +:0 > )lebalwen(nel ton fi +]"LC"[p = lcwen +]"epyt"[p = epytwen +]"pleh"[p = plehwen +]"lebal"[p = lebalwen +]"eulav"[p = lavwen +]"eman"[p = emanwen +:raples.fles ni p rof +)mrapt(dneppa.maraptset.fles +)lavwen=eulav ,emanwen(maraPtseT.ptxg = mrapt +)mrapa(dneppa.stupnit.fles +:esle +)mrapt(dneppa.maraptset.fles +)2mrapt(dneppa.mrapt +)lavwen=eulav ,emanwen(maraPtseT.ptxg = 2mrapt +)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt +)eper(dneppa.stupnit.fles +)mrapa(dneppa.eper +) +"dedeen sa }lebalwen{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman +(taepeR.ptxg = eper +:sper fi +)lcdlo(tni = lanoitisop.mrapa +:lanoitisop_si.fles fi +lanoitisop_si.fles = lanoitisop.mrapa +) +)emanwen ,epytwen( % +'LMXekam ni s% retemarap lanoitidda +\rof "s%" epyt retemarap desingocernU' +(rorrEeulaV esiar +:esle +) +,hsadn=sehsad_mun +,lavwen=eulav +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPnaelooB.ptxg = mrapa +:"naeloob" == epytwen file +) +,hsadn=sehsad_mun +,lavwen=eulav +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPtaolF.ptxg = mrapa +:"taolf" == epytwen file +) +,hsadn=sehsad_mun +,lavwen=eulav +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPregetnI.ptxg = mrapa +:"regetni" == epytwen file +) +,hsadn=sehsad_mun +,lavwen=eulav +,plehwen=pleh +,lebalwen=lebal +,emanwen +(maraPtxeT.ptxg = mrapa +:"txet" == epytwen fi +)emanwen(hsadNteg.fles = hsadn +emanwen = lebalwen +:0 > )lebalwen(nel ton fi +"1" == ]"taeper"[p = sper +]"LCgiro"[p = lcdlo +]"LC"[p = lcwen +]"epyt"[p = epytwen +]"pleh"[p = plehwen +]"lebal"[p = lebalwen +]"eulav"[p = lavwen +]"eman"[p = emanwen +:rapdda.fles ni p rof +)mrapt(dneppa.maraptset.fles +)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = mrapt +)tupnina(dneppa.stupnit.fles +:esle +)mrapt(dneppa.maraptset.fles +)2mrapt(dneppa.mrapt +)emanwen % "elpmas_s%"=eulav ,emanwen(maraPtseT.ptxg = 2mrapt +)"}emanwen{_R"f=eman(taepeRtseT.ptxg = mrapt +)eper(dneppa.stupnit.fles +)tupnina(dneppa.eper +) +"dedeen sa }bala{ ynam sa ddA"f=eltit ,"}emanwen{_R"f=eman +(taepeR.ptxg = eper +:sper fi +emanwen % "s%$" = edirrevo_enil_dnammoc.tupnina +)]"LCgiro"[p(tni = lanoitisop.tupnina +:esle +emanwen % "s%$ <" = edirrevo_enil_dnammoc.tupnina +8999999 = lanoitisop.tupnina +:"NIDTS" == )(reppu.]"LCgiro"[p fi +:lanoitisop_si.fles fi +lanoitisop_si.fles = lanoitisop.tupnina +) +,hsadn=sehsad_mun +,eslaF=elpitlum +,tmfwen=tamrof +,]"pleh"[p=pleh +,bala=lebal +,eslaF=lanoitpo +,emanwen +(maraPataD.ptxg = tupnina +]"lebal"[p = bala +:esle +]"LC"[p = bala +:0 > )]"lebal"[p(nel ton fi +"1" == )"0" ,"taeper"(teg.p = sper +)emanwen(hsadNteg.fles = hsadn +]"tamrof"[p = tmfwen +]"emanelifni"[p = emanwen +:selifni.fles ni p rof +)pt(dneppa.maraptset.fles +) +,c=erapmoc +,emanwen % "elpmas_s%"=eulav +,emanwen=eman +(tuptuOtseT.ptxg = pt +tset = c +:esle +) +,carf_atled=carf_atled +,atled=atled +,c=erapmoc +,emanwen % "elpmas_s%"=eulav +,emanwen=eman +(tuptuOtseT.ptxg = pt +enoN = carf_atled +)nt(tni = atled +:esle +))nt(taolf ,0.1(nim = carf_atled +enoN = atled +:nt ni "." fi +:"" > nt fi +)(pirts.]1[)":"(tilps.tset = nt +"ezis_mis" = c +:)"ezis_mis"(htiwstrats.tset file +) +,dl=ffid_senil +,c=erapmoc +,emanwen % "elpmas_s%"=eulav +,emanwen=eman +(tuptuOtseT.ptxg = pt +)]1[)":"(tilps.tset(tni = dl +:tigidsi.]1[)":"(tilps.tset fi +0 = dl +"ffid" = c +:)"ffid"(htiwstrats.)(pirts.tset fi +:"" > )(pirts.tset fi +enoN = dl +)mrapa(dneppa.stuptuot.fles +emanwen % "s%$" = edirrevo_enil_dnammoc.mrapa +)lcdlo(tni = lanoitisop.mrapa +:esle +emanwen % "s%$ >" = edirrevo_enil_dnammoc.mrapa +9999999 = lanoitisop.mrapa +:"TUODTS" == )(reppu.lcdlo fi +:lanoitisop_si.fles fi +lanoitisop_si.fles = lanoitisop.mrapa +) +emanwen=lebal ,hsadn=sehsad_mun ,tmfwen=tamrof ,emanwen=eman +(ataDtuptuO.ptxg = mrapa +)lcwen(hsadNteg.fles = hsadn +)(pirts.tset = tset +]"LCgiro"[p = lcdlo +]"tset"[p = tset +]"LC"[p = lcwen +]"tamrof"[p = tmfwen +]"eman"[p = emanwen +:seliftuo.fles ni p rof +"""loot ot stnemele dedeen lla ddA""" +aqon # :)fles(marapLMXod fed + +hsadn nruter +1 = hsadn +:2 < )emanwen(nel fi +2 = hsadn +:esle +0 = hsadn +:lanoitisop_si.fles fi +:)emanwen ,fles(hsadNteg fed + +)c(LCXa +:plc ni c rof +)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc +dne LC YID # :xiffus_resu_lc.sgra.fles fi +)lc(LCXa +:tceriderlcxtsal.fles ni lc rof +:tceriderlcxtsal.fles fi +)v(LCXa +)k(LCXa +k % "s%--" = k +:esle +k % "s%-" = k +:1 == ))(pirts.k(nel fi +:esle +)k(LCXa +edirrevok = k +:"" > edirrevok fi +:xiffuslcx.fles ni )edirrevok ,v ,k( rof + +mrof deman esrapgra ni smarap neht stupni # +dneppa.lclmx.fles = LCXa +"""elyts esrapgra""" +:)fles(esrapgralc fed + +)c(LCXa +:plc ni c rof +)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc +dne LC YID # :xiffus_resu_lc.sgra.fles fi +)lc(LCXa +:tceriderlcxtsal.fles ni lc rof +:tceriderlcxtsal.fles fi +)v(LCXa +:xiffuslcx.fles ni )edirrevok ,v ,k( rof +dneppa.lclmx.fles = LCXa +smarap neht redro ni stupni # +:)fles(lanoitisoplc fed + +pdda = ]i[rapdda.fles +]"LC"[pdda = ]"LCgiro"[pdda +)p(ypoc.ypoc = pdda +:)rapdda.fles(etaremune ni p ,i rof +pftuo = ]i[seliftuo.fles +ypoc peek # ]"LC"[pftuo = ]"LCgiro"[pftuo +)p(ypoc.ypoc = pftuo +:)seliftuo.fles(etaremune ni p ,i rof +pfni = ]i[selifni.fles +]"LC"[pfni = ]"emanelifni"[pfni +:esle +)"_" ," "(ecalper.]"lebal"[pfni = ]"emanelifni"[pfni +:]"0" ,"lanoitisop"[ ni ssapmarap.sgra.fles fi +]"LC"[pfni = ]"LCgiro"[pfni +)p(ypoc.ypoc = pfni +:)selifni.fles(etaremune ni p ,i rof +) +,]"eman"[p +,]"LC"[p +( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,)(tigidsi.] +"LC" +[p tressa +:)rapdda.fles(etaremune ni p ,i rof +) +,]"eman"[p +,]"LC"[p +( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,) +"TUODTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p +( tressa +:)seliftuo.fles(etaremune ni p ,i rof +) +,]"lebal"[p +,]"LC"[p +( % "s% rof s% tog - sregetni lanidro eb tsum sretemarap lanoitisoP" ,) +"NIDTS" == )(reppu.)(pirts.]"LC"[p ro )(tigidsi.]"LC"[p +( tressa +:)selifni.fles(etaremune ni p ,i rof +:"lanoitisop" == ssapmarap.sgra.fles fi +"""lanidro ciremun rieht yb detacilpmoc era sretemarap lanoitisop """ +:)fles(rappunaelc fed + +)(esolc.tcafitra +))"8ftu" ,tpircs.fles(setyb(etirw.tcafitra +)"bw" ,tra(nepo = tcafitra +)]0[emetucexe.fles ,eman_loot.fles( % "s%.s%" = tra +xr = tpircSdepacse.fles +)"war dne#"(dneppa.xr +)"war#" ,0(tresni.xr +]"" > )(pirts.x fi xr ni x rof "}x{ "f[ = tpircSdecaps.fles +)(esolc.tpircst +)tpircs.fles(etirw.tpircst +)"w" ,elifs.fles(nepo = tpircst +) +)]0[emetucexe.fles( % "s%_"=xiffus ,eman_loot.fles=xiferp +(pmetskm.elifpmet = elifs.fles ,eldnahf +)xr(nioj."n\" = tpircs.fles +"nur tonnaC .ytpme si tpircs deilppuS" ,0 > )kcehcxr(nel tressa +]"" > )(pirts.x fi xr ni x rof )(pirts.x[ = kcehcxr +]xr ni x rof )(pirtsr.x[ = xr +)(senildaer.)"r" ,htap_tpircs.sgra.fles(nepo = xr +:)fles(tpircSperp fed + +xiffuslcx = xiffuslcx.fles +)(tros.xiffuslcx +)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +:raples.fles ni p rof +)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +]"edirrevo"[p = revo +) +"!senil dnammoc retemarap lanoitisop ni dettimrep ton - derongi }man{ rof staepeR .gninraw ###"f +(tnirp +:per fi +esnes ON ekam staeper # "1" == ]"taeper"[p = per +]"eman"[p = man +:rapdda.fles ni p rof +)]"" ,]"eman"[p % "s%$" ,]"LC"[p[(dneppa.xiffuslcx +:esle +]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles +:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi +:)seliftuo.fles(etaremune ni p ,i rof +)emdneppax(dneppa.xiffuslcx +]"" ,]"emanelifni"[p % "s%$" ,]"LC"[p[ = emdneppax +:esle +] +,]"emanelifni"[p % "s%$ <" +,]"emanelifni"[p +,"999" +[ = emdneppax +:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi +:)selifni.fles(etaremune ni p ,i rof +][ = xiffuslcx +:)fles(soplcperp fed + +xiffuslcx = xiffuslcx.fles +)]]"edirrevo"[p ,]"eman"[p % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +:raples.fles ni p rof +)]revo ,man % '"s%$"' ,]"LC"[p[(dneppa.xiffuslcx +]"edirrevo"[p = revo +:esle +'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo +:per fi +"1" == ]"taeper"[p = per +]"eman"[p = man +:rapdda.fles ni p rof +)]"" ,]"eman"[p % "s%$" ,]"eman"[p[(dneppa.xiffuslcx +:esle +]]"eman"[p % "s%$" ,">"[ = tceriderlcxtsal.fles +:"TUODTS" == )(reppu.)(pirts.]"LCgiro"[p fi +:)seliftuo.fles(etaremune ni p ,i rof +)emdneppax(dneppa.xiffuslcx +]revo ,]"LC"[p % "s%$" ,]"LC"[p[ = emdneppax +'rof dne#n\"}man{.per$" }man{--n\:}man{_R$ ni per$ rof#'f = revo +:per fi +"" = revo +"1" == ]"taeper"[p = per +:esle +] +,man % "s%$ <" +,man +,man +[ = emdneppax +:"NIDTS" == )(reppu.)(pirts.]"LCgiro"[p fi +]"emanelifni"[p = man +:)selifni.fles(etaremune ni p ,i rof +][ = xiffuslcx +:)fles(pgraperp fed + +)c(LCXa +:plc ni c rof +)xiffus_resu_lc.sgra.fles(tilps.xelhs = plc +dne LC YID # :xiffus_resu_lc.sgra.fles fi +)]"eman"[]0[seliftuo.fles % "s%$"(LCXa +)">"(LCXa +:0 > )seliftuo.fles(nel fi +)]"emanelifni"[]0[selifni.fles % "s%$"(LCXa +)"<"(LCXa +:0 > )selifni.fles(nel fi +dneppa.lclmx.fles = LCXa +"""o/i rof > dna < sesu - staeper ro sretemarap on""" +:)fles(elpmislc fed + +)(esrapgralc.fles +)(pgraperp.fles +:esle +)(lanoitisoplc.fles +)(soplcperp.fles +:"lanoitisop" == ssapmarap.sgra.fles fi +:esle +)(elpmislc.fles +:"0" == ssapmarap.sgra.fles fi + +)xe(LCXa +:emetucexe.fles ni xe rof +:esle +)"emnur$"(LCXa +)xe(LCXa +:emetucexe.fles ni xe rof +:htap_tpircs.sgra.fles fi +enoN = edirrevo_tset.fles +:esle +]sots ni x rof )(pirtsr.x[ = edirrevo_tset.fles +)(senildaer.)"r" ,edirrevo_tset.sgra.fles(nepo = sots +:edirrevo_tset.sgra.fles fi +enoN = edirrevo_dnammoc.fles +:esle +]socs ni x rof )(pirtsr.x[ = edirrevo_dnammoc.fles +)(senildaer.)"r" ,edirrevo_dnammoc.sgra.fles(nepo = socs +:edirrevo_dnammoc.sgra.fles fi +)(tpircSperp.fles +:htap_tpircs.sgra.fles fi +][ = maraptset.fles +)(stuptuO.ptxg = stuptuot.fles +)(stupnI.ptxg = stupnit.fles +)eman_loot.fles % 'txt.gol_nur_FT_s%',ridper.fles(nioj.htap.so = golt.fles +)ridper.fles(ridkm.so +:)ridper.fles(stsixe.htap.so ton fi +)ridtset.fles(ridkm.so +:)ridtset.fles(stsixe.htap.so ton fi +)ridtuoloot.fles(ridkm.so +:)ridtuoloot.fles(stsixe.htap.so ton fi +)"atad-tset" ,ridtuoloot.fles(nioj.htap.so = ridtset.fles +)eman_loot.fles % "zg.dehsloot_detset_ton_s%" ,ridtuoloot.fles(nioj.htap.so # tuo_loot_detsetnu.sgra = htapratwen.fles +"negloot/." = ridper.fles +"tuoft/." = ridtuoloot.fles +) +,EXEEKAF +,csed_loot.sgra.fles +,noisrev_loot.sgra.fles +,di_loot.fles +,eman_loot.fles +(looT.txg = lootwen.fles +eman_loot.fles = di_loot.fles +)eman_loot.sgra ,"" ,"+]_9-0Z-Az-a^["(bus.er = eman_loot.fles +'"esrapgra" ro "lanoitisop","0" eb tsum ssapmarap.sgra' ,] +,"lanoitisop" +,"esrapgra" +,"0" +[ ni ssapmarap.sgra tressa +dneppa.lclmx.fles = LCXa +enoN = emetucexe.fles +:esle +] +,)(pirts.]0[)":"(tilps.]0[)","(tilps.segakcap.sgra.fles +[ = emetucexe.fles +:segakcap.sgra.fles fi +:esle +] +,exesys.sgra.fles +[ = emetucexe.fles +:esle +)exesys.sgra.fles(tilps.xelhs = emetucexe.fles +:exesys.sgra.fles ni " " fi +:exesys.sgra.fles fi +"lanoitisop" == ssapmarap.sgra.fles = lanoitisop_si.fles +][ = lclmx.fles +enoN = tceriderlcxtsal.fles +)(rappunaelc.fles +sgra = sgra.fles +) +"yranoitcid a eb dluohs - demroflam si }sretemarap_txettceles.sgra{ sretemarap_txettceles--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi sretemarap_txettceles.sgra ni x rof )x(sdaol.nosj +[ = raples.fles +:yrt +) +"yranoitcid a eb dluohs - demroflam si }sretemarap_lanoitidda.sgra{ sretemarap_lanoitidda--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi sretemarap_lanoitidda.sgra ni x rof )x(sdaol.nosj +[ = rapdda.fles +:yrt +'tros emos fo tuptuo na tuohtiw liaf lliw rennur boj yxalaG ehT .deificeps snoitcelloc tuptuo ro seliftuo oN' ,0 > ))snoitcelloc.fles(nel + )seliftuo.fles(nel( tressa +) +"yranoitcid a eb dluohs - demroflam si }selif_tuptuo.sgra{ retemarap selif_tuptuo--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi selif_tuptuo.sgra ni x rof )x(sdaol.nosj +[ = seliftuo.fles +:yrt +) +"yranoitcid a eb dluohs - demroflam si })selif_tupni.sgra(rts{ retemarap selif_tupni--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi selif_tupni.sgra ni x rof )x(sdaol.nosj +[ = selifni.fles +:yrt +) +"yranoitcid a eb dluohs - demroflam si })noitcelloc.sgra(rts{ retemarap snoitcelloc--"f +(tnirp +:noitpecxE tpecxe +] +1 > ))(pirts.x(nel fi noitcelloc.sgra ni x rof )x(sdaol.nosj +[ = snoitcelloc.fles +:yrt +:0 > )noitcelloc.sgra(nel fi +][ = snoitcelloc.fles +)(dwcteg.so = dwcruo.fles +)'sloot_lacol',toor_yxalag.sgra(nioj.htap.so = sloot_lacol.fles +""" +noitareneg loot lmxyxalag rof dedeen stnemele eraperp dna +ereh loot eht gninnur rof lc enil dnammoc eraperp +""" +aqon # :)enoN=sgra ,fles(__tini__ fed + +""" + +lmxyxalag sesu +tpircs yrartibra na rof repparW""" +:yrotcaF_looT ssalc + + +selput_noitatic nruter +)))(pirts.]: )"xetbib"(nel[noitatic ,"xetbib"((dneppa.selput_noitatic +:esle +)))(pirts.]: )"iod"(nel[noitatic ,"iod"((dneppa.selput_noitatic +:)"iod"(htiwstrats.noitatic fi +:snoitatic ni noitatic rof +][ = selput_noitatic +])(pirts.c fi )"**YRTNE**"(tilps.txet_snoitatic ni c rof c[ = snoitatic +"""""" +:)txet_snoitatic(snoitatic_esrap fed + + +)]txet ni c rof )c ,c(teg.elbat_epacse_hateehc[(nioj."" nruter +""".txet nihtiw seititne ecudorP""" +:)txet(epacse_hateehc fed + + +}"#\\" :"#" ,"$\\" :"$"{ = elbat_epacse_hateehc + + +)))(emit.emit(emitlacol.emit ,"S%:M%:H% Y%/m%/d%"(emitfrts.emit nruter +"""gnirts a sa emit tnerruc nruter""" +:)(wonemit fed + + +.edirrevo htiw # +neve exe eht gnidneperp lmxyxalag xif ot pmub noisrev/RP a litnu siht deen # +"~~~EM~~~EVOMER~~~" = EXEEKAF +"yrotcafloot/2rabuf/moc.buhtig//:sptth" = LRUyrotcaFloot +eurT = gubed +eurT = esobrev +"2202 hcraM 4.2V" = noisrevym + +lmay tropmi + +TE sa eerte.lmxl tropmi + +ptxg sa sretemarap.loot.lmxyxalag tropmi +txg sa loot.lmxyxalag tropmi + +yxalag tropmi dnelboib morf + +emit tropmi +elifpmet tropmi +elifrat tropmi +sys tropmi +ssecorpbus tropmi +lituhs tropmi +xelhs tropmi +er tropmi +so tropmi +nosj tropmi +ltncf tropmi +ypoc tropmi +esrapgra tropmi + + + +.tset htiw loot reporp wen a snruter dna # +stuptuo tset eht setaerc ,evihcra detset-non a no omenalp snur retset ehT # +noitpoda reniatnocoib dna tnempoleved lairotut NTG fo trap sa # +llatsni/tset dna etareneg - sloot owt otni derotcafeR :2202 hcram # +# +yrotcafloot/2rabuf/moc.buhtig//:sptth # +ta emoclew sexif gub dna tnemevorpmi rof snoitseggus # +LPGL eht rednu desneciL # +devreser sthgir lla # +# +2102 yaM )moc pots liamg ta surazal pots ssor( surazal ssor thgirypoc # +# +yrotcafloot/2rabuf/moc.buhtig//:sptth ees # diff -r 2beaae16651e -r 0183cad9d13b tf_apikey_mutate/tf_apikey_mutate.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tf_apikey_mutate/tf_apikey_mutate.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,186 @@ + + + + Rotates all API keys in a ToolFactory instance + + bioblend + python + six + + + + + + +$APIK_mutate_log]]> + + 0: + user = query.first() + user.username = username + user.set_password_cleartext(password) + sa_session.add(user) + sa_session.flush() + uexists = True + else: + user = User(email) + user.username = username + user.set_password_cleartext(password) + sa_session.add(user) + sa_session.flush() + + security_agent.create_private_user_role(user) + if not user.default_permissions: + security_agent.user_set_default_permissions(user, history=True, dataset=True) + + if key is not None: + query = sa_session.query(APIKeys).filter_by(user_id=user.id).delete() + sa_session.flush() + + api_key = APIKeys() + api_key.user_id = user.id + api_key.key = key + sa_session.add(api_key) + sa_session.flush() + return user, uexists + +def run_sed(options): + """ + eg replacement = 'APIK="%s"' % options.key + line_start = 'APIK=' + """ + fixme = [] + tool_config_file: "tool_conf.xml,../local_tools/local_tool_conf.xml" + # database_connection: "sqlite:////universe.sqlite?isolation_level=IMMEDIATE" + tfc = 'tool_conf.xml,%s/local_tools/local_tool_conf.xml' % options.galaxy_root + fixfile = "%s/config/galaxy.yml" % options.galaxy_root + fixme.append((' virtualenv: ', ' virtualenv: "%s"' % options.galaxy_venv, fixfile)) + fixme.append((' galaxy_root: ', ' galaxyroot: "%s"' % options.galaxy_root, fixfile)) + fixme.append((' tool_config_file: ', ' tool_config_file: "%s"' % tfc, fixfile)) + fixfile = "%s/local_tools/toolfactory/toolfactory.py" % options.galaxy_root + fixme.append((' self.GALAXY_ADMIN_KEY =', ' self.GALAXY_ADMIN_KEY = "%s"' % options.key, fixfile )) + fixme.append((' self.GALAXY_URL = ' , ' self.GALAXY_URL = "%s"' % options.galaxy_url, fixfile )) + fixfile = "%s/local_tools/toolfactory/install_tf_deps.sh" % options.galaxy_root + fixme.append(('APIK=', 'APIK="%s"' % options.key, fixfile )) + fixme.append(('LOCALTOOLDIR=', 'LOCALTOOLDIR="%s"' % os.path.join(os.path.abspath(options.galaxy_root), "local_tools"), fixfile )) + fixfile = "%s/local_tools/toolfactory/localplanemotest.sh" % options.galaxy_root + fixme.append(('GALAXY_URL=', 'GALAXY_URL=%s' % options.galaxy_url, fixfile)) + fixme.append(('API_KEY=', 'API_KEY=%s' % options.key, fixfile)) + fixfile = "%s/local_tools/toolfactory/toolfactory_fast_test.sh" % options.galaxy_root + fixme.append(('GALAXY_URL=', 'GALAXY_URL=%s' % options.galaxy_url, fixfile)) + fixme.append(('API_KEY=', 'API_KEY=%s' % options.key, fixfile)) + fixme.append(('GALAXY_VENV=', 'GALAXY_VENV=%s' % options.galaxy_venv, fixfile)) + fixme.append(('API_KEY_USER=', 'API_KEY_USER=%s' % options.botkey, fixfile)) + for line_start, line_replacement, file_to_edit in fixme: + cmd = ["sed", "-i", "s#.*%s.*#%s#g" % (line_start, line_replacement), file_to_edit] + print("## executing", ' '.join(cmd)) + res = subprocess.run(cmd) + if not res.returncode == 0: + print('### Non zero %d return code from %s ' % (res.returncode, ''.join(cmd))) + + +if __name__ == "__main__": + print('starting!', file=sys.stderr) + apikey = "%s" % hash(random.random()) + apikey2 = "%s" % hash(random.random()) + parser = argparse.ArgumentParser(description="Create Galaxy Admin User.") + parser.add_argument("--galaxy_url", help="Galaxy server URL", default="http://localhost:8080") + parser.add_argument("--galaxy_root", help="Galaxy root directory path", default="/work/galaxytf") + parser.add_argument("--galaxy_venv", help="Galaxy venv path", default="/work/galaxytf/.venv") + parser.add_argument("--user", help="Username - an email address.", default="toolfactory@galaxy.org") + parser.add_argument("--password", help="Password", default="ChangeMe!") + parser.add_argument("--password2", help="Password", default=apikey2) + parser.add_argument("--key", help="API-Key.", default=apikey) + parser.add_argument("--botkey", help="bot API-Key.", default=apikey2) + parser.add_argument("--username", default="tfadmin") + parser.add_argument("args", nargs=argparse.REMAINDER) + options = parser.parse_args() + sys.path.insert(1, options.galaxy_root) + sys.path.insert(1, os.path.join(options.galaxy_root, "lib")) + sys.path.insert(1, os.path.join(options.galaxy_venv, "lib", "python3.10", "site-packages")) + from galaxy.model import User, APIKeys + from galaxy.model.mapping import init + from galaxy.model.orm.scripts import get_config + cnf = get_config(argv=['-c','galaxy', ],cwd=options.galaxy_root) + print('cnf=%s' % cnf, file=sys.stderr) + cdb_url = cnf["db_url"] + # or perhaps "postgresql:///ubuntu?host=/var/run/postgresql" + # this is harder to please get_config(sys.argv, use_argparse=False)["db_url"] + print('### Using cdb_url', cdb_url, file=sys.stderr) + mapping = init("/tmp/", cdb_url) + sa_session = mapping.context + security_agent = mapping.security_agent + usr, uexists = add_user( + sa_session, security_agent, options.user, options.password, key=options.key, username=options.username + ) + print("added user", options.user, "apikey", options.key, file=sys.stderr) + + usr, uexists = add_user( + sa_session, security_agent, 'test@bx.psu.edu', options.password2, key=options.botkey, username='bot' + ) + run_sed(options) + print('Evil deeds done', file=sys.stderr) + + +#end raw]]> + + + + + + + + + + + + 10.1093/bioinformatics/bts573 + + + diff -r 2beaae16651e -r 0183cad9d13b toolfactory/install_tf_deps.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/install_tf_deps.sh Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,17 @@ +LOCALTOOLDIR="/home/ross/rossgit/galaxytf231/local_tools" +APIK="1718977735397126400" +GAL="http://localhost:8080" +# all unless a single id is passed in as $1 +if [ -z "$1" ]; then + for f in $LOCALTOOLDIR/*; do + if [ -d "$f" ]; then + TOOL=`basename "$f"` + install_tool_deps -v -g $GAL -a $APIK -t $LOCALTOOLDIR/$TOOL/$TOOL.xml + fi + done +else + install_tool_deps -v -g $GAL -a $APIK -t $LOCALTOOLDIR/$1/$1.xml +fi + + + diff -r 2beaae16651e -r 0183cad9d13b toolfactory/localplanemotest.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/localplanemotest.sh Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,6 @@ +# pass path to tool as parameter /work/galaxytf/local_tools/tacrev/tacrev.xml +GALAXY_URL=http://localhost:8080 +API_KEY=1718977735397126400 +# for test@bx.psu.edu user +# for sed to edit at installation +planemo test --galaxy_admin_key $API_KEY --engine external_galaxy --galaxy_url $GALAXY_URL --update_test_data $1 diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/input1_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/test-data/input1_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,741 @@ +#!/usr/bin/env python +# rgToolFactory.py +# see https://github.com/fubar2/toolfactory +# +# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012 +# +# all rights reserved +# Licensed under the LGPL +# suggestions for improvement and bug fixes welcome at https://github.com/fubar2/toolfactory +# +# July 2020: BCC was fun and I feel like rip van winkle after 5 years. +# Decided to +# 1. Fix the toolfactory so it works - done for simplest case +# 2. Fix planemo so the toolfactory function works +# 3. Rewrite bits using galaxyxml functions where that makes sense - done +# +# removed all the old complications including making the new tool use this same script +# galaxyxml now generates the tool xml https://github.com/hexylena/galaxyxml +# No support for automatic HTML file creation from arbitrary outputs +# TODO: add option to run that code as a post execution hook +# TODO: add additional history input parameters - currently only one + + +import argparse +import logging +import os +import re +import shutil +import subprocess +import sys +import tarfile +import tempfile +import time + +import galaxyxml.tool as gxt +import galaxyxml.tool.parameters as gxtp + +import lxml + +myversion = "V2.1 July 2020" +verbose = True +debug = True +toolFactoryURL = "https://github.com/fubar2/toolfactory" +ourdelim = "~~~" + +# --input_files="$input_files~~~$CL~~~$input_formats~~~$input_label +# ~~~$input_help" +IPATHPOS = 0 +ICLPOS = 1 +IFMTPOS = 2 +ILABPOS = 3 +IHELPOS = 4 +IOCLPOS = 5 + +# --output_files "$otab.history_name~~~$otab.history_format~~~$otab.CL +ONAMEPOS = 0 +OFMTPOS = 1 +OCLPOS = 2 +OOCLPOS = 3 + +# --additional_parameters="$i.param_name~~~$i.param_value~~~ +# $i.param_label~~~$i.param_help~~~$i.param_type~~~$i.CL~~~i$.param_CLoverride" +ANAMEPOS = 0 +AVALPOS = 1 +ALABPOS = 2 +AHELPPOS = 3 +ATYPEPOS = 4 +ACLPOS = 5 +AOVERPOS = 6 +AOCLPOS = 7 + + +foo = len(lxml.__version__) +# fug you, flake8. Say my name! + +def timenow(): + """return current time as a string + """ + return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) + + +def quote_non_numeric(s): + """return a prequoted string for non-numerics + useful for perl and Rscript parameter passing? + """ + try: + _ = float(s) + return s + except ValueError: + return '"%s"' % s + + +html_escape_table = {"&": "&", ">": ">", "<": "<", "$": r"\$"} + + +def html_escape(text): + """Produce entities within text.""" + return "".join(html_escape_table.get(c, c) for c in text) + + +def html_unescape(text): + """Revert entities within text. Multiple character targets so use replace""" + t = text.replace("&", "&") + t = t.replace(">", ">") + t = t.replace("<", "<") + t = t.replace("\\$", "$") + return t + + +def parse_citations(citations_text): + """ + """ + citations = [c for c in citations_text.split("**ENTRY**") if c.strip()] + citation_tuples = [] + for citation in citations: + if citation.startswith("doi"): + citation_tuples.append(("doi", citation[len("doi") :].strip())) + else: + citation_tuples.append( + ("bibtex", citation[len("bibtex") :].strip()) + ) + return citation_tuples + + +class ScriptRunner: + """Wrapper for an arbitrary script + uses galaxyxml + + """ + + def __init__(self, args=None): + """ + prepare command line cl for running the tool here + and prepare elements needed for galaxyxml tool generation + """ + + self.infiles = [x.split(ourdelim) for x in args.input_files] + self.outfiles = [x.split(ourdelim) for x in args.output_files] + self.addpar = [x.split(ourdelim) for x in args.additional_parameters] + self.args = args + self.cleanuppar() + self.lastclredirect = None + self.lastxclredirect = None + self.cl = [] + self.xmlcl = [] + self.is_positional = self.args.parampass == "positional" + aCL = self.cl.append + assert args.parampass in [ + "0", + "argparse", + "positional", + ], 'Parameter passing in args.parampass must be "0","positional" or "argparse"' + self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name) + self.tool_id = self.tool_name + if self.args.interpreter_name: + exe = "$runMe" + else: + exe = self.args.exe_package + assert ( + exe is not None + ), "No interpeter or executable passed in - nothing to run so cannot build" + self.tool = gxt.Tool( + self.args.tool_name, + self.tool_id, + self.args.tool_version, + self.args.tool_desc, + exe, + ) + self.tinputs = gxtp.Inputs() + self.toutputs = gxtp.Outputs() + self.testparam = [] + if ( + self.args.runmode == "Executable" or self.args.runmode == "system" + ): # binary - no need + aCL(self.args.exe_package) # this little CL will just run + else: + self.prepScript() + self.elog = "%s_error_log.txt" % self.tool_name + self.tlog = "%s_runner_log.txt" % self.tool_name + + if self.args.parampass == "0": + self.clsimple() + else: + clsuffix = [] + xclsuffix = [] + for i, p in enumerate(self.infiles): + if p[IOCLPOS] == "STDIN": + appendme = [ + p[IOCLPOS], + p[ICLPOS], + p[IPATHPOS], + "< %s" % p[IPATHPOS], + ] + xappendme = [ + p[IOCLPOS], + p[ICLPOS], + p[IPATHPOS], + "< $%s" % p[ICLPOS], + ] + else: + appendme = [p[IOCLPOS], p[ICLPOS], p[IPATHPOS], ""] + xappendme = [p[IOCLPOS], p[ICLPOS], "$%s" % p[ICLPOS], ""] + clsuffix.append(appendme) + xclsuffix.append(xappendme) + # print('##infile i=%d, appendme=%s' % (i,appendme)) + for i, p in enumerate(self.outfiles): + if p[OOCLPOS] == "STDOUT": + self.lastclredirect = [">", p[ONAMEPOS]] + self.lastxclredirect = [">", "$%s" % p[OCLPOS]] + else: + clsuffix.append([p[OOCLPOS], p[OCLPOS], p[ONAMEPOS], ""]) + xclsuffix.append( + [p[OOCLPOS], p[OCLPOS], "$%s" % p[ONAMEPOS], ""] + ) + for p in self.addpar: + clsuffix.append( + [p[AOCLPOS], p[ACLPOS], p[AVALPOS], p[AOVERPOS]] + ) + xclsuffix.append( + [p[AOCLPOS], p[ACLPOS], '"$%s"' % p[ANAMEPOS], p[AOVERPOS]] + ) + clsuffix.sort() + xclsuffix.sort() + self.xclsuffix = xclsuffix + self.clsuffix = clsuffix + if self.args.parampass == "positional": + self.clpositional() + else: + self.clargparse() + + def prepScript(self): + aCL = self.cl.append + rx = open(self.args.script_path, "r").readlines() + rx = [x.rstrip() for x in rx] + rxcheck = [x.strip() for x in rx if x.strip() > ""] + assert len(rxcheck) > 0, "Supplied script is empty. Cannot run" + self.script = "\n".join(rx) + fhandle, self.sfile = tempfile.mkstemp( + prefix=self.tool_name, suffix="_%s" % (self.args.interpreter_name) + ) + tscript = open(self.sfile, "w") + tscript.write(self.script) + tscript.close() + self.indentedScript = " %s" % "\n".join( + [" %s" % html_escape(x) for x in rx] + ) + self.escapedScript = "%s" % "\n".join( + [" %s" % html_escape(x) for x in rx] + ) + art = "%s.%s" % (self.tool_name, self.args.interpreter_name) + artifact = open(art, "wb") + artifact.write(bytes(self.script, "utf8")) + artifact.close() + aCL(self.args.interpreter_name) + aCL(self.sfile) + + def cleanuppar(self): + """ positional parameters are complicated by their numeric ordinal""" + for i, p in enumerate(self.infiles): + if self.args.parampass == "positional": + assert p[ICLPOS].isdigit(), ( + "Positional parameters must be ordinal integers - got %s for %s" + % (p[ICLPOS], p[ILABPOS]) + ) + p.append(p[ICLPOS]) + if p[ICLPOS].isdigit() or self.args.parampass == "0": + scl = "input%d" % (i + 1) + p[ICLPOS] = scl + self.infiles[i] = p + for i, p in enumerate( + self.outfiles + ): # trying to automagically gather using extensions + if self.args.parampass == "positional" and p[OCLPOS] != "STDOUT": + assert p[OCLPOS].isdigit(), ( + "Positional parameters must be ordinal integers - got %s for %s" + % (p[OCLPOS], p[ONAMEPOS]) + ) + p.append(p[OCLPOS]) + if p[OCLPOS].isdigit() or p[OCLPOS] == "STDOUT": + scl = p[ONAMEPOS] + p[OCLPOS] = scl + self.outfiles[i] = p + for i, p in enumerate(self.addpar): + if self.args.parampass == "positional": + assert p[ACLPOS].isdigit(), ( + "Positional parameters must be ordinal integers - got %s for %s" + % (p[ACLPOS], p[ANAMEPOS]) + ) + p.append(p[ACLPOS]) + if p[ACLPOS].isdigit(): + scl = "input%s" % p[ACLPOS] + p[ACLPOS] = scl + self.addpar[i] = p + + def clsimple(self): + """ no parameters - uses < and > for i/o + """ + aCL = self.cl.append + aCL("<") + aCL(self.infiles[0][IPATHPOS]) + aCL(">") + aCL(self.outfiles[0][OCLPOS]) + aXCL = self.xmlcl.append + aXCL("<") + aXCL("$%s" % self.infiles[0][ICLPOS]) + aXCL(">") + aXCL("$%s" % self.outfiles[0][ONAMEPOS]) + + def clpositional(self): + # inputs in order then params + aCL = self.cl.append + for (o_v, k, v, koverride) in self.clsuffix: + if " " in v: + aCL("%s" % v) + else: + aCL(v) + aXCL = self.xmlcl.append + for (o_v, k, v, koverride) in self.xclsuffix: + aXCL(v) + if self.lastxclredirect: + aXCL(self.lastxclredirect[0]) + aXCL(self.lastxclredirect[1]) + + def clargparse(self): + """ argparse style + """ + aCL = self.cl.append + aXCL = self.xmlcl.append + # inputs then params in argparse named form + for (o_v, k, v, koverride) in self.xclsuffix: + if koverride > "": + k = koverride + elif len(k.strip()) == 1: + k = "-%s" % k + else: + k = "--%s" % k + aXCL(k) + aXCL(v) + for (o_v, k, v, koverride) in self.clsuffix: + if koverride > "": + k = koverride + elif len(k.strip()) == 1: + k = "-%s" % k + else: + k = "--%s" % k + aCL(k) + aCL(v) + + def getNdash(self, newname): + if self.is_positional: + ndash = 0 + else: + ndash = 2 + if len(newname) < 2: + ndash = 1 + return ndash + + def doXMLparam(self): + """flake8 made me do this...""" + for p in self.outfiles: + newname, newfmt, newcl, oldcl = p + ndash = self.getNdash(newcl) + aparm = gxtp.OutputData(newcl, format=newfmt, num_dashes=ndash) + aparm.positional = self.is_positional + if self.is_positional: + if oldcl == "STDOUT": + aparm.positional = 9999999 + aparm.command_line_override = "> $%s" % newcl + else: + aparm.positional = int(oldcl) + aparm.command_line_override = "$%s" % newcl + self.toutputs.append(aparm) + tp = gxtp.TestOutput( + name=newcl, value="%s_sample" % newcl, format=newfmt + ) + self.testparam.append(tp) + for p in self.infiles: + newname = p[ICLPOS] + newfmt = p[IFMTPOS] + ndash = self.getNdash(newname) + if not len(p[ILABPOS]) > 0: + alab = p[ICLPOS] + else: + alab = p[ILABPOS] + aninput = gxtp.DataParam( + newname, + optional=False, + label=alab, + help=p[IHELPOS], + format=newfmt, + multiple=False, + num_dashes=ndash, + ) + aninput.positional = self.is_positional + self.tinputs.append(aninput) + tparm = gxtp.TestParam(name=newname, value="%s_sample" % newname) + self.testparam.append(tparm) + for p in self.addpar: + newname, newval, newlabel, newhelp, newtype, newcl, override, oldcl = p + if not len(newlabel) > 0: + newlabel = newname + ndash = self.getNdash(newname) + if newtype == "text": + aparm = gxtp.TextParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "integer": + aparm = gxtp.IntegerParam( + newname, + label=newname, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "float": + aparm = gxtp.FloatParam( + newname, + label=newname, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + else: + raise ValueError( + 'Unrecognised parameter type "%s" for\ + additional parameter %s in makeXML' + % (newtype, newname) + ) + aparm.positional = self.is_positional + if self.is_positional: + aninput.positional = int(oldcl) + self.tinputs.append(aparm) + self.tparm = gxtp.TestParam(newname, value=newval) + self.testparam.append(tparm) + + def doNoXMLparam(self): + alab = self.infiles[0][ILABPOS] + if len(alab) == 0: + alab = self.infiles[0][ICLPOS] + max1s = ( + "Maximum one input if parampass is 0 - more than one input files supplied - %s" + % str(self.infiles) + ) + assert len(self.infiles) == 1, max1s + newname = self.infiles[0][ICLPOS] + aninput = gxtp.DataParam( + newname, + optional=False, + label=alab, + help=self.infiles[0][IHELPOS], + format=self.infiles[0][IFMTPOS], + multiple=False, + num_dashes=0, + ) + aninput.command_line_override = "< $%s" % newname + aninput.positional = self.is_positional + self.tinputs.append(aninput) + tp = gxtp.TestParam(name=newname, value="%s_sample" % newname) + self.testparam.append(tp) + newname = self.outfiles[0][OCLPOS] + newfmt = self.outfiles[0][OFMTPOS] + anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0) + anout.command_line_override = "> $%s" % newname + anout.positional = self.is_positional + self.toutputs.append(anout) + tp = gxtp.TestOutput( + name=newname, value="%s_sample" % newname, format=newfmt + ) + self.testparam.append(tp) + + def makeXML(self): + """ + Create a Galaxy xml tool wrapper for the new script + Uses galaxyhtml + Hmmm. How to get the command line into correct order... + """ + self.tool.command_line_override = self.xmlcl + if self.args.interpreter_name: + self.tool.interpreter = self.args.interpreter_name + if self.args.help_text: + helptext = open(self.args.help_text, "r").readlines() + helptext = [html_escape(x) for x in helptext] + self.tool.help = "".join([x for x in helptext]) + else: + self.tool.help = ( + "Please ask the tool author (%s) for help \ + as none was supplied at tool generation\n" + % (self.args.user_email) + ) + self.tool.version_command = None # do not want + requirements = gxtp.Requirements() + + if self.args.interpreter_name: + if self.args.interpreter_name == "python": + requirements.append( + gxtp.Requirement( + "package", "python", self.args.interpreter_version + ) + ) + elif self.args.interpreter_name not in ["bash", "sh"]: + requirements.append( + gxtp.Requirement( + "package", + self.args.interpreter_name, + self.args.interpreter_version, + ) + ) + else: + if self.args.exe_package and self.args.parampass != "system": + requirements.append( + gxtp.Requirement( + "package", + self.args.exe_package, + self.args.exe_package_version, + ) + ) + self.tool.requirements = requirements + if self.args.parampass == "0": + self.doNoXMLparam() + else: + self.doXMLparam() + self.tool.outputs = self.toutputs + self.tool.inputs = self.tinputs + if self.args.runmode not in ["Executable", "system"]: + configfiles = gxtp.Configfiles() + configfiles.append(gxtp.Configfile(name="runMe", text=self.script)) + self.tool.configfiles = configfiles + tests = gxtp.Tests() + test_a = gxtp.Test() + for tp in self.testparam: + test_a.append(tp) + tests.append(test_a) + self.tool.tests = tests + self.tool.add_comment( + "Created by %s at %s using the Galaxy Tool Factory." + % (self.args.user_email, timenow()) + ) + self.tool.add_comment("Source in git at: %s" % (toolFactoryURL)) + self.tool.add_comment( + "Cite: Creating re-usable tools from scripts doi: 10.1093/bioinformatics/bts573" + ) + exml = self.tool.export() + xf = open('%s.xml' % self.tool_name, "w") + xf.write(exml) + xf.write("\n") + xf.close() + # ready for the tarball + + def makeTooltar(self): + """ + a tool is a gz tarball with eg + /toolname/tool.xml /toolname/tool.py /toolname/test-data/test1_in.foo ... + NOTE names for test inputs and outputs are munged here so must + correspond to actual input and output names used on the generated cl + """ + retval = self.run() + if retval: + sys.stderr.write( + "## Run failed. Cannot build yet. Please fix and retry" + ) + sys.exit(1) + tdir = "tfout" + if not os.path.exists(tdir): + os.mkdir(tdir) + self.makeXML() + testdir = os.path.join(tdir, "test-data") + if not os.path.exists(testdir): + os.mkdir(testdir) # make tests directory + for p in self.infiles: + pth = p[IPATHPOS] + dest = os.path.join(testdir, "%s_sample" % p[ICLPOS]) + shutil.copyfile(pth, dest) + for p in self.outfiles: + pth = p[OCLPOS] + if p[OOCLPOS] == "STDOUT" or self.args.parampass == "0": + pth = p[ONAMEPOS] + dest = os.path.join(testdir, "%s_sample" % p[ONAMEPOS]) + shutil.copyfile(pth, dest) + dest = os.path.join(tdir, p[ONAMEPOS]) + shutil.copyfile(pth, dest) + else: + pth = p[OCLPOS] + dest = os.path.join(testdir, "%s_sample" % p[OCLPOS]) + shutil.copyfile(pth, dest) + dest = os.path.join(tdir, p[OCLPOS]) + shutil.copyfile(pth, dest) + + if os.path.exists(self.tlog) and os.stat(self.tlog).st_size > 0: + shutil.copyfile(self.tlog, os.path.join(testdir, "test1_log_outfiletxt")) + if self.args.runmode not in ["Executable", "system"]: + stname = os.path.join(tdir, "%s" % (self.sfile)) + if not os.path.exists(stname): + shutil.copyfile(self.sfile, stname) + xreal = '%s.xml' % self.tool_name + xout = os.path.join(tdir,xreal) + shutil.copyfile(xreal, xout) + tarpath = "toolfactory_%s.tgz" % self.tool_name + tf = tarfile.open(tarpath, "w:gz") + tf.add(name=tdir, arcname=self.tool_name) + tf.close() + shutil.copyfile(tarpath, self.args.new_tool) + shutil.copyfile(xreal,"tool_xml.txt") + repdir = "TF_run_report_tempdir" + if not os.path.exists(repdir): + os.mkdir(repdir) + repoutnames = [x[OCLPOS] for x in self.outfiles] + with os.scandir('.') as outs: + for entry in outs: + if entry.name.endswith('.tgz') or not entry.is_file(): + continue + if entry.name in repoutnames: + shutil.copyfile(entry.name,os.path.join(repdir,entry.name)) + elif entry.name == "%s.xml" % self.tool_name: + shutil.copyfile(entry.name,os.path.join(repdir,"new_tool_xml")) + return retval + + def run(self): + """ + Some devteam tools have this defensive stderr read so I'm keeping with the faith + Feel free to update. + """ + s = "run cl=%s" % str(self.cl) + + logging.debug(s) + scl = " ".join(self.cl) + err = None + if self.args.parampass != "0": + ste = open(self.elog, "wb") + if self.lastclredirect: + sto = open( + self.lastclredirect[1], "wb" + ) # is name of an output file + else: + sto = open(self.tlog, "wb") + sto.write( + bytes( + "## Executing Toolfactory generated command line = %s\n" + % scl, + "utf8", + ) + ) + sto.flush() + p = subprocess.run(self.cl, shell=False, stdout=sto, stderr=ste) + sto.close() + ste.close() + tmp_stderr = open(self.elog, "rb") + err = "" + buffsize = 1048576 + try: + while True: + err += str(tmp_stderr.read(buffsize)) + if not err or len(err) % buffsize != 0: + break + except OverflowError: + pass + tmp_stderr.close() + retval = p.returncode + else: # work around special case of simple scripts that take stdin and write to stdout + sti = open(self.infiles[0][IPATHPOS], "rb") + sto = open(self.outfiles[0][ONAMEPOS], "wb") + # must use shell to redirect + p = subprocess.run(self.cl, shell=False, stdout=sto, stdin=sti) + retval = p.returncode + sto.close() + sti.close() + if os.path.isfile(self.tlog) and os.stat(self.tlog).st_size == 0: + os.unlink(self.tlog) + if os.path.isfile(self.elog) and os.stat(self.elog).st_size == 0: + os.unlink(self.elog) + if p.returncode != 0 and err: # problem + sys.stderr.write(err) + logging.debug("run done") + return retval + + +def main(): + """ + This is a Galaxy wrapper. It expects to be called by a special purpose tool.xml as: + rgBaseScriptWrapper.py --script_path "$scriptPath" --tool_name "foo" --interpreter "Rscript" + + """ + parser = argparse.ArgumentParser() + a = parser.add_argument + a("--script_path", default="") + a("--tool_name", default=None) + a("--interpreter_name", default=None) + a("--interpreter_version", default=None) + a("--exe_package", default=None) + a("--exe_package_version", default=None) + a("--input_files", default=[], action="append") + a("--output_files", default=[], action="append") + a("--user_email", default="Unknown") + a("--bad_user", default=None) + a("--make_Tool", default=None) + a("--help_text", default=None) + a("--tool_desc", default=None) + a("--tool_version", default=None) + a("--citations", default=None) + a("--additional_parameters", action="append", default=[]) + a("--edit_additional_parameters", action="store_true", default=False) + a("--parampass", default="positional") + a("--tfout", default="./tfout") + a("--new_tool", default="new_tool") + a("--runmode", default=None) + args = parser.parse_args() + assert not args.bad_user, ( + 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to "admin_users" in the Galaxy configuration file' + % (args.bad_user, args.bad_user) + ) + assert ( + args.tool_name + ), "## Tool Factory expects a tool name - eg --tool_name=DESeq" + assert ( + args.interpreter_name or args.exe_package + ), "## Tool Factory wrapper expects an interpreter or an executable package" + assert args.exe_package or ( + len(args.script_path) > 0 and os.path.isfile(args.script_path) + ), "## Tool Factory wrapper expects a script path - eg --script_path=foo.R if no executable" + args.input_files = [ + x.replace('"', "").replace("'", "") for x in args.input_files + ] + # remove quotes we need to deal with spaces in CL params + for i, x in enumerate(args.additional_parameters): + args.additional_parameters[i] = args.additional_parameters[i].replace( + '"', "" + ) + r = ScriptRunner(args) + if args.make_Tool: + retcode = r.makeTooltar() + else: + retcode = r.run() + if retcode: + sys.exit(retcode) # indicate failure to job runner + + +if __name__ == "__main__": + main() diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/output2_sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/test-data/output2_sample Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,165 @@ +*trats uoy erofeb GNINRAW* + +YLNO yxalaG etavirp a no loot siht llatsnI +ecnatsni noitcudorp ro cilbup a no REVEN esaelP + +troppus noitatic gnidda notlihC nhoJ yb 4102 tsugua detadpU + +keeB ned nav suiraM yb detroper sgub xif ot 4102 8 tsugua detadpU + +ta ecruoser eht etic esaelP +fer=epytyek&JWYdwMrWs1hQzcl=yekji?375stb/tnirper/igc/gro.slanruojdrofxo.scitamrofnioib//:ptth +.krow dehsilbup ruoy ni loot siht esu uoy fi + +**yrotS trohS** + +.sloot yxalaG wen gnitareneg fo elbapac loot yxalaG lausunu na si sihT +gnitpircs suoregnad ylemertxe erofereht dna *detcirtsernu* gnisopxe yb skrow tI +ot meht gniwolla ,revres yxalaG tsoh eht fo srotartsinimda detangised lla ot +,stes atad tupni detceles elpitlum revo lrep dna hs ,nohtyp ,R ni stpircs nur +.tuptuo sa tes atad wen elgnis a gnitirw + +*sretemarap elyts esrapgra ro lanoitisop htiw elbatucexe yna ro tpircs hsab/lrep/nohtyp/r gnikrow a evah uoY* + +.loot yxalaG a gnisu ,setunim ni loot yxalaG yranidro na otni denrut eb nac tI + + +**yxalaG yna otni noitallatsni rof sloot yxalaG wen fo noitareneg detamotuA** + +.ylppus uoy sgnittes retemarap dna stupni atad tset elpmas llams gnisu detareneg si tset A +a dliub ot desu eb nac yeht ,decudorp neeb evah stuptuo esac tset eht ecnO +tnemeriuqer a sa dekab si elbatucexe ro tpircs deilppus ehT .loot yxalaG wen +.xob eht fo tuo elbitapmoc wolfkrow ylluf ,loot yxalaG yranidro ,wen a otni +rotartsinimda na yb dehs loot a aiv dellatsni era sloot detareneG +.sresu ruoy rof sloot yxalaG rehto lla ekil yltcaxe krow dna + +**liateD eroM** + +a otni etsap ot tpircs a deraperp evah dluohs uoy ,yrotcaFlooT eht esu oT +yrotsih ruoy morf tceles ot ydaer elpmaxe tupni tset llams a dna dnim ni egakcap a evah ro ,xob txet +.tpircs wen ruoy tset ot + +em rof skrow ```atad-tset/yrotcafloot/srekam_loot/sloot/yxalag/~ atad_tset-- yxalag/~ toor_yxalag-- lmx.2yrotcaFlooTgr tset omenalp``` + +uoY .mrof yrotcaF looT eht no egaugnal gnitpircs hcae ni elpmaxe na si erehT +thgir eht tceles ot rebmemer - tuo ti yrt ot eseht etsap dna tuc tsuj nac +gnisu tes atad tset llams a etaerc ot deen osla ll'uoY .esaelp reterpretni +.loot atad wen dda yrotsih yxalaG eht + +ni tuptuo loot eht no nottub "oder" eht esu ,wohemos sliaf tpircs eht fI +gub eht xiF .tpircs nekorb htiw etelpmoc mrof eht etaercer ot yrotsih ruoy +.taeper ,hsaw ,esniR .niaga etucexe dna + +tpircs ruoy snur taht loot yxalaG wen a ,yllufssecus snur tpircs eht ecnO +dna txet pleh emos ylppus dna noitpo "etareneg" eht tceleS .detareneg eb nac +epytatad yxalaG wen a fo mrof eht ni detareneg eb lliw loot wen ehT .seman +a ot daolpu ot ydaer evihcra na s'ti ,stseggus eman eht sa - *zg.dehsloot* +.yrotisoper loot wen a sa dehSlooT yxalaG + +revres yxalaG lacol yna otni dellatsni eb nac ti ,dehSlooT a ni s'ti ecnO +.ecafretni evitartsinimda revres eht morf + +tpircs eht ,emit hcae - ti nur nac sresu lacol ,dellatsni si loot wen eht ecnO +nesohc tupni eht htiw detucexe eb lliw tliub saw ti nehw deilppus saw taht +eht htiw etareneg uoy sloot eht ,sdrow rehto nI .yrotsih s'resu eht morf +.emit yreve tpircs ruoy nur tub,loot yxalaG rehto yna ekil tsuj nur yrotcaFlooT + +,tuptuo eno ,tupni enO .stnenopmoc wolfkrow rof tcefrep era sloot yrotcaf looT +.selbairav on + +,loot siht fo *rewop emosewa eht tiolpxe ylefas dna ylluf oT* +siht gnillatsni repoleved a eb dluohs uoy ,dehSlooT eht dna yxalaG +na era uoy erehw ecnatsni lacol hctarcs/lanosrep/etavirp a no loot +ees seceip eht lla peek ot teg uoy ,ti kaerb uoy fi ,nehT .resu_nimda +emoH/ikiw/yrotcaflootyxalag/rabuf/gro.tekcubtib//:sptth + +**noitallatsnI** +eht gnisu yltneinevnoc tsom ti llatsni nac uoY .loot yxalaG a si sihT +niaM yxalaG eht dniF .knil "sdehs loot esworb dna hcraeS" evitartsinimda +yrotcafloot eht rof hcraes dna /ude.usp.xb.2g.dehsloot//:sptth ta dehsloot +.ti llatsni ot noitpo eht tceles dna edoc eht weiver dna ti nepO .yrotisoper + +eb ot deen ereh selif yp dna lmx eht ,yaw taht loot eht teg t'nac uoy fI +sloot wen a otni deipoc +yrtne wen a sdeen lmx.fnoc_loot ruoY yrotcafloot/sloot sa hcus yrotceridbus +lmx eht ot gnitniop +::ekil gnihtemos - elif + +>"sredliubloot"=di "sloot gnidliub looT"=eman noitces< +>/"lmx.yrotcaFlooTgr/yrotcafloot"=elif loot< +>noitces/< + +,ereht ydaerla ton fI +:dda esaelp +"yraniB:yranib.sepytatad.yxalag"=epyt "zg.dehsloot"=noisnetxe epytatad< +>/ "eurT"=ssalcbus "pizg-x/trapitlum"=epytemim +.lmx.fnoc_sepyt_atad lacol ruoy ot + + +**noitucexe detcirtseR** + +- sresu nimda yb YLNO elbasu eb neht lliw flesti loot yrotcaf loot ehT +YLNO .thgir s'taht ,seY** ini.igsw_esrevinu ni sresu_nimda ni sDI htiw elpoep +ot dewolla fI .tnemom a rof ti tuoba knihT **loot siht nur nac sresu_nimda +dluow taht gniht ylno eht ,revres yxalaG ruoy no tpircs yrartibra yna nur +ylbaborp dluow atad yxalaG ruoy lla gniyortsed no tneb tnaercsim a edepmi +.slliks lacinhcet etairporppa fo kcal eb + +**seod ti tahW** + +dna R ,nohtyp ni stpircs elpmis rof yrotcaf loot a si sihT +.taht si looc woH .detareneg yllacitamotua era stset lanoitcnuF .yltnerruc lrep + +nac yllanoitpO .yrotsih eht morf tupni eno daer taht stpircs elpmis ot DETIMIL +stuptuo fo rebmun yna tcelloc yllanoitpo dna ,tesatad yrotsih wen eno etirw +- etagivan ot resu eht rof egap xedni LMTH detarenegotua na no sknil otni +nwohs era stuptuo fdp - selif tuptuo dna segami setirw tpircs eht fi lufesu +dna taht os tpircstsohg htiw knurhs era s'fdp detaolb s'R dna slianbmuht sa +.elbaliava eb ot deen kigamegami + +trats os ,loot yxalaG yna ekil decnahne dna detide eb nac sloot detareneG +a ot pu gel suoires a uoy steg tpircs detareneg a ecnis pu dliub dna llams +.eno xelpmoc erom + +**od uoy tahW** + +dna srorre xatnys eht xif uoy ,tpircs ruoy nur dna etsap uoY +erofeb tpircs eht tide dna nottub oder eht esu nac uoY .snur ti yllautneve +.llew ytterp skrow ti - gubed uoy sa ti nurer ot gniyrt + +elbitapmoc dehsloot a etareneg nac uoy ,atad tset emos no skrow tpircs eht ecnO +ni loot yxalaG yranidro na sa nur ot ydaer tpircs ruoy gniniatnoc elif pizg +detamotua ylegral dna efas snaem tahT .dehsloot lacol ruoy no yrotisoper a +.dehsloot ruoy esu ot derugifnoc yxalaG noitcudorp yna ni noitallatsni + +**ytiruceS loot detareneG** + +tsuj s'ti ,loot detareneg a llatsni uoy ecnO +rieht dna yllamron nur tsuj yehT .efas si tpircs eht gnimussa - loot rehtona +.dehsloot efas ecitcarp ,esaelp tub erucesni yllausunu gnihtyna od tonnac resu +.yracs yllaer si ti - eno siht yllaicepsE .loot yna llatsni uoy erofeb edoc eht daeR + +**edoC dneS** + +?esaelp seussi tekcubtib sa emoclew snoitseggus dna sehctaP + +**noitubirttA** + +yrotcaF looT yxalaG ehT :stpircs morf sloot elbasu-er gnitaerC +maeT yxalaG ehT ;nnameiZ kraM ;ipsaK ynotnA ;surazaL ssoR +375stb/scitamrofnioib/3901.01 :iod ;2102 scitamrofnioiB + +fer=epytyek&JWYdwMrWs1hQzcl=yekji?375stb/tnirper/igc/gro.slanruojdrofxo.scitamrofnioib//:ptth + +**gnisneciL** + +0102 surazaL ssoR thgirypoC +moc doirep liam g ta surazal ssor + +.devreser sthgir llA + +LPGL eht rednu desneciL + +**tohsneercs yrotagilbO** + +gnp.looTtpircScimanyd/segami/989ef2308adf/crs/rekamlootyxalag/rabuf/gro.tekcubtib//:ptth diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/pyrevpos.python --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/test-data/pyrevpos.python Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,13 @@ +# reverse order of text by row +import sys +inp = sys.argv[1] +outp = sys.argv[2] +i = open(inp,'r').readlines() +o = open(outp,'w') +for row in i: + rs = row.rstrip() + rs = list(rs) + rs.reverse() + o.write(''.join(rs)) +o.close() + diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/pyrevpos_not_tested.toolshed_sample Binary file toolfactory/test-data/pyrevpos_not_tested.toolshed_sample has changed diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/test1_log.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/test-data/test1_log.txt Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1 @@ +## Executing Toolfactory generated command line = python /tmp/pyrevposq5dmcdy1.python /tmp/tmpqrksf8sd/files/5/b/9/dataset_5b952a86-87df-44ad-a415-ea549f3f0cee.dat output2 diff -r 2beaae16651e -r 0183cad9d13b toolfactory/test-data/toolfactory_pyrevpos_tgz_sample Binary file toolfactory/test-data/toolfactory_pyrevpos_tgz_sample has changed diff -r 2beaae16651e -r 0183cad9d13b toolfactory/toolfactory.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/toolfactory.py Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,1393 @@ +# see https://github.com/fubar2/toolfactory +# +# copyright ross lazarus (ross stop lazarus at gmail stop com) May 2012 +# +# all rights reserved +# Licensed under the LGPL +# suggestions for improvement and bug fixes welcome at +# https://github.com/fubar2/toolfactory +# +# February 2023: Refactored to use galaxy-tool-test script in galaxyutil +# planemo not needed if tool is already installed. +# sqlite does not seem to work - switch to postgresql in the installation script +# +# march 2022: Refactored into two tools - generate and test/install +# as part of GTN tutorial development and biocontainer adoption +# The tester runs planemo on a non-tested archive, creates the test outputs +# and returns a new proper tool with test. + + +import argparse +import copy +import json +import logging +import os +import re +import shlex +import shutil +import subprocess +import sys +import tarfile +import tempfile +import time + +from bioblend import galaxy +from bioblend import ConnectionError + +import galaxyxml.tool as gxt +import galaxyxml.tool.parameters as gxtp + +import lxml.etree as ET + +import yaml + + +logger = logging.getLogger(__name__) + + +class Tool_Factory: + """Wrapper for an arbitrary script + uses galaxyxml + """ + + def __init__(self, args=None): # noqa + """ + prepare command line cl for running the tool here + and prepare elements needed for galaxyxml tool generation + """ + assert args.parampass in [ + "0", + "embed", + "argparse", + "positional", + "embednfmod", + ], ( + "args.parampass %s not 0,positional, embed, embednfmod or argparse" + % args.parampass + ) + # sed will update these settings during tfsetup.py first run + self.GALAXY_ADMIN_KEY = "1718977735397126400" + self.GALAXY_URL = "http://localhost:8080" + self.profile = "22.05" + self.not_iuc = True + self.args = args + self.tool_version = self.args.tool_version + self.myversion = "V3.0 February 2023" + self.verbose = True + self.debug = True + self.toolFactoryURL = "https://github.com/fubar2/galaxy_tf_overlay" + self.logger = logging.getLogger(__name__) + self.nfcoremod = False + if args.parampass == "embednfmod": + self.nfcoremod = True + self.script_in_help = False # IUC recommendation + self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name) + self.tool_id = self.tool_name + self.local_tools = os.path.realpath( + os.path.join(args.galaxy_root, "local_tools") + ) + self.repdir = os.path.realpath(args.tfcollection) + self.testdir = os.path.join(self.repdir, self.tool_name) + self.toold = os.path.join(self.local_tools, self.tool_name) + self.tooltestd = os.path.join(self.toold, "test-data") + if self.nfcoremod: + self.local_tools = os.path.join(args.tfcollection, "tools") + self.repdir = os.path.join(args.tfcollection, "TFouts", self.tool_name) + self.toold = os.path.join(self.local_tools, self.tool_name) + self.tooltestd = os.path.join(self.toold, "test-data") + os.makedirs(self.repdir, exist_ok=True) + os.makedirs(self.toold, exist_ok=True) + os.makedirs(self.tooltestd, exist_ok=True) + os.makedirs(self.local_tools, exist_ok=True) + self.local_tool_conf = os.path.join(self.local_tools, "local_tool_conf.xml") + self.ourcwd = os.getcwd() + self.collections = [] + if len(args.collection) > 0: + try: + self.collections = [ + json.loads(x) for x in args.collection if len(x.strip()) > 1 + ] + except Exception: + self.logger.error( + f"--collections parameter {str(args.collection)} is malformed - should be a dictionary" + ) + self.infiles = [] + try: + self.infiles = [ + json.loads(x) for x in args.input_files if len(x.strip()) > 1 + ] + except Exception: + self.logger.error( + f"--input_files parameter {str(args.input_files)} is malformed - should be a dictionary" + ) + self.extra_files = [] + if len(args.xtra_files) > 0: + try: + self.extra_files = [ + json.loads(x) for x in args.xtra_files if len(x.strip()) > 1 + ] + except Exception: + self.logger.error( + f"--xtra_files parameter {str(args.xtra_files)} is malformed - should be a dictionary" + ) + self.outfiles = [] + try: + self.outfiles = [ + json.loads(x) for x in args.output_files if len(x.strip()) > 1 + ] + except Exception: + self.logger.error( + f"--output_files parameter {args.output_files} is malformed - should be a dictionary" + ) + assert ( + len(self.outfiles) + len(self.collections) + ) > 0, "No outfiles or output collections specified. The Galaxy job runner will fail without an output of some sort" + self.addpar = [] + try: + self.addpar = [ + json.loads(x) for x in args.additional_parameters if len(x.strip()) > 1 + ] + except Exception: + self.logger.error( + f"--additional_parameters {args.additional_parameters} is malformed - should be a dictionary" + ) + self.selpar = [] + try: + self.selpar = [ + json.loads(x) for x in args.selecttext_parameters if len(x.strip()) > 1 + ] + except Exception: + self.logger.error( + f"--selecttext_parameters {args.selecttext_parameters} is malformed - should be a dictionary" + ) + self.selfagpar = [] + try: + self.selflagpar = [ + json.loads(x) for x in args.selectflag_parameters if len(x.strip()) > 1 + ] + except Exception: + self.logger.error( + f"--selectflag_parameters {args.selecttext_parameters} is malformed - should be a dictionary" + ) + self.cleanuppar() + self.lastxclredirect = None + self.xmlcl = [] + self.is_positional = self.args.parampass == "positional" + self.is_embedded = self.args.parampass == "embedded" + if self.args.sysexe: + if " " in self.args.sysexe: + self.executeme = shlex.split(self.args.sysexe) + else: + self.executeme = [ + self.args.sysexe, + ] + else: + if self.args.packages: + self.executeme = [ + self.args.packages.split(",")[0].split(":")[0].strip(), + ] + else: + self.executeme = [] + aXCL = self.xmlcl.append + self.newtarpath = args.tested_tool_out + self.tinputs = gxtp.Inputs() + self.toutputs = gxtp.Outputs() + self.testparam = [] + if self.args.script_path: + self.prepScript() + else: + self.script = None + if self.args.cl_override != None: + scos = open(self.args.cl_override, "r").readlines() + self.cl_override = [x.rstrip() for x in scos] + else: + self.cl_override = None + if self.args.test_override != None: + stos = open(self.args.test_override, "r").readlines() + self.test_override = [x.rstrip() for x in stos] + else: + self.test_override = None + if self.args.cl_prefix != None: + scos = open(self.args.cl_prefix, "r").readlines() + self.cl_prefix = [x.rstrip() for x in scos] + else: + self.cl_prefix = None + if self.args.cl_suffix != None: + stos = open(self.args.cl_suffix, "r").readlines() + self.cl_suffix = [x.rstrip() for x in stos] + else: + self.cl_suffix = None + if self.args.script_path: + for ex in self.executeme: + if ex: + aXCL(ex) + aXCL("'$runme'") + else: + for ex in self.executeme: + aXCL(ex) + if self.args.parampass == "0": + self.clsimple() + elif self.args.parampass == "positional": + self.prepclpos() + self.clpositional() + elif self.args.parampass == "argparse": + self.prepargp() + self.clargparse() + elif self.args.parampass.startswith("embed"): + self.prepembed() + else: + logging.error( + "Parampass value %s not in 0, positional, argparse, embed or embednfmod" + % self.args.parampass + ) + logging.shutdown() + sys.exit(6) + + def clsimple(self): + """no parameters or repeats - uses < and > for i/o""" + aXCL = self.xmlcl.append + if len(self.infiles) > 0: + aXCL("<") + aXCL("'$%s'" % self.infiles[0]["infilename"]) + if len(self.outfiles) > 0: + aXCL(">") + aXCL("'$%s'" % self.outfiles[0]["name"]) + + def prepembed(self): + """fix self.script""" + scrip = self.script + if self.nfcoremod: + self.script = ( + '#set prefix = "%s"\n#set task_process = "%s"\n' + % (self.tool_name, self.tool_name) + + scrip + ) + self.xmlcl = [] # wipe anything there + aX = self.xmlcl.append + aX("") + if self.nfcoremod: + aX('#set prefix = "%s"' % self.tool_name) + aX('#set task_process = "%s"' % self.tool_name) + for p in self.collections: + aX("mkdir -p %s &&" % p["name"]) + aX("%s '$runme'" % self.args.sysexe) + + def prepargp(self): + xclsuffix = [] + for i, p in enumerate(self.infiles): + rep = p["required"] in ["optional1", "required1"] + req = p["required"] in ["required", "required1"] + nam = p["infilename"] + flag = p["CL"] + if p["origCL"].strip().upper() == "STDIN": + xappendme = [ + nam, + nam, + "< '$%s'" % nam, + ] + else: + xappendme = [p["CL"], "'$%s'" % p["CL"], ""] + xclsuffix.append(xappendme) + for i, p in enumerate(self.outfiles): + if p["origCL"].strip().upper() == "STDOUT": + self.lastxclredirect = [">", "'$%s'" % p["name"]] + else: + xclsuffix.append([p["name"], "'$%s'" % p["name"], ""]) + for p in self.addpar: + nam = p["name"] + val = p["value"] + flag = p["CL"] + rep = p.get("repeat", 0) == "1" + if rep: + over = f'#for $rep in $R_{nam}:\n--{nam} "$rep.{nam}"\n#end for' + else: + over = p.get("override", "") + if p["type"] == "clflag": + over = f'#if ${nam} == "set"\n --{flag}\n#end if' + xclsuffix.append([p["CL"], "'$%s'" % nam, over]) + for p in self.selpar: + xclsuffix.append([p["CL"], "'$%s'" % p["name"], p.get("override", "")]) + for p in self.selflagpar: + xclsuffix.append(["", "'$%s'" % p["name"], ""]) + for p in self.collections: + newname = p["name"] + xclsuffix.append([newname, "'%s'" % newname, ""]) + self.xclsuffix = xclsuffix + + def prepclpos(self): + xclsuffix = [] + for i, p in enumerate(self.infiles): + if p["origCL"].strip().upper() == "STDIN": + xappendme = [ + "999", + p["infilename"], + "< '$%s'" % p["infilename"], + ] + else: + xappendme = [p["CL"], "'$%s'" % p["infilename"], ""] + xclsuffix.append(xappendme) + for i, p in enumerate(self.outfiles): + if p["origCL"].strip().upper() == "STDOUT": + self.lastxclredirect = [">", "'$%s'" % p["name"]] + else: + xclsuffix.append([p["CL"], "'$%s'" % p["name"], ""]) + for p in self.addpar: + nam = p["name"] + rep = p.get("repeat", "0") == "1" # repeats make NO sense + if rep: + logger.warning( + f"### warning. Repeats for {nam} ignored - not permitted in positional parameter command lines!" + ) + over = p.get("override", "") + xclsuffix.append([p["CL"], "'$%s'" % nam, over]) + for p in self.selpar: + xclsuffix.append([p["CL"], "'$%s'" % p["name"], p.get("override", "")]) + for p in self.selflagpar: + xclsuffix.append(["", "'$%s'" % p["name"], ""]) + for p in self.collections: + newname = p["name"] + xclsuffix.append([newname, "'$%s'" % newname, ""]) + xclsuffix.sort() + self.xclsuffix = xclsuffix + + def prepScript(self): + s = open(self.args.script_path, "r").read() + ss = s.split("\n") + rxcheck = [x for x in ss if x.strip() > ""] + assert len(rxcheck) > 0, "Supplied script is empty. Cannot run" + if self.args.sysexe and self.args.parampass != "embed": + rxcheck.insert(0, "#raw") + rxcheck.append("#end raw") + self.script = "\n".join(rxcheck) + if len(self.executeme) > 0: + self.sfile = os.path.join( + self.repdir, "%s.%s.txt" % (self.tool_name, self.executeme[0]) + ) + else: + self.sfile = os.path.join( + self.repdir, "%s.script.txt" % (self.tool_name) + ) + tscript = open(self.sfile, "w") + tscript.write(self.script) + tscript.write("\n") + tscript.close() + self.spacedScript = [ + f" {x.replace('${','$ {')}" for x in ss if x.strip() > "" + ] + self.escapedScript = rxcheck + + def cleanuppar(self): + """positional parameters are complicated by their numeric ordinal""" + if self.args.parampass == "positional": + for i, p in enumerate(self.infiles): + assert ( + p["CL"].isdigit() or p["CL"].strip().upper() == "STDIN" + ), "Positional parameters must be ordinal integers - got %s for %s" % ( + p["CL"], + p["label"], + ) + for i, p in enumerate(self.outfiles): + assert ( + p["CL"].isdigit() or p["CL"].strip().upper() == "STDOUT" + ), "Positional parameters must be ordinal integers - got %s for %s" % ( + p["CL"], + p["name"], + ) + for i, p in enumerate(self.addpar): + assert p[ + "CL" + ].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % ( + p["CL"], + p["name"], + ) + for i, p in enumerate(self.infiles): + infp = copy.copy(p) + infp["origCL"] = infp["CL"] + if self.args.parampass in ["positional", "0"]: + infp["infilename"] = infp["label"].replace(" ", "_") + else: + infp["infilename"] = infp["CL"] + self.infiles[i] = infp + for i, p in enumerate(self.outfiles): + outfp = copy.copy(p) + outfp["origCL"] = outfp["CL"] # keep copy + if outfp.get("label", None) == None: + outfp["label"] = "" + self.outfiles[i] = outfp + for i, p in enumerate(self.addpar): + addp = copy.copy(p) + addp["origCL"] = addp["CL"] + self.addpar[i] = addp + for i, p in enumerate(self.collections): + addp = copy.copy(p) + addp["CL"] = addp["name"] + self.collections[i] = addp + + def clpositional(self): + # inputs in order then params + aXCL = self.xmlcl.append + for (k, v, koverride) in self.xclsuffix: + aXCL(v) + if self.lastxclredirect: + for cl in self.lastxclredirect: + aXCL(cl) + + def clargparse(self): + """argparse style""" + aXCL = self.xmlcl.append + # inputs then params in argparse named form + for (k, v, koverride) in self.xclsuffix: + if koverride > "": + k = koverride + aXCL(k) + else: + kl = len(k.strip()) + if kl == 0: + k = " " + elif kl == 1: + k = "-%s" % k + else: + k = "--%s" % k + aXCL(k) + aXCL(v) + if self.lastxclredirect: + for cl in self.lastxclredirect: + aXCL(cl) + + def getNdash(self, newname): + if self.is_positional: + ndash = 0 + else: + ndash = 2 + if len(newname) < 2: + ndash = 1 + return ndash + + def doXMLparam(self): # noqa + """Add all needed elements to tool""" + for p in self.outfiles: + newname = p["name"] + newfmt = p["format"] + newcl = p["CL"] + test = p["test"] + oldcl = p["origCL"] + test = test.strip() + filta = p.get("when", []) + lab = p.get("label", "") + if len(lab.strip()) == 0: + lab = newname + ndash = self.getNdash(newcl) + aparm = gxtp.OutputData( + name=newname, format=newfmt, num_dashes=ndash, label=lab + ) + if len(filta) > 0: + ofilta = gxtp.ChangeFormat() + for ( + whens + ) in filta: # when input=|image_type| value=|large_png| format=|png| + whenss = whens.replace("|", '"').replace("when ", "") + clauses = whenss.split() + for c in clauses: + if c.startswith("value"): + v = c.split("=")[1] + elif c.startswith("format"): + f = c.split("=")[1] + elif c.startswith("input"): + i = c.split("=")[1] + else: + print( + "bad when - need value=, format= and input=, got", whens + ) + owhen = gxtp.ChangeFormatWhen(format=f, input=i, value=v) + ofilta.append(owhen) + aparm.append(ofilta) + aparm.positional = self.is_positional + if self.is_positional: + if oldcl.upper() == "STDOUT": + aparm.positional = 9999999 + aparm.command_line_override = "> '$%s'" % newname + else: + aparm.positional = int(oldcl) + aparm.command_line_override = "'$%s'" % newname + self.toutputs.append(aparm) + ld = None + if test.strip() > "": + if test.strip().startswith("diff"): + c = "diff" + ld = 0 + if test.split(":")[1].isdigit: + ld = int(test.split(":")[1]) + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + lines_diff=ld, + ) + elif test.startswith("sim_size"): + c = "sim_size" + tn = test.split(":")[1].strip() + if tn > "": + if "." in tn: + delta = None + delta_frac = min(1.0, float(tn)) + else: + delta = int(tn) + delta_frac = None + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + delta=delta, + delta_frac=delta_frac, + ) + else: + c = test + tp = gxtp.TestOutput( + name=newname, + value="%s_sample" % newname, + compare=c, + ) + self.testparam.append(tp) + for p in self.infiles: + newname = p["infilename"] + newfmt = p["format"] + ndash = self.getNdash(newname) + reps = p.get("required", "") in ["optional1", "required1"] + isoptional = p.get("required", "") in ["optional", "optional1"] + if not len(p["label"]) > 0: + alab = p["CL"] + else: + alab = p["label"] + aninput = gxtp.DataParam( + newname, + optional=isoptional, + label=alab, + help=p["help"], + format=newfmt, + multiple=reps, + num_dashes=ndash, + ) + aninput.positional = self.is_positional + if self.is_positional: + if p["origCL"].upper() == "STDIN": + aninput.positional = 9999998 + aninput.command_line_override = "< '$%s'" % newname + else: + aninput.positional = int(p["origCL"]) + aninput.command_line_override = "'$%s'" % newname + self.tinputs.append(aninput) + tparm = gxtp.TestParam(newname, value="%s_sample" % newname) + self.testparam.append(tparm) + for p in self.addpar: + newname = p["name"] + newval = p.get("value", "") + newlabel = p["label"] + newhelp = p.get("help", "") + newtype = p.get("type", "?") + newcl = p["CL"] + oldcl = p["origCL"] + reps = p.get("repeat", "0") == "1" + if not len(newlabel) > 0: + newlabel = newname + ndash = self.getNdash(newname) + if newtype == "text": + aparm = gxtp.TextParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "integer": + aparm = gxtp.IntegerParam( + newname, + label=newlabel, + help=newhelp, + value=int(newval.replace("'", "").replace('"', "")), + num_dashes=ndash, + ) + elif newtype == "float": + aparm = gxtp.FloatParam( + newname, + label=newlabel, + help=newhelp, + value=float(newval.replace("'", "").replace('"', "")), + num_dashes=ndash, + ) + elif newtype == "boolean": + aparm = gxtp.BooleanParam( + newname, + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + elif newtype == "clflag": + initval = newval + aparm = gxtp.SelectParam( + newname, + label=newlabel, + help=newhelp, + num_dashes=ndash, + display="radio", + ) + anoptt = gxtp.SelectOption( + value="set", + text="Set this flag", + ) + anoptf = gxtp.SelectOption( + value="notset", + text="Do not set this flag", + ) + if p["value"] == "set": # make default same as form + aparm.append(anoptt) + aparm.append(anoptf) + else: + aparm.append(anoptf) + aparm.append(anoptt) + elif newtype == "datacolumn": + aparm = gxtp.TextParam( + newname, + type="data_column", + data_ref=p["dataref"], + multiple=(p["multiple"] == "1"), + label=newlabel, + help=newhelp, + value=newval, + num_dashes=ndash, + ) + else: + raise ValueError( + 'Unrecognised parameter type "%s" for \ + additional parameter %s in makeXML' + % (newtype, newname) + ) + aparm.positional = self.is_positional + if self.is_positional: + aparm.positional = int(oldcl) + if reps: + repe = gxtp.Repeat( + name=f"R_{newname}", + title=f"Any number of {newlabel} repeats are allowed", + ) + repe.append(aparm) + self.tinputs.append(repe) + tparm = gxtp.TestRepeat(name=f"R_{newname}") + tparm2 = gxtp.TestParam(newname, value=newval) + tparm.append(tparm2) + self.testparam.append(tparm) + else: + self.tinputs.append(aparm) + tparm = gxtp.TestParam(newname, value=newval) + self.testparam.append(tparm) + for p in self.selpar: + newname = p["name"] + newval = p.get("value", "") + newlabel = p["label"] + newhelp = p["help"] + newtype = p["type"] + newcl = p["CL"] + if not len(newlabel) > 0: + newlabel = newname + ndash = self.getNdash(newname) + if newtype == "selecttext": + newtext = p["texts"] + aparm = gxtp.SelectParam( + newname, + label=newlabel, + help=newhelp, + num_dashes=ndash, + ) + for i in range(len(newval)): + anopt = gxtp.SelectOption( + value=newval[i], + text=newtext[i], + ) + aparm.append(anopt) + aparm.positional = self.is_positional + if self.is_positional: + aparm.positional = int(newcl) + self.tinputs.append(aparm) + tparm = gxtp.TestParam(newname, value=newval[0]) + self.testparam.append(tparm) + else: + raise ValueError( + 'Unrecognised parameter type "%s" for\ + selecttext parameter %s in makeXML' + % (newtype, newname) + ) + for p in self.selflagpar: + newname = p["name"] + newval = p["value"] + newlabel = p["label"] + newhelp = p["help"] + newtype = p["type"] + newtext = p["texts"] + newcl = p["CL"] + if not len(newlabel) > 0: + newlabel = newname + aparm = gxtp.SelectParam( + newname, + label=newlabel, + help=newhelp, + num_dashes=0, + ) + for i in range(len(newval)): + anopt = gxtp.SelectOption( + value=newval[i], + text=newtext[i], + ) + aparm.append(anopt) + aparm.positional = self.is_positional + if self.is_positional: + aparm.positional = int(newcl) + self.tinputs.append(aparm) + tparm = gxtp.TestParam(newname, value=newval[0]) + self.testparam.append(tparm) + + def doNoXMLparam(self): + """filter style package - stdin to stdout""" + if len(self.infiles) > 0: + alab = self.infiles[0]["label"] + if len(alab) == 0: + alab = self.infiles[0]["infilename"] + max1s = ( + "Maximum one input if parampass is 0 but multiple input files supplied - %s" + % str(self.infiles) + ) + assert len(self.infiles) == 1, max1s + newname = self.infiles[0]["infilename"] + aninput = gxtp.DataParam( + newname, + optional=False, + label=alab, + help=self.infiles[0]["help"], + format=self.infiles[0]["format"], + multiple=False, + num_dashes=0, + ) + aninput.command_line_override = "< $%s" % newname + aninput.positional = True + self.tinputs.append(aninput) + tp = gxtp.TestParam(name=newname, value="%s_sample" % newname) + self.testparam.append(tp) + if len(self.outfiles) > 0: + newname = self.outfiles[0]["name"] + newfmt = self.outfiles[0]["format"] + anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0) + anout.command_line_override = "> $%s" % newname + anout.positional = self.is_positional + self.toutputs.append(anout) + tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname) + self.testparam.append(tp) + + def makeXML(self): # noqa + """ + Create a Galaxy xml tool wrapper for the new script + Uses galaxyhtml + Hmmm. How to get the command line into correct order... + """ + requirements = gxtp.Requirements() + self.condaenv = [] + if self.args.packages: + try: + for d in self.args.packages.split(","): + ver = None + packg = None + d = d.replace("==", ":") + d = d.replace("=", ":") + if ":" in d: + packg, ver = d.split(":")[:2] + ver = ver.strip() + packg = packg.strip() + self.tool_version = ver + else: + packg = d.strip() + ver = None + if ver == "": + ver = None + if packg: + requirements.append( + gxtp.Requirement("package", packg.strip(), ver) + ) + self.condaenv.append(d) + except Exception: + self.logger.error( + "### malformed packages string supplied - cannot parse = %s" + % self.args.packages + ) + sys.exit(2) + elif self.args.container: + requirements.append(gxtp.Requirement("container", self.args.container)) + self.newtool = gxt.Tool( + self.tool_name, + self.tool_id, + self.tool_version, + self.args.tool_desc, + "", + profile=self.profile, + ) + self.newtool.requirements = requirements + iXCL = self.xmlcl.insert + aXCL = self.xmlcl.append + if self.args.cl_prefix: # DIY CL start + self.xmlcl = self.cl_prefix + self.xmlcl + if self.args.cl_suffix: # DIY CL end + self.xmlcl += self.cl_suffix + if self.cl_override: + self.newtool.command_override = self.cl_override # config file + else: + self.newtool.command_override = self.xmlcl + self.cites = self.parse_citations() + cite = gxtp.Citations() + if self.cites and len(self.cites) > 0: + for c in self.cites: + acite = gxtp.Citation(type=c[0], value=c[1]) + cite.append(acite) + acite = gxtp.Citation(type="doi", value="10.1093/bioinformatics/bts573") + cite.append(acite) + self.newtool.citations = cite + safertext = "" + if self.args.help_text: + self.helptext = open(self.args.help_text, "r").readlines() + safertext = "\n".join([self.cheetah_escape(x) for x in self.helptext]) + if len(safertext.strip()) == 0: + safertext = ( + "Ask the tool author (%s) to rebuild with help text please\n" + % (self.args.user_email) + ) + if self.script_in_help and self.args.script_path: + if len(safertext) > 0: + safertext = safertext + "\n\n------\n" # transition allowed! + scr = [x for x in self.spacedScript if x.strip() > ""] + scr.insert(0, "\n\nScript::\n") + if len(scr) > 300: + scr = ( + scr[:100] + + [" >300 lines - stuff deleted", " ......"] + + scr[-100:] + ) + scr.append("\n") + safertext = safertext + "\n".join(scr) + self.newtool.help = " ".join(self.helptext) + for p in self.collections: + newkind = p["kind"] + newname = p["name"] + newlabel = p["label"] + newdisc = p["discover"] + collect = gxtp.OutputCollection(newname, label=newlabel, type=newkind) + disc = gxtp.DiscoverDatasets( + pattern=newdisc, directory=f"{newname}", visible="false" + ) + collect.append(disc) + self.toutputs.append(collect) + try: + tparm = gxtp.TestOutputCollection(newname) # broken until PR merged. + self.testparam.append(tparm) + except Exception: + logging.error( + "WARNING: Galaxyxml version does not have the PR merged yet - tests for collections must be over-ridden until then!" + ) + self.newtool.version_command = f'echo "{self.tool_version}"' + if self.args.parampass == "0": + self.doNoXMLparam() + else: + self.doXMLparam() + self.newtool.outputs = self.toutputs + self.newtool.inputs = self.tinputs + if self.args.script_path: + configfiles = gxtp.Configfiles() + configfiles.append(gxtp.Configfile(name="runme", text=self.script)) + self.newtool.configfiles = configfiles + tests = gxtp.Tests() + test_a = gxtp.Test() + for tp in self.testparam: + test_a.append(tp) + tests.append(test_a) + self.newtool.tests = tests + self.newtool.add_comment( + "Created by %s at %s using the Galaxy Tool Factory." + % (self.args.user_email, self.timenow()) + ) + self.newtool.add_comment("Source in git at: %s" % (self.toolFactoryURL)) + exml = self.newtool.export() + if ( + self.test_override + ): # cannot do this inside galaxyxml as it expects lxml objects for tests + part1 = exml.split("")[0] + part2 = exml.split("")[1] + fixed = "%s\n%s\n%s" % (part1, "\n".join(self.test_override), part2) + exml = fixed + with open(os.path.join(self.toold, "%s.xml" % self.tool_name), "w") as xf: + xf.write(exml) + xf.write("\n") + with open(os.path.join(self.repdir, "%s_xml.xml" % self.tool_name), "w") as xf: + xf.write(exml) + xf.write("\n") + + def writeShedyml(self): + """for planemo""" + yuser = self.args.user_email.split("@")[0] + yfname = os.path.join(self.toold, ".shed.yml") + yamlf = open(yfname, "w") + odict = { + "name": self.tool_name, + "owner": "fubar2", + "type": "unrestricted", + "description": "ToolFactory autogenerated tool", + "synopsis": self.args.tool_desc, + "category": "ToolFactory generated Tools", + } + yaml.dump(odict, yamlf, allow_unicode=True) + yamlf.close() + + def writeTFyml(self): + """for posterity""" + adict = {} + rargs = [ + "input_files", + "output_files", + "additional_parameters", + "selecttext_parameters", + "selectflag_parameters", + "xtra_files", + ] + args = vars(self.args) + for k in args.keys(): + if k not in rargs: + adict[k] = args.get(k, None) + else: + if adict.get(k, None): + adict[k].append(adict[k]) + else: + adict[k] = [args.get(k, None)] + adict["script"] = self.script + adict["help"] = self.helptext + yfname = os.path.join(self.repdir, "%s_ToolFactory.yml" % self.tool_name) + yf = open(yfname, "w") + yaml.dump(adict, yf) + yf.close() + + def saveTestdata(self, pname, testDataURL): + """ + may need to be ungzipped and in test folder + """ + res = 0 + localpath = os.path.join(self.tooltestd, "%s_sample" % pname) + print("#### save", testDataURL, "for", pname, "to", localpath) + if not os.path.exists(localpath): + cl = [ + "wget", + "--timeout", + "5", + "--tries", + "2", + "-O", + localpath, + testDataURL, + ] + if testDataURL.endswith(".gz"): # major kludge as usual... + gzlocalpath = "%s.gz" % localpath + cl = [ + "wget", + "-q", + "--timeout", + "5", + "--tries", + "2", + "-O", + gzlocalpath, + testDataURL, + "&&", + "rm", + "-f", + localpath, + "&&", + "gunzip", + gzlocalpath, + ] + p = subprocess.run(" ".join(cl), shell=True) + if p.returncode: + print("Got", p.returncode, "from executing", " ".join(cl)) + else: + print("Not re-downloading", localpath) + return res + + def makeTool(self): + """write xmls and input samples into place""" + if self.args.parampass == 0: + self.doNoXMLparam() + else: + self.makeXML() + if self.args.script_path and self.not_iuc: + stname = os.path.join(self.toold, os.path.split(self.sfile)[1]) + if not os.path.exists(stname): + shutil.copyfile(self.sfile, stname) + logger.info("Copied %s to %s" % (self.sfile, stname)) + for p in self.infiles: + paths = p["name"] + pname = p["CL"] + pathss = paths.split(",") + np = len(pathss) + if p.get("URL", None): + res = self.saveTestdata(pname, p["URL"]) + for i, pth in enumerate(pathss): + if os.path.exists(pth): + if np > 1: + dest = os.path.join( + self.tooltestd, "%s_%d_sample" % (p["infilename"], i + 1) + ) + else: + dest = os.path.join( + self.tooltestd, "%s_sample" % p["infilename"] + ) + shutil.copyfile(pth, dest) + logger.info("Copied %s to %s" % (pth, dest)) + else: + logger.info( + "Optional input path %s does not exist - not copied" % pth + ) + if self.extra_files and len(self.extra_files) > 0: + for xtra in self.extra_files: + fpath = xtra["fpath"] + dest = os.path.join(self.toold, xtra["fname"]) + shutil.copyfile(fpath, dest) + logger.info("Copied xtra file %s to %s" % (fpath, dest)) + shutil.copytree(self.toold, self.testdir, dirs_exist_ok=True) + + def makeToolTar(self, test_retcode=0): + """move outputs into test-data and prepare the tarball""" + excludeme = "tool_test_output" + + def exclude_function(tarinfo): + filename = tarinfo.name + return None if filename.startswith(excludeme) else tarinfo + + logger.info("makeToolTar starting with tool test retcode=%d\n" % test_retcode) + td = os.listdir(self.toold) + for f in td: + if f.startswith("tool_test_output"): + os.unlink(os.path.join(self.toold, f)) + if self.newtarpath: + tf = tarfile.open(self.newtarpath, "w:gz") + tf.add( + name=self.toold, + arcname=self.tool_name, + # filter=exclude_function, + ) + + def planemo_local_test(self): + """ + weird legacyversion error popping up again from package version upgrade in conda_util.py in the venv. + Seems ok if run as a shell script using the Galaxy installed planemo august 1st 2023 + """ + shutil.copytree(self.toold, self.testdir, dirs_exist_ok=True) + x = "%s.xml" % self.tool_name + xout = os.path.abspath(os.path.join(self.testdir, x)) + cl = [ + "planemo", + "test", + "--galaxy_admin_key", + self.GALAXY_ADMIN_KEY, + "--engine", + "external_galaxy", + "--update_test_data", + "--galaxy_url", + self.GALAXY_URL, + xout, + ] + clx = [ + "planemo", + "test", + "--galaxy_admin_key", + "[GALAXY_ADMIN_KEY]", + "--engine", + "external_galaxy", + "--update_test_data", + "--galaxy_url", + self.GALAXY_URL, + xout, + ] + logger.info("planemo_local_test executing: %s" % " ".join(clx)) + p = subprocess.run( + " ".join(cl), + timeout=90, + shell=True, + cwd=self.testdir, + capture_output=True, + check=True, + text=True, + ) + for errline in p.stderr.splitlines(): + logger.info("planemo: %s" % errline) + for errline in p.stdout.splitlines(): + logger.info("planemo: %s" % errline) + shutil.copytree(self.testdir, self.toold) + dest = self.repdir + src = self.tooltestd + logger.info("copying to %s to %s test_outs" % (src, dest)) + shutil.copytree(src, dest, dirs_exist_ok=True) + return p.returncode + + def fast_local_test(self): + """ + galaxy-tool-test -u http://localhost:8080 -a 1613612977827175424 -t tacrev -o local --publish-history + Seems to have a race condition when multiple jobs running. Works well - 15 secs or so if only onejob at a time! so job_conf fixed. + Failure will eventually get stuck. Might need a timeout in the script + """ + scrpt = os.path.join(self.args.toolfactory_dir, "toolfactory_fast_test.sh") + extrapaths = self.tooltestd + cl = ["/usr/bin/bash", scrpt, self.tool_name, extrapaths, extrapaths] + logger.info("fast_local_test executing %s \n" % (" ".join(cl))) + p = subprocess.run( + " ".join(cl), + shell=True, + cwd=self.testdir, + capture_output=True, + check=True, + text=True, + ) + for errline in p.stderr.splitlines(): + logger.info("ephemeris: %s" % errline) + for errline in p.stdout.splitlines(): + logger.info("ephemeris: %s" % errline) + shutil.copytree(self.testdir, self.toold, dirs_exist_ok=True) + dest = self.repdir + src = self.tooltestd + shutil.copytree(src, dest, dirs_exist_ok=True) + return p.returncode + + def update_toolconf(self, remove=False): + """tempting to recreate it from the local_tools directory each time + currently adds new tools if not there. + """ + + def sortchildrenby(parent, attr): + parent[:] = sorted(parent, key=lambda child: child.get(attr)) + + logger.info("Updating tool conf files for %s\n" % (self.tool_name)) + tcpath = self.local_tool_conf + xmlfile = os.path.join(self.tool_name, "%s.xml" % self.tool_name) + try: + parser = ET.XMLParser(remove_blank_text=True) + tree = ET.parse(tcpath, parser) + except ET.XMLSyntaxError: + logger.error( + "### Tool configuration update access error - %s cannot be parsed as xml by element tree\n" + % tcpath + ) + sys.exit(4) + root = tree.getroot() + hasTF = False + e = root.findall("section") + if len(e) > 0: + hasTF = True + TFsection = e[0] + if not hasTF: + TFsection = ET.Element( + "section", {"id": "localtools", "name": "Local Tools"} + ) + root.insert(0, TFsection) # at the top! + our_tools = TFsection.findall("tool") + conf_tools = [x.attrib["file"] for x in our_tools] + if not remove: + if xmlfile not in conf_tools: # new + ET.SubElement(TFsection, "tool", {"file": xmlfile}) + sortchildrenby(TFsection, "file") + tree.write(tcpath, pretty_print=True) + gi = galaxy.GalaxyInstance(url=self.GALAXY_URL, key=self.GALAXY_ADMIN_KEY) + toolready = False + now = time.time() + nloop = 5 + while nloop >= 0 and not toolready: + try: + res = gi.tools.show_tool(tool_id=self.tool_name) + toolready = True + logger.info( + "Tool %s ready after %f seconds - %s\n" + % (self.tool_name, time.time() - now, res) + ) + except ConnectionError: + nloop -= 1 + time.sleep(2) + logger.info("Connection error - waiting 2 seconds.\n") + if nloop < 1: + logger.error( + "Tool %s still not ready after %f seconds - please check the form and the generated xml for errors? \n" + % (self.tool_name, time.time() - now) + ) + return 2 + else: + return 0 + else: + if xmlfile in conf_tools: # remove + for rem in our_tools: + if rem.attrib["file"] == xmlfile: + rem.getparent().remove(rem) + self.logger.info( + "###=============== removed tool %s from %s" + % (xmlfile, tcpath) + ) + sortchildrenby(TFsection, "file") + tree.write(tcpath, pretty_print=True) + + def install_deps(self): + """ + use script to install new tool dependencies + """ + cll = [ + "sh", + "%s/install_tf_deps.sh" % self.args.toolfactory_dir, + self.tool_name, + ] + self.logger.info("Running %s\n" % " ".join(cll)) + try: + p = subprocess.run( + " ".join(cll), shell=True, capture_output=True, check=True, text=True + ) + for errline in p.stderr.splitlines(): + self.logger.info(errline) + return p.returncode + except: + return 1 + + def timenow(self): + """return current time as a string""" + return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time())) + + def cheetah_escape(self, text): + """Produce entities within text.""" + cheetah_escape_table = {"$": "\\$", "#": "\\#"} + return "".join([cheetah_escape_table.get(c, c) for c in text]) + + def parse_citations(self): + """""" + if self.args.citations: + ct = open(self.args.citations, "r").read() + citations = [c.strip() for c in ct.split("**ENTRY**") if c.strip()] + citation_tuples = [] + for citation in citations: + if citation.startswith("doi"): + citation_tuples.append(("doi", citation[len("doi") :].strip())) + else: + citation_tuples.append( + ("bibtex", citation[len("bibtex") :].strip()) + ) + return citation_tuples + else: + return None + + +def main(): + """ + This is a Galaxy wrapper. + It expects to be called by a special purpose tool.xml + + """ + parser = argparse.ArgumentParser() + a = parser.add_argument + a("--nftest", action="store_true", default=False) + a("--script_path", default=None) + a("--sysexe", default=None) + a("--packages", default=None) + a("--tool_name", default="newtool") + a("--input_files", default=[], action="append") + a("--output_files", default=[], action="append") + a("--user_email", default="Unknown") + a("--bad_user", default=None) + a("--help_text", default=None) + a("--tool_desc", default=None) + a("--toolfactory_dir", default=None) + a("--tool_version", default="0.01") + a("--citations", default=None) + a("--cl_suffix", default=None) + a("--cl_prefix", default=None) + a("--cl_override", default=None) + a("--test_override", default=None) + a("--additional_parameters", action="append", default=[]) + a("--selecttext_parameters", action="append", default=[]) + a("--selectflag_parameters", action="append", default=[]) + a("--edit_additional_parameters", action="store_true", default=False) + a("--parampass", default="positional") + a("--tfcollection", default="toolgen") + a("--galaxy_root", default="/galaxy-central") + a("--collection", action="append", default=[]) + a("--include_tests", default=False, action="store_true") + a("--install_flag", action="store_true", default=False) + a("--admin_only", default=True, action="store_true") + a("--tested_tool_out", default=None) + a("--container", default=None, required=False) + a("--tool_conf_path", default="config/tool_conf.xml") # relative to $__root_dir__ + a( + "--xtra_files", + default=[], + action="append", + ) # history data items to add to the tool base directory + tfcl = sys.argv[1:] + args = parser.parse_args() + if args.admin_only: + assert not args.bad_user, ( + 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to "admin_users" in the galaxy.yml Galaxy configuration file' + % (args.bad_user, args.bad_user) + ) + assert ( + args.tool_name + ), "## This ToolFactory cannot build a tool without a tool name. Please supply one." + os.makedirs(args.tfcollection, exist_ok=True) + logfilename = os.path.join( + args.tfcollection, "ToolFactory_make_%s_log.txt" % args.tool_name + ) + logger.setLevel(logging.INFO) + fh = logging.FileHandler(logfilename, mode="w") + fformatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") + fh.setFormatter(fformatter) + logger.addHandler(fh) + tf = Tool_Factory(args) + tf.makeTool() + tf.writeShedyml() + # tf.writeTFyml()tf.writeTFyml() + tf.update_toolconf() + time.sleep(5) + if tf.condaenv and len(tf.condaenv) > 0: + res = tf.install_deps() + if res > 0: + logger.debug("Toolfactory installed deps failed") + logging.shutdown() + sys.exit(6) + time.sleep(2) + testret = tf.fast_local_test() # planemo_local_test() + if False and int(testret) > 0: + logger.error("ToolFactory tool build and test failed. :(") + logger.info( + "This is usually because the supplied script or dependency did not run correctly with the test inputs and parameter settings" + ) + logger.info("when tested with galaxy_tool_test. Error code:%d" % int(testret)) + logger.info( + "The 'i' (information) option shows how the ToolFactory was called, stderr and stdout, and what the command line was." + ) + logger.info( + "Expand (click on) any of the broken (red) history output titles to see that 'i' button and click it" + ) + logger.info( + "Make sure it is the same as your working test command line and double check that data files are coming from and going to where they should" + ) + logger.info( + "In the output collection, the tool xml element must be the equivalent of your working command line for the test to work" + ) + logging.shutdown() + sys.exit(5) + else: + tf.makeToolTar(testret) + jcl = sys.argv[1:] + with open( + os.path.join( + args.tfcollection, "ToolFactory_%s_commandline.json" % args.tool_name + ), + "w", + ) as fout: + fout.write(" ".join(jcl)) + logging.shutdown() + + +if __name__ == "__main__": + main() diff -r 2beaae16651e -r 0183cad9d13b toolfactory/toolfactory.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/toolfactory.xml Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,655 @@ + + Scripts into tools v3.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + python + galaxyxml + bioblend + planemo + ephemeris + + + 0 +--cl_suffix "$clsuffix" + #end if + #if len(str($cl_options.cl_prefix)) > 0 +--cl_prefix "$clprefix" + #end if + #if len(str($cl_options.cl_override)) > 0 +--cl_override "$commandoverride" + #end if + #if len(str($cl_options.test_override)) > 0 +--test_override "$testoverride" + #end if + #if $deps.packages > "": + --packages "$deps.packages" + #end if + #if $deps.usescript.choosescript == "yes" +--script_path "$runscript" +--sysexe "$deps.usescript.scriptrunner" + #end if +--tool_name "$tool_name" --user_email "$useremail" --citations "$citeme" --parampass "$io_param.ppass.parampass" +--tool_desc "$tool_desc" +--tool_version "$tool_version" +--help_text "$helpme" + #if $io_param.ppass.parampass != '0' + #if str($io_param.ppass.addparam.edit_params) == "yes" +--edit_additional_parameters + #end if + #for $apar in $io_param.ppass.addparam.additional_parameters + #if $apar.ap_type.param_type=="selecttext" +--selecttext_parameters '{"name":"$apar.param_name", "label":"$apar.param_label", "help":"$apar.param_help", +"type":"$apar.ap_type.param_type","CL":"$apar.param_CL","override":"$apar.param_CLprefixed","value": [ + #for $i,$st in enumerate($apar.ap_type.selectTexts): + "$st.select_value" + #if ($i < (len($apar.ap_type.selectTexts)-1)): + , + #end if + #end for + ], "texts": [ + #for $i,$st in enumerate($apar.ap_type.selectTexts): + "$st.select_text" + #if ($i < (len($apar.ap_type.selectTexts)-1)): + , + #end if + + #end for + ] + }' + #else if $apar.ap_type.param_type=="selectflag" +--selectflag_parameters '{"name":"$apar.param_name", "label":"$apar.param_label", "help":"$apar.param_help", +"type":"$apar.ap_type.param_type","CL":"$apar.param_CL","override":"$apar.param_CLprefixed","value": [ + #for $i,$st in enumerate($apar.ap_type.selectFlags): + "$st.select_value" + #if ($i < (len($apar.ap_type.selectFlags)-1)): + , + #end if + #end for + ], "texts": [ + #for $i,$st in enumerate($apar.ap_type.selectFlags): + "$st.select_text" + #if ($i < (len($apar.ap_type.selectFlags)-1)): + , + #end if + + #end for + ] + }' + #else if $apar.ap_type.param_type=="datacolumn" +--additional_parameters '{"name": "$apar.param_name", "value": "$apar.ap_type.param_value", "label": "$apar.param_label", "help": "$apar.param_help", +"type": "$apar.ap_type.param_type","CL": "$apar.param_CL","override": "$apar.param_CLprefixed", "repeat": "$apar.param_repeat", "multiple": "$apar.ap_type.param_multiple", + "dataref": "$apar.ap_type.param_dataref"}' + #else: +--additional_parameters '{"name": "$apar.param_name", "value": "$apar.ap_type.param_value", "label": "$apar.param_label", "help": "$apar.param_help", +"type": "$apar.ap_type.param_type","CL": "$apar.param_CL","override": "$apar.param_CLprefixed", "repeat": "$apar.param_repeat"}' + #end if + #end for + #end if + #for $intab in $io_param.ppass.io.history_inputs +--input_files '{"name": "$intab.input_files", "CL": "$intab.input_CL", "format": "$intab.input_formats", "label": "$intab.input_label", +"help": "$intab.input_help", "required": "$intab.input_required"}' + #end for + #for $otab in $io_param.ppass.io.history_outputs + #if str($otab.history_label) > "" + --output_files '{"name": "$otab.history_name", "format": "$otab.history_format", "CL": "$otab.history_CL", "test": "$otab.history_test", "label": "$otab.history_label" + #else + --output_files '{"name": "$otab.history_name", "format": "$otab.history_format", "CL": "$otab.history_CL", "test": "$otab.history_test" + #end if + #if $otab.history_whens + , "when": [ + #for $i, $hw in enumerate($otab.history_whens) + "$hw.history_when" + #if ($i < (len($otab.history_whens)-1)) + , + #end if + #end for + ] + #end if + }' + #end for + #for $collect in $io_param.ppass.io.collection_outputs +--collection '{"name": "$collect.name", "kind": "$collect.kind", "discover": "$collect.discover", "label": "$collect.label"}' + #end for +--tfcollection 'toolgen' +--tested_tool_out "$untested_tool" +--nftest +--galaxy_root "$__root_dir__" +--toolfactory_dir "$__tool_directory__" + #if $cl_options.xtracond.needxtra == "yes" + #for $x in $cl_options.xtracond.xtra_files +--xtra_file '{"fpath":"$x", "fname":"$x.element_identifier"}' + #end for + #end if +#end if +]]> + + + +${deps.usescript.dynScript} + + +#if len(str($cl_options.cl_override).strip()) > 1: +${cl_options.cl_override} +#end if + + +#if len(str($cl_options.test_override).strip()) > 1: +${cl_options.test_override} +#end if + + +#if len(str($cl_options.cl_prefix).strip()) > 1: +${cl_options.cl_prefix} +#end if + + +#if len(str($cl_options.cl_suffix).strip()) > 1: +${cl_options.cl_suffix} +#end if + + +${help_text} + + + +#for $citation in $citations: + #if $citation.citation_type.type == "bibtex": + **ENTRY**bibtex + ${citation.citation_type.bibtex} + #else + **ENTRY**doi + ${citation.citation_type.doi} + #end if +#end for + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +**Details and attribution** +(see GTF_) + +**Local Admins ONLY** +Only users with emails in the local admin_user configuration setting in config/galaxy.yml can run this tool. + +**If you find a bug** +Please raise an issue, or even better, submit a pull request fixing it, on the github repository GTF_ + +**What it does** +This tool contains an automated code generator, and creates normal, workflow compatible Galaxy tools as Toolshed ready archives. The +new tool is immediately installed and available for use - a page refresh will be needed to see the new tool in the "Local" tool section. + +Generated tools can use existing Conda packages. These become requirements for optional scripts pasted into this tool form. +Pasted scripts *cannot be adjusted* by the downstream user. + +Any number of parameters can be built into the new tool form for passing in to the script or executable at runtime. +These can be editable by the downstream user or baked in. + +A new tarball compatible with any Galaxy toolshed is created in your history, including a test based on the supplied default parameter +values and input history datasets. + +.. class:: warningmark + +**Note to system administrators** +This tool offers *NO* built in protection against malicious scripts. It should only be installed on private/personnal Galaxy instances. +Admin_users will have the power to do anything they want as the Galaxy user if you install this tool. + +.. class:: warningmark + +**Use on public servers** is STRONGLY discouraged for obvious reasons + +The tools generated by this tool will run just as securely as any other normal installed Galaxy tool but like any other new tools, +should always be checked carefully before installation. We recommend that you follow the good code hygiene practices associated with safe toolshed practices. + + +Paper_ + +*Licensing* + +Copyright Ross Lazarus May 2012 +Licensed under the MIT_ licence. + +.. _MIT: https://mit-license.org/ +.. _GTF: https://github.com/fubar2/galaxy_tf_overlay +.. _Paper: https://academic.oup.com/bioinformatics/article/28/23/3139/192853 + + + + + 10.1093/bioinformatics/bts573 + +
+ + diff -r 2beaae16651e -r 0183cad9d13b toolfactory/toolfactory_fast_test.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/toolfactory_fast_test.sh Thu Feb 22 10:48:01 2024 +0000 @@ -0,0 +1,11 @@ +GALAXY_URL=http://localhost:8080 +GALAXY_VENV=/home/ross/rossgit/galaxytf231/.venv +API_KEY=1718977735397126400 +API_KEY_USER=995248011247121408 +# for test@bx.psu.edu user +# for sed to edit at installation +# must pass toolname outdir as cl params in that order... +# shows api keys do uncomment for debugging if you must +# echo "toolfactory_fast_test.sh: galaxy-tool-test -u $GALAXY_URL -a $API_KEY -k $API_KEY_USER -t $1 -o $2 --test-data $3" +galaxy-tool-test -u $GALAXY_URL -a $API_KEY -k $API_KEY_USER -t $1 -o $2 --test-data $3 --publish-history +