Repository 'xcms_summary'
hg clone https://toolshed.g2.bx.psu.edu/repos/lecorguille/xcms_summary

Changeset 28:018a9771de28 (2021-04-07)
Previous changeset 27:bed23aa27b4b (2020-09-24) Next changeset 29:2a2850fdf29e (2023-09-11)
Commit message:
"planemo upload for repository https://github.com/workflow4metabolomics/xcms commit dcc90f9cf76e6980c0a7d9698c89fab826e7adae"
modified:
README.rst
abims_xcms_summary.xml
lib.r
macros_xcms.xml
test-data/faahKO-single.xset.merged.group.retcor.group.fillpeaks.summary.html
xcms_summary.r
b
diff -r bed23aa27b4b -r 018a9771de28 README.rst
--- a/README.rst Thu Sep 24 08:09:02 2020 +0000
+++ b/README.rst Wed Apr 07 16:46:50 2021 +0000
b
@@ -4,6 +4,10 @@
 
 .. _News: https://bioconductor.org/packages/release/bioc/news/xcms/NEWS
 
+**Version 3.12.0+galaxy* - 03/03/2020**
+
+- UPGRADE: upgrade the xcms version from 3.6.1 to 3.12.0 (see XCMS News_)
+
 **Version 3.6.1+galaxy1 - 05/04/2020**
 
 - UPGRADE: upgrade the CAMERA version from 1.38.0 to 1.42.0
b
diff -r bed23aa27b4b -r 018a9771de28 abims_xcms_summary.xml
--- a/abims_xcms_summary.xml Thu Sep 24 08:09:02 2020 +0000
+++ b/abims_xcms_summary.xml Wed Apr 07 16:46:50 2021 +0000
b
@@ -1,4 +1,4 @@
-<tool id="abims_xcms_summary" name="xcms process history" version="@TOOL_VERSION@+galaxy2">
+<tool id="abims_xcms_summary" name="xcms process history" version="@TOOL_VERSION@+galaxy0">
 
     <description>Create a summary of XCMS analysis</description>
 
@@ -8,8 +8,8 @@
     </macros>
 
     <requirements>
- <requirement type="package" version="@TOOL_VERSION@">bioconductor-xcms</requirement>    
- <requirement type="package" version="1.40.0">bioconductor-camera</requirement>
+        <requirement type="package" version="@TOOL_VERSION@">bioconductor-xcms</requirement>
+        <requirement type="package" version="1.46.0">bioconductor-camera</requirement>
         <requirement type="package" version="1.1_5">r-batch</requirement>
     </requirements>
 
@@ -87,12 +87,12 @@
 Changelog/News
 --------------
 
+@HELP_XCMS_NEWVERSION_31200@
+
 **Version 3.6.1+galaxy2 - 23/09/2020**
 
 - BUGFIX: "Error: object 'sampleNamesList' not found" in case of .RData input from CAMERA
 
-.. _News: https://bioconductor.org/packages/release/bioc/news/xcms/NEWS
-
 **Version 3.6.1+galaxy1 - 05/04/2020**
 
 - UPGRADE: upgrade the CAMERA version from 1.38.0 to 1.42.0
