From e525cc224a3053d08b6aaa6c1953f7507aede854 Mon Sep 17 00:00:00 2001 From: Sam Ruby Date: Sun, 19 Mar 2000 17:57:03 +0000 Subject: [PATCH] NetRexxC and supporting taskdefs. NetRexxC 1.160 or higher needed (due to bugs in the way the compiler handles error streams). Note: I changed the package names and converted the calls from using Introspection to directly calling the compiler. Submitted by: dIon Gillard git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267637 13f79535-47bb-0310-9956-ffa450edef68 --- build.xml | 2 + .../tools/ant/taskdefs/optional/NetRexxC.java | 649 ++++++++++++++++++ .../taskdefs/optional/RenameExtensions.java | 105 +++ 3 files changed, 756 insertions(+) create mode 100644 src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java create mode 100644 src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java diff --git a/build.xml b/build.xml index 7357672f0..199b3b8f5 100644 --- a/build.xml +++ b/build.xml @@ -29,6 +29,7 @@ + @@ -54,6 +55,7 @@ deprecation="on" optimize="on" > + diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java b/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java new file mode 100644 index 000000000..93ae53519 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java @@ -0,0 +1,649 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.taskdefs.optional; + +import org.apache.tools.ant.*; +import org.apache.tools.ant.taskdefs.*; + +import netrexx.lang.Rexx; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +/** + * Task to compile NetRexx source files. This task can take the following + * arguments: + *
    + *
  • binary
  • + *
  • classpath
  • + *
  • comments
  • + *
  • compile
  • + *
  • console
  • + *
  • crossref
  • + *
  • decimal
  • + *
  • destdir
  • + *
  • diag
  • + *
  • explicit
  • + *
  • format
  • + *
  • keep
  • + *
  • logo
  • + *
  • replace
  • + *
  • savelog
  • + *
  • srcdir
  • + *
  • sourcedir
  • + *
  • strictargs
  • + *
  • strictassign
  • + *
  • strictcase
  • + *
  • strictimport
  • + *
  • symbols
  • + *
  • time
  • + *
  • trace
  • + *
  • utf8
  • + *
  • verbose
  • + *
+ * Of these arguments, the srcdir argument is required. + * + *

When this task executes, it will recursively scan the srcdir + * looking for NetRexx source files to compile. This task makes its + * compile decision based on timestamp. + *

Before files are compiled they and any other file in the + * srcdir will be copied to the destdir allowing support files to be + * located properly in the classpath. The reason for copying the source files + * before the compile is that NetRexxC has only two destinations for classfiles: + *

    + *
  1. The current directory, and,
  2. + *
  3. The directory the source is in (see sourcedir option) + *
+ * + * @author dIon Gillard dion@multitask.com.au + */ + +public class NetRexxC extends MatchingTask { + + // variables to hold arguments + private boolean binary; + private String classpath; + private boolean comments; + private boolean compact; + private boolean compile = true; + private boolean console; + private boolean crossref; + private boolean decimal = true; + private File destDir; + private boolean diag; + private boolean explicit; + private boolean format; + private boolean java; + private boolean keep; + private boolean logo = true; + private boolean replace; + private boolean savelog; + private File srcDir; + private boolean sourcedir = true; // ?? Should this be the default for ant? + private boolean strictargs; + private boolean strictassign; + private boolean strictcase; + private boolean strictimport; + private boolean strictprops; + private boolean strictsignal; + private boolean symbols; + private boolean time; + private String trace = "trace2"; + private boolean utf8; + private String verbose = "verbose3"; + + // other implementation variables + private Vector compileList = new Vector(); + private Hashtable filecopyList = new Hashtable(); + private String oldClasspath = System.getProperty("java.class.path"); + + + /** + * Set whether literals are treated as binary, rather than NetRexx types + */ + public void setBinary(String binary) { + this.binary = Project.toBoolean(binary); + } + + /** + * Set the classpath used for NetRexx compilation + */ + public void setClasspath(String classpath) { + this.classpath = classpath; + } + + /** + * Set whether comments are passed through to the generated java source. + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false + */ + public void setComments(String comments) { + this.comments = Project.toBoolean(comments); + } + + /** + * Set whether error messages come out in compact or verbose format. + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false + */ + public void setCompact(String compact) { + this.compact = Project.toBoolean(compact); + } + + /** + * Set whether the NetRexx compiler should compile the generated java code + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is true. + * Setting this flag to false, will automatically set the keep flag to true. + */ + public void setCompile(String compile) { + this.compile = Project.toBoolean(compile); + if (!this.compile && !this.keep) this.keep = true; + } + + /** + * Set whether or not messages should be displayed on the 'console' + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is true. + */ + public void setConsole(String console) { + this.console = Project.toBoolean(console); + } + + /** + * Whether variable cross references are generated + */ + public void setCrossref(String crossref) { + this.crossref = Project.toBoolean(crossref); + } + + /** + * Set whether decimal arithmetic should be used for the netrexx code. + * Binary arithmetic is used when this flag is turned off. + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is true. + */ + public void setDecimal(String decimal) { + this.decimal = Project.toBoolean(decimal); + } + + /** + * Set the destination directory into which the NetRexx source + * files should be copied and then compiled. + */ + public void setDestDir(String destDirName) { + destDir = project.resolveFile(destDirName); + } + + /** + * Whether diagnostic information about the compile is generated + */ + public void setDiag(String diag) { + this.diag = Project.toBoolean(diag); + } + + /** + * Sets whether variables must be declared explicitly before use. + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setExplicit(String explicit) { + this.explicit = Project.toBoolean(explicit); + } + + /** + * Whether the generated java code is formatted nicely or left to match NetRexx + * line numbers for call stack debugging + */ + public void setFormat(String format) { + this.format = Project.toBoolean(format); + } + + /** + * Whether the generated java code is produced + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setJava(String java) { + this.java = Project.toBoolean(java); + } + + + /** + * Sets whether the generated java source file should be kept after compilation. + * The generated files will have an extension of .java.keep, not .java + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setKeep(String keep) { + this.keep = Project.toBoolean(keep); + } + + /** + * Whether the compiler text logo is displayed when compiling + */ + public void setLogo(String logo) { + this.logo = Project.toBoolean(logo); + } + + /** + * Whether the generated .java file should be replaced when compiling + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setReplace(String replace) { + this.replace = Project.toBoolean(replace); + } + + /** + * Sets whether the compiler messages will be written to NetRexxC.log as + * well as to the console + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setSavelog(String savelog) { + this.savelog = Project.toBoolean(savelog); + } + + /** + * Tells the NetRexx compiler to store the class files in the same directory + * as the source files. The alternative is the working directory + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is true. + */ + public void setSourcedir(String sourcedir) { + this.sourcedir = Project.toBoolean(sourcedir); + } + + /** + * Set the source dir to find the source Java files. + */ + public void setSrcDir(String srcDirName) { + srcDir = project.resolveFile(srcDirName); + } + + /** + * Tells the NetRexx compiler that method calls always need parentheses, + * even if no arguments are needed, e.g. aStringVar.getBytes + * vs. aStringVar.getBytes() + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setStrictargs(String strictargs) { + this.strictargs = Project.toBoolean(strictargs); + } + + /** + * Tells the NetRexx compile that assignments must match exactly on type + */ + public void setStrictassign(String strictassign) { + this.strictassign = Project.toBoolean(strictassign); + } + + /** + * Specifies whether the NetRexx compiler should be case sensitive or not + */ + public void setStrictcase(String strictcase) { + this.strictcase = Project.toBoolean(strictcase); + } + + /** + * Sets whether classes need to be imported explicitly using an + * import statement. By default the NetRexx compiler will import + * certain packages automatically + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setStrictimport(String strictimport) { + this.strictimport = Project.toBoolean(strictimport); + } + + /** + * Sets whether local properties need to be qualified explicitly using this + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setStrictprops(String strictprops) { + this.strictprops = Project.toBoolean(strictprops); + } + + + /** + * Whether the compiler should force catching of exceptions by explicitly named types + */ + public void setStrictsignal(String strictsignal) { + this.strictsignal = Project.toBoolean(strictsignal); + } + + /** + * Sets whether debug symbols should be generated into the class file + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setSymbols(String symbols) { + this.symbols = Project.toBoolean(symbols); + } + + /** + * Asks the NetRexx compiler to print compilation times to the console + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setTime(String time) { + this.time = Project.toBoolean(time); + } + + /** + * Turns on or off tracing and directs the resultant trace output + * Valid values are: "trace", "trace1", "trace2" and "notrace". + * "trace" and "trace2" + */ + public void setTrace(String trace) { + if (trace.equalsIgnoreCase("trace") + || trace.equalsIgnoreCase("trace1") + || trace.equalsIgnoreCase("trace2") + || trace.equalsIgnoreCase("notrace")) { + this.trace = trace; + } else { + throw new BuildException("Unknown trace value specified: '" + trace + "'"); + } + } + + /** + * Tells the NetRexx compiler that the source is in UTF8 + * Valid true values are "on" or "true". Anything else sets the flag to false. + * The default value is false. + */ + public void setUtf8(String utf8) { + this.utf8 = Project.toBoolean(utf8); + } + + /** + * Whether lots of warnings and error messages should be generated + */ + public void setVerbose(String verbose) { + this.verbose = verbose; + } + + /** + * Executes the task, i.e. does the actual compiler call + */ + public void execute() throws BuildException { + + // first off, make sure that we've got a srcdir and destdir + if (srcDir == null || destDir == null ) { + throw new BuildException("srcDir and destDir attributes must be set!"); + } + + // scan source and dest dirs to build up both copy lists and + // compile lists + // scanDir(srcDir, destDir); + DirectoryScanner ds = getDirectoryScanner(srcDir); + + String[] files = ds.getIncludedFiles(); + + scanDir(srcDir, destDir, files); + + // copy the source and support files + copyFilesToDestination(); + + // compile the source files + if (compileList.size() > 0) { + project.log("Compiling " + compileList.size() + " source files to " + destDir); + doNetRexxCompile(); + } + } + + /** + * Scans the directory looking for source files to be compiled and + * support files to be copied. + */ + private void scanDir(File srcDir, File destDir, String[] files) { + for (int i = 0; i < files.length; i++) { + File srcFile = new File(srcDir, files[i]); + File destFile = new File(destDir, files[i]); + String filename = files[i]; + // if it's a non source file, copy it if a later date than the + // dest + // if it's a source file, see if the destination class file + // needs to be recreated via compilation + if (filename.toLowerCase().endsWith(".nrx")) { + File classFile = new File(destDir, filename.substring(0, filename.lastIndexOf('.')) + ".class"); + if (!compile || srcFile.lastModified() > classFile.lastModified()) { + filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath()); + compileList.addElement(destFile.getAbsolutePath()); + } + } else { + if (srcFile.lastModified() > destFile.lastModified()) { + filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath()); + } + } + } + } + + /** + * Copy eligible files from the srcDir to destDir + */ + private void copyFilesToDestination() { + if (filecopyList.size() > 0) { + project.log("Copying " + filecopyList.size() + " files to " + destDir.getAbsolutePath()); + Enumeration enum = filecopyList.keys(); + while (enum.hasMoreElements()) { + String fromFile = (String)enum.nextElement(); + String toFile = (String)filecopyList.get(fromFile); + try { + project.copyFile(fromFile, toFile); + } catch (IOException ioe) { + String msg = "Failed to copy " + fromFile + " to " + toFile + + " due to " + ioe.getMessage(); + throw new BuildException(msg, ioe); + } + } + } + } + + /** + * Peforms a copmile using the NetRexx 1.1.x compiler + */ + private void doNetRexxCompile() throws BuildException { + project.log("Using NetRexx compiler", project.MSG_VERBOSE); + String classpath = getCompileClasspath(); + StringBuffer compileOptions = new StringBuffer(); + StringBuffer fileList = new StringBuffer(); + + // create an array of strings for input to the compiler: one array + // comes from the compile options, the other from the compileList + String[] compileOptionsArray = getCompileOptionsAsArray(); + String[] fileListArray = new String[compileList.size()]; + Enumeration e = compileList.elements(); + int j = 0; + while (e.hasMoreElements()) { + fileListArray[j] = (String)e.nextElement(); + j++; + } + // create a single array of arguments for the compiler + String compileArgs[] = new String[compileOptionsArray.length + fileListArray.length]; + for (int i = 0; i < compileOptionsArray.length; i++) { + compileArgs[i] = compileOptionsArray[i]; + } + for (int i = 0; i < fileListArray.length; i++) { + compileArgs[i+compileOptionsArray.length] = fileListArray[i]; + } + + // print nice output about what we are doing for the log + compileOptions.append("Compilation args: "); + for (int i = 0; i < compileOptionsArray.length; i++) { + compileOptions.append(compileOptionsArray[i]); + compileOptions.append(" "); + } + project.log(compileOptions.toString(), project.MSG_VERBOSE); + + String eol = System.getProperty("line.separator"); + StringBuffer niceSourceList = new StringBuffer("Files to be compiled:" + eol); + + for (int i = 0; i < compileList.size(); i++) { + niceSourceList.append(" "); + niceSourceList.append(compileList.elementAt(i).toString()); + niceSourceList.append(eol); + } + + project.log(niceSourceList.toString(), project.MSG_VERBOSE); + + // need to set java.class.path property and restore it later + // since the NetRexx compiler has no option for the classpath + String currentClassPath = System.getProperty("java.class.path"); + Properties currentProperties = System.getProperties(); + currentProperties.put("java.class.path", classpath); + + try { + int rc = COM.ibm.netrexx.process.NetRexxC.main( + new Rexx(compileArgs), new PrintWriter(project.getOutput())); + + if (rc > 1) { // 1 is warnings from real NetRexxC + String msg = "Compile failed, messages should have been provided."; + throw new BuildException(msg); + } + } finally { + // need to reset java.class.path property + // since the NetRexx compiler has no option for the classpath + currentProperties = System.getProperties(); + currentProperties.put("java.class.path", currentClassPath); + } + } + + /** + * Builds the compilation classpath. + */ + private String getCompileClasspath() { + StringBuffer classpath = new StringBuffer(); + + // add dest dir to classpath so that previously compiled and + // untouched classes are on classpath + classpath.append(destDir.getAbsolutePath()); + + // add our classpath to the mix + if (this.classpath != null) { + addExistingToClasspath(classpath, this.classpath); + } + + // add the system classpath + // addExistingToClasspath(classpath,System.getProperty("java.class.path")); + return classpath.toString(); + } + + /** + * This + */ + private String[] getCompileOptionsAsArray() { + Vector options = new Vector(); + options.addElement(binary ? "-binary" : "-nobinary"); + options.addElement(comments ? "-comments" : "-nocomments"); + options.addElement(compile ? "-compile" : "-nocompile"); + options.addElement(compact ? "-compact" : "-nocompact"); + options.addElement(console ? "-console" : "-noconsole"); + options.addElement(crossref ? "-crossref" : "-nocrossref"); + options.addElement(decimal ? "-decimal" : "-nodecimal"); + options.addElement(diag ? "-diag" : "-nodiag"); + options.addElement(explicit ? "-explicit": "-noexplicit"); + options.addElement(format ? "-format" : "-noformat"); + options.addElement(keep ? "-keep" : "-nokeep"); + options.addElement(logo ? "-logo" : "-nologo"); + options.addElement(replace ? "-replace" : "-noreplace"); + options.addElement(savelog ? "-savelog" : "-nosavelog"); + options.addElement(sourcedir ? "-sourcedir" : "-nosourcedir"); + options.addElement(strictargs ? "-strictargs" : "-nostrictargs"); + options.addElement(strictassign ? "-strictassign" : "-nostrictassign"); + options.addElement(strictcase ? "-strictcase": "-nostrictcase"); + options.addElement(strictimport ? "-strictimport" : "-nostrictimport"); + options.addElement(strictprops ? "-strictprops" : "-nostrictprops"); + options.addElement(strictsignal ? "-strictsignal" : "-nostrictsignal"); + options.addElement(symbols ? "-symbols" : "-nosymbols"); + options.addElement(time ? "-time" : "-notime"); + options.addElement("-" + trace); + options.addElement(utf8 ? "-utf8" : "-noutf8"); + options.addElement("-" + verbose); + String[] results = new String[options.size()]; + options.copyInto(results); + return results; + } + /** + * Takes a classpath-like string, and adds each element of + * this string to a new classpath, if the components exist. + * Components that don't exist, aren't added. + * We do this, because jikes issues warnings for non-existant + * files/dirs in his classpath, and these warnings are pretty + * annoying. + * @param target - target classpath + * @param source - source classpath + * to get file objects. + */ + private void addExistingToClasspath(StringBuffer target,String source) { + StringTokenizer tok = new StringTokenizer(source, + System.getProperty("path.separator"), false); + while (tok.hasMoreTokens()) { + File f = project.resolveFile(tok.nextToken()); + + if (f.exists()) { + target.append(File.pathSeparator); + target.append(f.getAbsolutePath()); + } else { + project.log("Dropping from classpath: "+ + f.getAbsolutePath(),project.MSG_VERBOSE); + } + } + + } +} diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java b/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java new file mode 100644 index 000000000..5eea03003 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java @@ -0,0 +1,105 @@ +/* + * RenameExtensions.java + * + * Created on 16 March 2000, 23:14 + */ + +package org.apache.tools.ant.taskdefs.optional; + +import java.io.*; +import java.util.*; +import org.apache.tools.ant.*; +import org.apache.tools.ant.taskdefs.*; + +/** + * + * @author dion + * @version + */ +public class RenameExtensions extends MatchingTask { + + private String fromExtension = ""; + private String toExtension = ""; + private boolean replace = false; + private File srcDir; + + + /** Creates new RenameExtensions */ + public RenameExtensions() { + super(); + } + + /** store fromExtension **/ + public void setFromExtension(String from) { + fromExtension = from; + } + + /** store toExtension **/ + public void setToExtension(String to) { + toExtension = to; + } + + /** + * store replace attribute - this determines whether the target file + * should be overwritten if present + */ + public void setReplace(String replaceString) { + replace = Project.toBoolean(replaceString); + } + + /** + * Set the source dir to find the files to be renamed. + */ + public void setSrcDir(String srcDirName) { + srcDir = project.resolveFile(srcDirName); + } + + /** + * Executes the task, i.e. does the actual compiler call + */ + public void execute() throws BuildException { + + // first off, make sure that we've got a from and to extension + if (fromExtension == null || toExtension == null || srcDir == null) { + throw new BuildException("srcDir, destDir, fromExtension and toExtension attributes must be set!"); + } + + // scan source and dest dirs to build up rename list + DirectoryScanner ds = getDirectoryScanner(srcDir); + + String[] files = ds.getIncludedFiles(); + + Hashtable renameList = scanDir(srcDir, files); + + Enumeration e = renameList.keys(); + File fromFile = null; + File toFile = null; + while (e.hasMoreElements()) { + fromFile = (File)e.nextElement(); + toFile = (File)renameList.get(fromFile); + if (toFile.exists() && replace) toFile.delete(); + if (!fromFile.renameTo(toFile)) throw new BuildException("Rename from: '" + fromFile + "' to '" + toFile + "' failed."); + } + + } + private Hashtable scanDir(File srcDir, String[] files) { + Hashtable list = new Hashtable(); + for (int i = 0; i < files.length; i++) { + File srcFile = new File(srcDir, files[i]); + String filename = files[i]; + // if it's a file that ends in the fromExtension, copy to the rename list + if (filename.toLowerCase().endsWith(fromExtension)) { + File destFile = new File(srcDir, filename.substring(0, filename.lastIndexOf(fromExtension)) + toExtension); + if (replace || !destFile.exists()) { + list.put(srcFile, destFile); + } else { + project.log("Rejecting file: '" + srcFile + "' for rename as replace is false and file exists", Project.MSG_VERBOSE); + } + } else { + project.log("File '"+ filename + "' doesn't match fromExtension: '" + fromExtension + "'", Project.MSG_VERBOSE); + } + } + return list; + } + +}