b
diff -r bed23aa27b4b -r 018a9771de28 lib.r
--- a/lib.r Thu Sep 24 08:09:02 2020 +0000
+++ b/lib.r Wed Apr 07 16:46:50 2021 +0000
[
b'@@ -6,8 +6,8 @@\n parseCommandArgs <- function(...) {\n     args <- batch::parseCommandArgs(...)\n     for (key in names(args)) {\n-        if (args[key] %in% c("TRUE","FALSE"))\n-            args[key] = as.logical(args[key])\n+        if (args[key] %in% c("TRUE", "FALSE"))\n+            args[key] <- as.logical(args[key])\n     }\n     return(args)\n }\n@@ -17,14 +17,20 @@\n # - load the packages\n # - display the sessionInfo\n loadAndDisplayPackages <- function(pkgs) {\n-    for(pkg in pkgs) suppressPackageStartupMessages( stopifnot( library(pkg, quietly=TRUE, logical.return=TRUE, character.only=TRUE)))\n+    for (pkg in pkgs) suppressPackageStartupMessages(stopifnot(library(pkg, quietly = TRUE, logical.return = TRUE, character.only = TRUE)))\n \n-    sessioninfo = sessionInfo()\n-    cat(sessioninfo$R.version$version.string,"\\n")\n+    sessioninfo <- sessionInfo()\n+    cat(sessioninfo$R.version$version.string, "\\n")\n     cat("Main packages:\\n")\n-    for (pkg in names(sessioninfo$otherPkgs)) { cat(paste(pkg,packageVersion(pkg)),"\\t") }; cat("\\n")\n+    for (pkg in names(sessioninfo$otherPkgs)) {\n+      cat(paste(pkg, packageVersion(pkg)), "\\t")\n+    }\n+    cat("\\n")\n     cat("Other loaded packages:\\n")\n-    for (pkg in names(sessioninfo$loadedOnly)) { cat(paste(pkg,packageVersion(pkg)),"\\t") }; cat("\\n")\n+    for (pkg in names(sessioninfo$loadedOnly)) {\n+      cat(paste(pkg, packageVersion(pkg)), "\\t")\n+    }\n+    cat("\\n")\n }\n \n #@author G. Le Corguille\n@@ -43,20 +49,20 @@\n     chromTIC_adjusted <- NULL\n     chromBPI_adjusted <- NULL\n     md5sumList <- NULL\n-    for(image in args$images) {\n+    for (image in args$images) {\n \n         load(image)\n         # Handle infiles\n         if (!exists("singlefile")) singlefile <- NULL\n         if (!exists("zipfile")) zipfile <- NULL\n-        rawFilePath <- retrieveRawfileInTheWorkingDirectory(singlefile, zipfile, args)\n+        rawFilePath <- retrieveRawfileInTheWorkingDir(singlefile, zipfile, args)\n         zipfile <- rawFilePath$zipfile\n         singlefile <- rawFilePath$singlefile\n \n         if (exists("raw_data")) xdata <- raw_data\n         if (!exists("xdata")) stop("\\n\\nERROR: The RData doesn\'t contain any object called \'xdata\'. This RData should have been created by an old version of XMCS 2.*")\n \n-        cat(sampleNamesList$sampleNamesOrigin,"\\n")\n+        cat(sampleNamesList$sampleNamesOrigin, "\\n")\n \n         if (!exists("xdata_merged")) {\n             xdata_merged <- xdata\n@@ -68,14 +74,14 @@\n             chromTIC_adjusted_merged <- chromTIC_adjusted\n             chromBPI_adjusted_merged <- chromBPI_adjusted\n         } else {\n-            if (is(xdata, "XCMSnExp")) xdata_merged <- c(xdata_merged,xdata)\n-            else if (is(xdata, "OnDiskMSnExp")) xdata_merged <- xcms:::.concatenate_OnDiskMSnExp(xdata_merged,xdata)\n+            if (is(xdata, "XCMSnExp")) xdata_merged <- c(xdata_merged, xdata)\n+            else if (is(xdata, "OnDiskMSnExp")) xdata_merged <- xcms:::.concatenate_OnDiskMSnExp(xdata_merged, xdata)\n             else stop("\\n\\nERROR: The RData either a OnDiskMSnExp object called raw_data or a XCMSnExp object called xdata")\n \n-            singlefile_merged <- c(singlefile_merged,singlefile)\n-            md5sumList_merged$origin <- rbind(md5sumList_merged$origin,md5sumList$origin)\n-            sampleNamesList_merged$sampleNamesOrigin <- c(sampleNamesList_merged$sampleNamesOrigin,sampleNamesList$sampleNamesOrigin)\n-            sampleNamesList_merged$sampleNamesMakeNames <- c(sampleNamesList_merged$sampleNamesMakeNames,sampleNamesList$sampleNamesMakeNames)\n+            singlefile_merged <- c(singlefile_merged, singlefile)\n+            md5sumList_merged$origin <- rbind(md5sumList_merged$origin, md5sumList$origin)\n+            sampleNamesList_merged$sampleNamesOrigin <- c(sampleNamesList_merged$sampleNamesOrigin, sampleNamesList$sampleNamesOrigin)\n+            sampleNamesList_merged$sampleNamesMakeNames <- c(sampleNamesList_merged$sampleNamesMakeNames, sampleNamesList$sampleNamesMakeNam'..b'length("singlefile") > 0)) {\n         files <- vector()\n         for (singlefile_sampleName in names(singlefile)) {\n             singlefile_galaxyPath <- singlefile[[singlefile_sampleName]]\n-            if(!file.exists(singlefile_galaxyPath)){\n-                error_message <- paste("Cannot access the sample:",singlefile_sampleName,"located:",singlefile_galaxyPath,". Please, contact your administrator ... if you have one!")\n+            if (!file.exists(singlefile_galaxyPath)) {\n+                error_message <- paste("Cannot access the sample:", singlefile_sampleName, "located:", singlefile_galaxyPath, ". Please, contact your administrator ... if you have one!")\n                 print(error_message); stop(error_message)\n             }\n \n-            if (!suppressWarnings( try (file.link(singlefile_galaxyPath, singlefile_sampleName), silent=T)))\n+            if (!suppressWarnings(try(file.link(singlefile_galaxyPath, singlefile_sampleName), silent = T)))\n                 file.copy(singlefile_galaxyPath, singlefile_sampleName)\n             files <- c(files, singlefile_sampleName)\n         }\n     }\n     # zipfile\n-    if(!is.null(zipfile) && (zipfile != "")) {\n-        if(!file.exists(zipfile)){\n-            error_message <- paste("Cannot access the Zip file:",zipfile,". Please, contact your administrator ... if you have one!")\n+    if (!is.null(zipfile) && (zipfile != "")) {\n+        if (!file.exists(zipfile)) {\n+            error_message <- paste("Cannot access the Zip file:", zipfile, ". Please, contact your administrator ... if you have one!")\n             print(error_message)\n             stop(error_message)\n         }\n-        suppressWarnings(unzip(zipfile, unzip="unzip"))\n+        suppressWarnings(unzip(zipfile, unzip = "unzip"))\n \n         #get the directory name\n-        suppressWarnings(filesInZip <- unzip(zipfile, list=T))\n-        directories <- unique(unlist(lapply(strsplit(filesInZip$Name,"/"), function(x) x[1])))\n+        suppressWarnings(filesInZip <- unzip(zipfile, list = T))\n+        directories <- unique(unlist(lapply(strsplit(filesInZip$Name, "/"), function(x) x[1])))\n         directories <- directories[!(directories %in% c("__MACOSX")) & file.info(directories)$isdir]\n         directory <- "."\n         if (length(directories) == 1) directory <- directories\n \n-        cat("files_root_directory\\t",directory,"\\n")\n+        cat("files_root_directory\\t", directory, "\\n")\n \n-        filepattern <- c("[Cc][Dd][Ff]", "[Nn][Cc]", "([Mm][Zz])?[Xx][Mm][Ll]","[Mm][Zz][Dd][Aa][Tt][Aa]", "[Mm][Zz][Mm][Ll]")\n-        filepattern <- paste(paste("\\\\.", filepattern, "$", sep=""),collapse="|")\n+        filepattern <- c("[Cc][Dd][Ff]", "[Nn][Cc]", "([Mm][Zz])?[Xx][Mm][Ll]", "[Mm][Zz][Dd][Aa][Tt][Aa]", "[Mm][Zz][Mm][Ll]")\n+        filepattern <- paste(paste("\\\\.", filepattern, "$", sep = ""), collapse = "|")\n         info <- file.info(directory)\n-        listed <- list.files(directory[info$isdir], pattern=filepattern,recursive=TRUE, full.names=TRUE)\n+        listed <- list.files(directory[info$isdir], pattern = filepattern, recursive = TRUE, full.names = TRUE)\n         files <- c(directory[!info$isdir], listed)\n         exists <- file.exists(files)\n         files <- files[exists]\n \n     }\n-    return(list(zipfile=zipfile, singlefile=singlefile, files=files))\n+    return(list(zipfile = zipfile, singlefile = singlefile, files = files))\n \n }\n \n@@ -417,15 +437,15 @@\n getxcmsSetObject <- function(xobject) {\n     # XCMS 1.x\n     if (class(xobject) == "xcmsSet")\n-        return (xobject)\n+        return(xobject)\n     # XCMS 3.x\n     if (class(xobject) == "XCMSnExp") {\n         # Get the legacy xcmsSet object\n-        suppressWarnings(xset <- as(xobject, \'xcmsSet\'))\n+        suppressWarnings(xset <- as(xobject, "xcmsSet"))\n         if (!is.null(xset@phenoData$sample_group))\n             sampclass(xset) <- xset@phenoData$sample_group\n         else\n             sampclass(xset) <- "."\n-        return (xset)\n+        return(xset)\n     }\n }\n'
b
diff -r bed23aa27b4b -r 018a9771de28 macros_xcms.xml
--- a/macros_xcms.xml Thu Sep 24 08:09:02 2020 +0000
+++ b/macros_xcms.xml Wed Apr 07 16:46:50 2021 +0000
b
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <macros>
 
-    <token name="@TOOL_VERSION@">3.6.1</token>
+    <token name="@TOOL_VERSION@">3.12.0</token>
     <xml name="requirements">
         <requirements>
             <requirement type="package" version="@TOOL_VERSION@">bioconductor-xcms</requirement>
@@ -243,6 +243,7 @@
 .. _xcms: https://bioconductor.org/packages/release/bioc/html/xcms.html
 .. _manual: http://www.bioconductor.org/packages/release/bioc/manuals/xcms/man/xcms.pdf
 .. _example: https://bioconductor.org/packages/release/bioc/vignettes/xcms/inst/doc/xcms.html
+.. _News: https://bioconductor.org/packages/release/bioc/news/xcms/NEWS
 
     </token>
 
@@ -256,6 +257,11 @@
 
 - UPGRADE: upgrade the xcms version from 3.4.4 to 3.6.1 (see XCMS News_)
     </token>
+    <token name="@HELP_XCMS_NEWVERSION_31200@">
+**Version 3.12.0+galaxy* - 03/03/2020**
+
+- UPGRADE: upgrade the xcms version from 3.6.1 to 3.12.0 (see XCMS News_)
+    </token>
 
     <xml name="citation">
         <citations>
b
diff -r bed23aa27b4b -r 018a9771de28 test-data/faahKO-single.xset.merged.group.retcor.group.fillpeaks.summary.html
--- a/test-data/faahKO-single.xset.merged.group.retcor.group.fillpeaks.summary.html Thu Sep 24 08:09:02 2020 +0000
+++ b/test-data/faahKO-single.xset.merged.group.retcor.group.fillpeaks.summary.html Wed Apr 07 16:46:50 2021 +0000
[
@@ -5,7 +5,7 @@
 <title>[W4M] XCMS analysis summary</title>
 <style>
 table, tr, td, th { border: 1px solid #000000; border-collapse:collapse; }
-td,th { padding: 5px; padding-right: 12px; }
+td, th { padding: 5px; padding-right: 12px; }
 th { background: #898989; text-align:left;color: white;}
 h2 { color: #FFA212; }
 ul li { margin-bottom:10px; }
b
diff -r bed23aa27b4b -r 018a9771de28 xcms_summary.r
--- a/xcms_summary.r Thu Sep 24 08:09:02 2020 +0000
+++ b/xcms_summary.r Wed Apr 07 16:46:50 2021 +0000
[
b'@@ -13,17 +13,21 @@\n cat("\\tSESSION INFO\\n")\n \n #Import the different functions\n-source_local <- function(fname){ argv <- commandArgs(trailingOnly=FALSE); base_dir <- dirname(substring(argv[grep("--file=", argv)], 8)); source(paste(base_dir, fname, sep="/")) }\n+source_local <- function(fname) {\n+  argv <- commandArgs(trailingOnly = FALSE); base_dir <- dirname(substring(argv[grep("--file=", argv)], 8)); source(paste(base_dir, fname, sep = "/"))\n+}\n source_local("lib.r")\n \n-pkgs <- c("CAMERA","batch")\n+pkgs <- c("CAMERA", "batch")\n loadAndDisplayPackages(pkgs)\n cat("\\n\\n");\n \n \n # ----- FUNCTION -----\n-writehtml <- function(...) { cat(...,"\\n", file=htmlOutput,append = TRUE,sep="") }\n-writeraw <- function(htmlOutput, object, open="at") {\n+writehtml <- function(...) {\n+  cat(..., "\\n", file = htmlOutput, append = TRUE, sep = "")\n+}\n+writeraw <- function(htmlOutput, object, open = "at") {\n     log_file <- file(htmlOutput, open = open)\n     sink(log_file)\n     sink(log_file, type = "output")\n@@ -33,26 +37,26 @@\n }\n getSampleNames <- function(xobject) {\n     if (class(xobject) == "xcmsSet")\n-        return (sampnames(xobject))\n+        return(sampnames(xobject))\n     if (class(xobject) == "XCMSnExp")\n-        return (xobject@phenoData@data$sample_name)\n+        return(xobject@phenoData@data$sample_name)\n }\n getFilePaths <- function(xobject) {\n     if (class(xobject) == "xcmsSet")\n-        return (xobject@filepaths)\n+        return(xobject@filepaths)\n     if (class(xobject) == "XCMSnExp")\n-        return (fileNames(xobject))\n+        return(fileNames(xobject))\n }\n equalParams <- function(param1, param2) {\n-    writeraw("param1.txt", param1, open="wt")\n-    writeraw("param2.txt", param2, open="wt")\n+    writeraw("param1.txt", param1, open = "wt")\n+    writeraw("param2.txt", param2, open = "wt")\n     return(tools::md5sum("param1.txt") == tools::md5sum("param2.txt"))\n }\n \n \n # ----- ARGUMENTS -----\n \n-args <- parseCommandArgs(evaluate=FALSE) #interpretation of arguments given in command line as an R list of objects\n+args <- parseCommandArgs(evaluate = FALSE) #interpretation of arguments given in command line as an R list of objects\n \n \n # ----- ARGUMENTS PROCESSING -----\n@@ -61,26 +65,26 @@\n load(args$image);\n \n htmlOutput <- "summary.html"\n-if (!is.null(args$htmlOutput)) htmlOutput = args$htmlOutput;\n+if (!is.null(args$htmlOutput)) htmlOutput <- args$htmlOutput;\n \n user_email <- NULL\n-if (!is.null(args$user_email)) user_email = args$user_email;\n+if (!is.null(args$user_email)) user_email <- args$user_email;\n \n # if the RData come from XCMS 1.x\n if (exists("xset")) {\n     xobject <- xset\n     # retrocompatability\n-    if (!exists("sampleNamesList")) sampleNamesList <- list("sampleNamesMakeNames"=make.names(sampnames(xobject)))\n+    if (!exists("sampleNamesList")) sampleNamesList <- list("sampleNamesMakeNames" = make.names(sampnames(xobject)))\n }\n # if the RData come from CAMERA\n if (exists("xa")) {\n     xobject <- xa@xcmsSet\n-    if (!exists("sampleNamesList")) sampleNamesList <- list("sampleNamesMakeNames"=make.names(xa@xcmsSet@phenoData$sample_name))\n+    if (!exists("sampleNamesList")) sampleNamesList <- list("sampleNamesMakeNames" = make.names(xa@xcmsSet@phenoData$sample_name))\n }\n # if the RData come from XCMS 3.x\n if (exists("xdata")) {\n     xobject <- xdata\n-    if (!exists("sampleNamesList")) sampleNamesList <- list("sampleNamesMakeNames"=make.names(xdata@phenoData@data$sample_name))\n+    if (!exists("sampleNamesList")) sampleNamesList <- list("sampleNamesMakeNames" = make.names(xdata@phenoData@data$sample_name))\n }\n \n if (!exists("xobject")) stop("You need at least a xdata, a xset or a xa object.")\n@@ -97,7 +101,7 @@\n \n     writehtml("<style>")\n         writehtml("table, tr, td, th { border: 1px solid #000000; border-collapse:collapse; }")\n-        writehtml("td,th { padding: 5px; padding-right: 12px; }")\n+        writehtml("td, th { padding: 5px; padding-right: 12px; }")\n         writehtml("th { background: #898989; text-align'..b'lay[arg][1]),"</td></tr>")\n+                    writehtml(line_begin, "<td>", arg, "</td><td>", unlist(listOFlistArgumentsDisplay[arg][1]), "</td></tr>")\n                     line_begin <- "<tr>"\n                 }\n             }\n@@ -202,7 +206,7 @@\n         writehtml("<h2>Informations about the CAMERA object:</h2>")\n \n         writehtml("<div>")\n-            writehtml("Number of pcgroup: ",length(xa@pspectra))\n+            writehtml("Number of pcgroup: ", length(xa@pspectra))\n         writehtml("</div>")\n     }\n \n@@ -210,21 +214,21 @@\n     writehtml("<div><ul>")\n         writehtml("<li>To cite the <b>XCMS</b> package in publications use:")\n             writehtml("<ul>")\n-            writehtml("<li>","Smith, C.A. and Want, E.J. and O\'Maille, G. and Abagyan,R. and Siuzdak, G.XCMS: Processing mass spectrometry data for metabolite profiling using nonlinear peak alignment, matching and identification, Analytical Chemistry, 78:779-787 (2006)","</li>")\n-            writehtml("<li>","Ralf Tautenhahn, Christoph Boettcher, Steffen Neumann: Highly sensitive feature detection for high resolution LC/MS BMC Bioinformatics, 9:504 (2008)","</li>")\n-            writehtml("<li>","H. Paul Benton, Elizabeth J. Want and Timothy M. D. Ebbels Correction of mass calibration gaps in liquid chromatography-mass spectrometry metabolomics data Bioinformatics, 26:2488 (2010)","</li>")\n+            writehtml("<li>", "Smith, C.A. and Want, E.J. and O\'Maille, G. and Abagyan,R. and Siuzdak, G.XCMS: Processing mass spectrometry data for metabolite profiling using nonlinear peak alignment, matching and identification, Analytical Chemistry, 78:779-787 (2006)", "</li>")\n+            writehtml("<li>", "Ralf Tautenhahn, Christoph Boettcher, Steffen Neumann: Highly sensitive feature detection for high resolution LC/MS BMC Bioinformatics, 9:504 (2008)", "</li>")\n+            writehtml("<li>", "H. Paul Benton, Elizabeth J. Want and Timothy M. D. Ebbels Correction of mass calibration gaps in liquid chromatography-mass spectrometry metabolomics data Bioinformatics, 26:2488 (2010)", "</li>")\n             writehtml("</ul>")\n         writehtml("</li>")\n \n         writehtml("<li>To cite the <b>CAMERA</b> package in publications use:")\n             writehtml("<ul>")\n-            writehtml("<li>","Kuhl, C., Tautenhahn, R., Boettcher, C., Larson, T. R. and Neumann,S. CAMERA: an integrated strategy for compound spectra extraction and annotation of liquid chromatography/mass spectrometry data sets. Analytical Chemistry, 84:283-289 (2012)","</li>")\n+            writehtml("<li>", "Kuhl, C., Tautenhahn, R., Boettcher, C., Larson, T. R. and Neumann,S. CAMERA: an integrated strategy for compound spectra extraction and annotation of liquid chromatography/mass spectrometry data sets. Analytical Chemistry, 84:283-289 (2012)", "</li>")\n             writehtml("</ul>")\n         writehtml("</li>")\n \n         writehtml("<li>To cite the <b>Workflow4Metabolimics (W4M)</b> project in publications use:")\n             writehtml("<ul>")\n-            writehtml("<li>","Franck Giacomoni, Gildas Le Corguill\xc3\xa9, Misharl Monsoor, Marion Landi, Pierre Pericard, M\xc3\xa9lanie P\xc3\xa9t\xc3\xa9ra, Christophe Duperier, Marie Tremblay-Franco, Jean-Fran\xc3\xa7ois Martin, Daniel Jacob, Sophie Goulitquer, Etienne A. Th\xc3\xa9venot and Christophe Caron (2014). Workflow4Metabolomics: A collaborative research infrastructure for computational metabolomics. Bioinformatics  doi:10.1093/bioinformatics/btu813","</li>")\n+            writehtml("<li>", "Franck Giacomoni, Gildas Le Corguill\xc3\xa9, Misharl Monsoor, Marion Landi, Pierre Pericard, M\xc3\xa9lanie P\xc3\xa9t\xc3\xa9ra, Christophe Duperier, Marie Tremblay-Franco, Jean-Fran\xc3\xa7ois Martin, Daniel Jacob, Sophie Goulitquer, Etienne A. Th\xc3\xa9venot and Christophe Caron (2014). Workflow4Metabolomics: A collaborative research infrastructure for computational metabolomics. Bioinformatics  doi:10.1093/bioinformatics/btu813", "</li>")\n             writehtml("</ul>")\n         writehtml("</li>")\n     writehtml("</ul></div>")\n'